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