1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 // Flags: --harmony-symbols --harmony-collections 29 // Flags: --expose-gc --allow-natives-syntax 30 31 var symbols = [] 32 33 34 // Returns true if the string is a valid 35 // serialization of Symbols added to the 'symbols' 36 // array. Adjust if you extend 'symbols' with other 37 // values. 38 function isValidSymbolString(s) { 39 return ["Symbol(66)"].indexOf(s) >= 0; 40 } 41 42 43 // Test different forms of constructor calls, all equivalent. 44 function TestNew() { 45 for (var i = 0; i < 2; ++i) { 46 for (var j = 0; j < 5; ++j) { 47 symbols.push(%CreatePrivateSymbol("66")) 48 symbols.push(Object(%CreatePrivateSymbol("66")).valueOf()) 49 } 50 gc() // Promote existing symbols and then allocate some more. 51 } 52 } 53 TestNew() 54 55 56 function TestType() { 57 for (var i in symbols) { 58 assertEquals("symbol", typeof symbols[i]) 59 assertTrue(typeof symbols[i] === "symbol") 60 assertTrue(%SymbolIsPrivate(symbols[i])) 61 assertEquals(null, %_ClassOf(symbols[i])) 62 assertEquals("Symbol", %_ClassOf(Object(symbols[i]))) 63 } 64 } 65 TestType() 66 67 68 function TestPrototype() { 69 for (var i in symbols) { 70 assertSame(Symbol.prototype, symbols[i].__proto__) 71 } 72 } 73 TestPrototype() 74 75 76 function TestConstructor() { 77 for (var i in symbols) { 78 assertSame(Symbol, symbols[i].__proto__.constructor) 79 assertSame(Symbol, Object(symbols[i]).__proto__.constructor) 80 } 81 } 82 TestConstructor() 83 84 85 function TestToString() { 86 for (var i in symbols) { 87 assertThrows(function() { String(symbols[i]) }, TypeError) 88 assertThrows(function() { symbols[i] + "" }, TypeError) 89 assertTrue(isValidSymbolString(symbols[i].toString())) 90 assertTrue(isValidSymbolString(Object(symbols[i]).toString())) 91 assertTrue(isValidSymbolString(Symbol.prototype.toString.call(symbols[i]))) 92 assertEquals( 93 "[object Symbol]", Object.prototype.toString.call(symbols[i])) 94 } 95 } 96 TestToString() 97 98 99 function TestToBoolean() { 100 for (var i in symbols) { 101 assertTrue(Boolean(symbols[i]).valueOf()) 102 assertFalse(!symbols[i]) 103 assertTrue(!!symbols[i]) 104 assertTrue(symbols[i] && true) 105 assertFalse(!symbols[i] && false) 106 assertTrue(!symbols[i] || true) 107 assertEquals(1, symbols[i] ? 1 : 2) 108 assertEquals(2, !symbols[i] ? 1 : 2) 109 if (!symbols[i]) assertUnreachable(); 110 if (symbols[i]) {} else assertUnreachable(); 111 } 112 } 113 TestToBoolean() 114 115 116 function TestToNumber() { 117 for (var i in symbols) { 118 assertSame(NaN, Number(symbols[i]).valueOf()) 119 assertSame(NaN, symbols[i] + 0) 120 } 121 } 122 TestToNumber() 123 124 125 function TestEquality() { 126 // Every symbol should equal itself, and non-strictly equal its wrapper. 127 for (var i in symbols) { 128 assertSame(symbols[i], symbols[i]) 129 assertEquals(symbols[i], symbols[i]) 130 assertTrue(Object.is(symbols[i], symbols[i])) 131 assertTrue(symbols[i] === symbols[i]) 132 assertTrue(symbols[i] == symbols[i]) 133 assertFalse(symbols[i] === Object(symbols[i])) 134 assertFalse(Object(symbols[i]) === symbols[i]) 135 assertFalse(symbols[i] == Object(symbols[i])) 136 assertFalse(Object(symbols[i]) == symbols[i]) 137 assertTrue(symbols[i] === symbols[i].valueOf()) 138 assertTrue(symbols[i].valueOf() === symbols[i]) 139 assertTrue(symbols[i] == symbols[i].valueOf()) 140 assertTrue(symbols[i].valueOf() == symbols[i]) 141 } 142 143 // All symbols should be distinct. 144 for (var i = 0; i < symbols.length; ++i) { 145 for (var j = i + 1; j < symbols.length; ++j) { 146 assertFalse(Object.is(symbols[i], symbols[j])) 147 assertFalse(symbols[i] === symbols[j]) 148 assertFalse(symbols[i] == symbols[j]) 149 } 150 } 151 152 // Symbols should not be equal to any other value (and the test terminates). 153 var values = [347, 1.275, NaN, "string", null, undefined, {}, function() {}] 154 for (var i in symbols) { 155 for (var j in values) { 156 assertFalse(symbols[i] === values[j]) 157 assertFalse(values[j] === symbols[i]) 158 assertFalse(symbols[i] == values[j]) 159 assertFalse(values[j] == symbols[i]) 160 } 161 } 162 } 163 TestEquality() 164 165 166 function TestGet() { 167 for (var i in symbols) { 168 assertTrue(isValidSymbolString(symbols[i].toString())) 169 assertEquals(symbols[i], symbols[i].valueOf()) 170 assertEquals(undefined, symbols[i].a) 171 assertEquals(undefined, symbols[i]["a" + "b"]) 172 assertEquals(undefined, symbols[i]["" + "1"]) 173 assertEquals(undefined, symbols[i][62]) 174 } 175 } 176 TestGet() 177 178 179 function TestSet() { 180 for (var i in symbols) { 181 symbols[i].toString = 0 182 assertTrue(isValidSymbolString(symbols[i].toString())) 183 symbols[i].valueOf = 0 184 assertEquals(symbols[i], symbols[i].valueOf()) 185 symbols[i].a = 0 186 assertEquals(undefined, symbols[i].a) 187 symbols[i]["a" + "b"] = 0 188 assertEquals(undefined, symbols[i]["a" + "b"]) 189 symbols[i][62] = 0 190 assertEquals(undefined, symbols[i][62]) 191 } 192 } 193 TestSet() 194 195 196 function TestCollections() { 197 var set = new Set 198 var map = new Map 199 var weakmap = new WeakMap 200 for (var i in symbols) { 201 set.add(symbols[i]) 202 map.set(symbols[i], i) 203 weakmap.set(symbols[i], i) 204 } 205 assertEquals(symbols.length, set.size) 206 assertEquals(symbols.length, map.size) 207 for (var i in symbols) { 208 assertTrue(set.has(symbols[i])) 209 assertTrue(map.has(symbols[i])) 210 assertTrue(weakmap.has(symbols[i])) 211 assertEquals(i, map.get(symbols[i])) 212 assertEquals(i, weakmap.get(symbols[i])) 213 } 214 for (var i in symbols) { 215 assertTrue(set.delete(symbols[i])) 216 assertTrue(map.delete(symbols[i])) 217 assertTrue(weakmap.delete(symbols[i])) 218 } 219 assertEquals(0, set.size) 220 assertEquals(0, map.size) 221 } 222 TestCollections() 223 224 225 226 function TestKeySet(obj) { 227 assertTrue(%HasFastProperties(obj)) 228 // Set the even symbols via assignment. 229 for (var i = 0; i < symbols.length; i += 2) { 230 obj[symbols[i]] = i 231 // Object should remain in fast mode until too many properties were added. 232 assertTrue(%HasFastProperties(obj) || i >= 30) 233 } 234 } 235 236 237 function TestKeyDefine(obj) { 238 // Set the odd symbols via defineProperty (as non-enumerable). 239 for (var i = 1; i < symbols.length; i += 2) { 240 Object.defineProperty(obj, symbols[i], {value: i, configurable: true}) 241 } 242 } 243 244 245 function TestKeyGet(obj) { 246 var obj2 = Object.create(obj) 247 for (var i in symbols) { 248 assertEquals(i|0, obj[symbols[i]]) 249 assertEquals(i|0, obj2[symbols[i]]) 250 } 251 } 252 253 254 function TestKeyHas() { 255 for (var i in symbols) { 256 assertTrue(symbols[i] in obj) 257 assertTrue(Object.hasOwnProperty.call(obj, symbols[i])) 258 } 259 } 260 261 262 function TestKeyEnum(obj) { 263 for (var name in obj) { 264 assertEquals("string", typeof name) 265 } 266 } 267 268 269 function TestKeyNames(obj) { 270 assertEquals(0, Object.keys(obj).length) 271 272 var names = Object.getOwnPropertyNames(obj) 273 for (var i in names) { 274 assertEquals("string", typeof names[i]) 275 } 276 } 277 278 279 function TestKeyDescriptor(obj) { 280 for (var i in symbols) { 281 var desc = Object.getOwnPropertyDescriptor(obj, symbols[i]); 282 assertEquals(i|0, desc.value) 283 assertTrue(desc.configurable) 284 assertEquals(i % 2 == 0, desc.writable) 285 assertEquals(i % 2 == 0, desc.enumerable) 286 assertEquals(i % 2 == 0, 287 Object.prototype.propertyIsEnumerable.call(obj, symbols[i])) 288 } 289 } 290 291 292 function TestKeyDelete(obj) { 293 for (var i in symbols) { 294 delete obj[symbols[i]] 295 } 296 for (var i in symbols) { 297 assertEquals(undefined, Object.getOwnPropertyDescriptor(obj, symbols[i])) 298 } 299 } 300 301 302 var objs = [{}, [], Object.create(null), Object(1), new Map, function(){}] 303 304 for (var i in objs) { 305 var obj = objs[i] 306 TestKeySet(obj) 307 TestKeyDefine(obj) 308 TestKeyGet(obj) 309 TestKeyHas(obj) 310 TestKeyEnum(obj) 311 TestKeyNames(obj) 312 TestKeyDescriptor(obj) 313 TestKeyDelete(obj) 314 } 315 316 317 function TestCachedKeyAfterScavenge() { 318 gc(); 319 // Keyed property lookup are cached. Hereby we assume that the keys are 320 // tenured, so that we only have to clear the cache between mark compacts, 321 // but not between scavenges. This must also apply for symbol keys. 322 var key = Symbol("key"); 323 var a = {}; 324 a[key] = "abc"; 325 326 for (var i = 0; i < 100000; i++) { 327 a[key] += "a"; // Allocations cause a scavenge. 328 } 329 } 330 TestCachedKeyAfterScavenge(); 331 332 333 function TestGetOwnPropertySymbols() { 334 var privateSymbol = %CreatePrivateSymbol("private") 335 var publicSymbol = Symbol() 336 var publicSymbol2 = Symbol() 337 var obj = {} 338 obj[publicSymbol] = 1 339 obj[privateSymbol] = 2 340 obj[publicSymbol2] = 3 341 var syms = Object.getOwnPropertySymbols(obj) 342 assertEquals(syms, [publicSymbol, publicSymbol2]) 343 } 344 TestGetOwnPropertySymbols() 345