Home | History | Annotate | Download | only in harmony
      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