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