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