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 // Test different forms of constructor calls, all equivalent. 34 function TestNew() { 35 for (var i = 0; i < 2; ++i) { 36 for (var j = 0; j < 5; ++j) { 37 symbols.push(%CreatePrivateSymbol("66")) 38 symbols.push(Object(%CreatePrivateSymbol("66")).valueOf()) 39 } 40 gc() // Promote existing symbols and then allocate some more. 41 } 42 } 43 TestNew() 44 45 46 function TestType() { 47 for (var i in symbols) { 48 assertEquals("symbol", typeof symbols[i]) 49 assertTrue(typeof symbols[i] === "symbol") 50 assertTrue(%SymbolIsPrivate(symbols[i])) 51 assertEquals(null, %_ClassOf(symbols[i])) 52 assertEquals("Symbol", %_ClassOf(new Symbol(symbols[i]))) 53 assertEquals("Symbol", %_ClassOf(Object(symbols[i]))) 54 } 55 } 56 TestType() 57 58 59 function TestPrototype() { 60 for (var i in symbols) { 61 assertSame(Symbol.prototype, symbols[i].__proto__) 62 } 63 } 64 TestPrototype() 65 66 67 function TestConstructor() { 68 for (var i in symbols) { 69 assertSame(Symbol, symbols[i].__proto__.constructor) 70 } 71 } 72 TestConstructor() 73 74 75 function TestName() { 76 for (var i in symbols) { 77 var name = symbols[i].name 78 assertTrue(name === "66") 79 } 80 } 81 TestName() 82 83 84 function TestToString() { 85 for (var i in symbols) { 86 assertThrows(function() { String(symbols[i]) }, TypeError) 87 assertThrows(function() { symbols[i] + "" }, TypeError) 88 assertThrows(function() { symbols[i].toString() }, TypeError) 89 assertThrows(function() { (new Symbol(symbols[i])).toString() }, TypeError) 90 assertThrows(function() { Object(symbols[i]).toString() }, TypeError) 91 assertEquals("[object Symbol]", Object.prototype.toString.call(symbols[i])) 92 } 93 } 94 TestToString() 95 96 97 function TestToBoolean() { 98 for (var i in symbols) { 99 assertTrue(Boolean(symbols[i]).valueOf()) 100 assertFalse(!symbols[i]) 101 assertTrue(!!symbols[i]) 102 assertTrue(symbols[i] && true) 103 assertFalse(!symbols[i] && false) 104 assertTrue(!symbols[i] || true) 105 assertEquals(1, symbols[i] ? 1 : 2) 106 assertEquals(2, !symbols[i] ? 1 : 2) 107 if (!symbols[i]) assertUnreachable(); 108 if (symbols[i]) {} else assertUnreachable(); 109 } 110 } 111 TestToBoolean() 112 113 114 function TestToNumber() { 115 for (var i in symbols) { 116 assertSame(NaN, Number(symbols[i]).valueOf()) 117 assertSame(NaN, symbols[i] + 0) 118 } 119 } 120 TestToNumber() 121 122 123 function TestEquality() { 124 // Every symbol should equal itself, and non-strictly equal its wrapper. 125 for (var i in symbols) { 126 assertSame(symbols[i], symbols[i]) 127 assertEquals(symbols[i], symbols[i]) 128 assertTrue(Object.is(symbols[i], symbols[i])) 129 assertTrue(symbols[i] === symbols[i]) 130 assertTrue(symbols[i] == symbols[i]) 131 assertFalse(symbols[i] === new Symbol(symbols[i])) 132 assertFalse(new Symbol(symbols[i]) === symbols[i]) 133 assertTrue(symbols[i] == new Symbol(symbols[i])) 134 assertTrue(new Symbol(symbols[i]) == symbols[i]) 135 } 136 137 // All symbols should be distinct. 138 for (var i = 0; i < symbols.length; ++i) { 139 for (var j = i + 1; j < symbols.length; ++j) { 140 assertFalse(Object.is(symbols[i], symbols[j])) 141 assertFalse(symbols[i] === symbols[j]) 142 assertFalse(symbols[i] == symbols[j]) 143 } 144 } 145 146 // Symbols should not be equal to any other value (and the test terminates). 147 var values = [347, 1.275, NaN, "string", null, undefined, {}, function() {}] 148 for (var i in symbols) { 149 for (var j in values) { 150 assertFalse(symbols[i] === values[j]) 151 assertFalse(values[j] === symbols[i]) 152 assertFalse(symbols[i] == values[j]) 153 assertFalse(values[j] == symbols[i]) 154 } 155 } 156 } 157 TestEquality() 158 159 160 function TestGet() { 161 for (var i in symbols) { 162 assertThrows(function() { symbols[i].toString() }, TypeError) 163 assertEquals(symbols[i], symbols[i].valueOf()) 164 assertEquals(undefined, symbols[i].a) 165 assertEquals(undefined, symbols[i]["a" + "b"]) 166 assertEquals(undefined, symbols[i]["" + "1"]) 167 assertEquals(undefined, symbols[i][62]) 168 } 169 } 170 TestGet() 171 172 173 function TestSet() { 174 for (var i in symbols) { 175 symbols[i].toString = 0 176 assertThrows(function() { symbols[i].toString() }, TypeError) 177 symbols[i].valueOf = 0 178 assertEquals(symbols[i], symbols[i].valueOf()) 179 symbols[i].a = 0 180 assertEquals(undefined, symbols[i].a) 181 symbols[i]["a" + "b"] = 0 182 assertEquals(undefined, symbols[i]["a" + "b"]) 183 symbols[i][62] = 0 184 assertEquals(undefined, symbols[i][62]) 185 } 186 } 187 TestSet() 188 189 190 function TestCollections() { 191 var set = new Set 192 var map = new Map 193 var weakmap = new WeakMap 194 for (var i in symbols) { 195 set.add(symbols[i]) 196 map.set(symbols[i], i) 197 weakmap.set(symbols[i], i) 198 } 199 assertEquals(symbols.length, set.size) 200 assertEquals(symbols.length, map.size) 201 for (var i in symbols) { 202 assertTrue(set.has(symbols[i])) 203 assertTrue(map.has(symbols[i])) 204 assertTrue(weakmap.has(symbols[i])) 205 assertEquals(i, map.get(symbols[i])) 206 assertEquals(i, weakmap.get(symbols[i])) 207 } 208 for (var i in symbols) { 209 assertTrue(set.delete(symbols[i])) 210 assertTrue(map.delete(symbols[i])) 211 assertTrue(weakmap.delete(symbols[i])) 212 } 213 assertEquals(0, set.size) 214 assertEquals(0, map.size) 215 } 216 TestCollections() 217 218 219 220 function TestKeySet(obj) { 221 assertTrue(%HasFastProperties(obj)) 222 // Set the even symbols via assignment. 223 for (var i = 0; i < symbols.length; i += 2) { 224 obj[symbols[i]] = i 225 // Object should remain in fast mode until too many properties were added. 226 assertTrue(%HasFastProperties(obj) || i >= 30) 227 } 228 } 229 230 231 function TestKeyDefine(obj) { 232 // Set the odd symbols via defineProperty (as non-enumerable). 233 for (var i = 1; i < symbols.length; i += 2) { 234 Object.defineProperty(obj, symbols[i], {value: i, configurable: true}) 235 } 236 } 237 238 239 function TestKeyGet(obj) { 240 var obj2 = Object.create(obj) 241 for (var i in symbols) { 242 assertEquals(i|0, obj[symbols[i]]) 243 assertEquals(i|0, obj2[symbols[i]]) 244 } 245 } 246 247 248 function TestKeyHas() { 249 for (var i in symbols) { 250 assertTrue(symbols[i] in obj) 251 assertTrue(Object.hasOwnProperty.call(obj, symbols[i])) 252 } 253 } 254 255 256 function TestKeyEnum(obj) { 257 for (var name in obj) { 258 assertEquals("string", typeof name) 259 } 260 } 261 262 263 function TestKeyNames(obj) { 264 assertEquals(0, Object.keys(obj).length) 265 266 var names = Object.getOwnPropertyNames(obj) 267 for (var i in names) { 268 assertEquals("string", typeof names[i]) 269 } 270 } 271 272 273 function TestKeyDescriptor(obj) { 274 for (var i in symbols) { 275 var desc = Object.getOwnPropertyDescriptor(obj, symbols[i]); 276 assertEquals(i|0, desc.value) 277 assertTrue(desc.configurable) 278 assertEquals(i % 2 == 0, desc.writable) 279 assertEquals(i % 2 == 0, desc.enumerable) 280 assertEquals(i % 2 == 0, 281 Object.prototype.propertyIsEnumerable.call(obj, symbols[i])) 282 } 283 } 284 285 286 function TestKeyDelete(obj) { 287 for (var i in symbols) { 288 delete obj[symbols[i]] 289 } 290 for (var i in symbols) { 291 assertEquals(undefined, Object.getOwnPropertyDescriptor(obj, symbols[i])) 292 } 293 } 294 295 296 var objs = [{}, [], Object.create(null), Object(1), new Map, function(){}] 297 298 for (var i in objs) { 299 var obj = objs[i] 300 TestKeySet(obj) 301 TestKeyDefine(obj) 302 TestKeyGet(obj) 303 TestKeyHas(obj) 304 TestKeyEnum(obj) 305 TestKeyNames(obj) 306 TestKeyDescriptor(obj) 307 TestKeyDelete(obj) 308 } 309 310 311 function TestCachedKeyAfterScavenge() { 312 gc(); 313 // Keyed property lookup are cached. Hereby we assume that the keys are 314 // tenured, so that we only have to clear the cache between mark compacts, 315 // but not between scavenges. This must also apply for symbol keys. 316 var key = Symbol("key"); 317 var a = {}; 318 a[key] = "abc"; 319 320 for (var i = 0; i < 100000; i++) { 321 a[key] += "a"; // Allocations cause a scavenge. 322 } 323 } 324 TestCachedKeyAfterScavenge(); 325