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: --expose-gc --allow-natives-syntax 29 30var symbols = [] 31 32 33// Returns true if the string is a valid 34// serialization of Symbols added to the 'symbols' 35// array. Adjust if you extend 'symbols' with other 36// values. 37function isValidSymbolString(s) { 38 return ["Symbol(66)"].indexOf(s) >= 0; 39} 40 41 42// Test different forms of constructor calls, all equivalent. 43function TestNew() { 44 for (var i = 0; i < 2; ++i) { 45 for (var j = 0; j < 5; ++j) { 46 symbols.push(%CreatePrivateSymbol("66")) 47 symbols.push(Object(%CreatePrivateSymbol("66")).valueOf()) 48 } 49 gc() // Promote existing symbols and then allocate some more. 50 } 51} 52TestNew() 53 54 55function TestType() { 56 for (var i in symbols) { 57 assertEquals("symbol", typeof symbols[i]) 58 assertTrue(typeof symbols[i] === "symbol") 59 assertTrue(%SymbolIsPrivate(symbols[i])) 60 assertEquals(null, %_ClassOf(symbols[i])) 61 assertEquals("Symbol", %_ClassOf(Object(symbols[i]))) 62 } 63} 64TestType() 65 66 67function TestPrototype() { 68 for (var i in symbols) { 69 assertSame(Symbol.prototype, symbols[i].__proto__) 70 } 71} 72TestPrototype() 73 74 75function TestConstructor() { 76 for (var i in symbols) { 77 assertSame(Symbol, symbols[i].__proto__.constructor) 78 assertSame(Symbol, Object(symbols[i]).__proto__.constructor) 79 } 80} 81TestConstructor() 82 83 84function TestToString() { 85 for (var i in symbols) { 86 assertThrows(function() {new String(symbols[i]) }, TypeError) 87 assertEquals(symbols[i].toString(), String(symbols[i])) 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} 96TestToString() 97 98 99function 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} 113TestToBoolean() 114 115 116function TestToNumber() { 117 for (var i in symbols) { 118 assertThrows(function() { Number(symbols[i]); }, TypeError); 119 assertThrows(function() { symbols[i] + 0; }, TypeError); 120 } 121} 122TestToNumber() 123 124 125function 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} 163TestEquality() 164 165 166function 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} 176TestGet() 177 178 179function 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} 193TestSet() 194 195 196function 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} 222TestCollections() 223 224 225 226function 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 237function 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 245function 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 254function 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 262function TestKeyEnum(obj) { 263 for (var name in obj) { 264 assertEquals("string", typeof name) 265 } 266} 267 268 269function 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 279function 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 292function 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 302var objs = [{}, [], Object.create(null), Object(1), new Map, function(){}] 303 304for (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 317function 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} 330TestCachedKeyAfterScavenge(); 331 332 333function 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} 344TestGetOwnPropertySymbols() 345 346 347function TestSealAndFreeze(freeze) { 348 var sym = %CreatePrivateSymbol("private") 349 var obj = {} 350 obj[sym] = 1 351 freeze(obj) 352 obj[sym] = 2 353 assertEquals(2, obj[sym]) 354 assertTrue(delete obj[sym]) 355 assertEquals(undefined, obj[sym]) 356} 357TestSealAndFreeze(Object.seal) 358TestSealAndFreeze(Object.freeze) 359TestSealAndFreeze(Object.preventExtensions) 360