Home | History | Annotate | Download | only in src
      1 // Copyright 2012 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 "use strict";
     29 
     30 // This file relies on the fact that the following declaration has been made
     31 // in runtime.js:
     32 // var $Array = global.Array;
     33 
     34 var $Set = global.Set;
     35 var $Map = global.Map;
     36 var $WeakMap = global.WeakMap;
     37 var $WeakSet = global.WeakSet;
     38 
     39 // Global sentinel to be used instead of undefined keys, which are not
     40 // supported internally but required for Harmony sets and maps.
     41 var undefined_sentinel = {};
     42 
     43 // -------------------------------------------------------------------
     44 // Harmony Set
     45 
     46 function SetConstructor() {
     47   if (%_IsConstructCall()) {
     48     %SetInitialize(this);
     49   } else {
     50     throw MakeTypeError('constructor_not_function', ['Set']);
     51   }
     52 }
     53 
     54 
     55 function SetAdd(key) {
     56   if (!IS_SET(this)) {
     57     throw MakeTypeError('incompatible_method_receiver',
     58                         ['Set.prototype.add', this]);
     59   }
     60   if (IS_UNDEFINED(key)) {
     61     key = undefined_sentinel;
     62   }
     63   return %SetAdd(this, key);
     64 }
     65 
     66 
     67 function SetHas(key) {
     68   if (!IS_SET(this)) {
     69     throw MakeTypeError('incompatible_method_receiver',
     70                         ['Set.prototype.has', this]);
     71   }
     72   if (IS_UNDEFINED(key)) {
     73     key = undefined_sentinel;
     74   }
     75   return %SetHas(this, key);
     76 }
     77 
     78 
     79 function SetDelete(key) {
     80   if (!IS_SET(this)) {
     81     throw MakeTypeError('incompatible_method_receiver',
     82                         ['Set.prototype.delete', this]);
     83   }
     84   if (IS_UNDEFINED(key)) {
     85     key = undefined_sentinel;
     86   }
     87   if (%SetHas(this, key)) {
     88     %SetDelete(this, key);
     89     return true;
     90   } else {
     91     return false;
     92   }
     93 }
     94 
     95 
     96 function SetGetSize() {
     97   if (!IS_SET(this)) {
     98     throw MakeTypeError('incompatible_method_receiver',
     99                         ['Set.prototype.size', this]);
    100   }
    101   return %SetGetSize(this);
    102 }
    103 
    104 
    105 function SetClear() {
    106   if (!IS_SET(this)) {
    107     throw MakeTypeError('incompatible_method_receiver',
    108                         ['Set.prototype.clear', this]);
    109   }
    110   // Replace the internal table with a new empty table.
    111   %SetInitialize(this);
    112 }
    113 
    114 
    115 // -------------------------------------------------------------------
    116 
    117 function SetUpSet() {
    118   %CheckIsBootstrapping();
    119 
    120   %SetCode($Set, SetConstructor);
    121   %FunctionSetPrototype($Set, new $Object());
    122   %SetProperty($Set.prototype, "constructor", $Set, DONT_ENUM);
    123 
    124   // Set up the non-enumerable functions on the Set prototype object.
    125   InstallGetter($Set.prototype, "size", SetGetSize);
    126   InstallFunctions($Set.prototype, DONT_ENUM, $Array(
    127     "add", SetAdd,
    128     "has", SetHas,
    129     "delete", SetDelete,
    130     "clear", SetClear
    131   ));
    132 }
    133 
    134 SetUpSet();
    135 
    136 
    137 // -------------------------------------------------------------------
    138 // Harmony Map
    139 
    140 function MapConstructor() {
    141   if (%_IsConstructCall()) {
    142     %MapInitialize(this);
    143   } else {
    144     throw MakeTypeError('constructor_not_function', ['Map']);
    145   }
    146 }
    147 
    148 
    149 function MapGet(key) {
    150   if (!IS_MAP(this)) {
    151     throw MakeTypeError('incompatible_method_receiver',
    152                         ['Map.prototype.get', this]);
    153   }
    154   if (IS_UNDEFINED(key)) {
    155     key = undefined_sentinel;
    156   }
    157   return %MapGet(this, key);
    158 }
    159 
    160 
    161 function MapSet(key, value) {
    162   if (!IS_MAP(this)) {
    163     throw MakeTypeError('incompatible_method_receiver',
    164                         ['Map.prototype.set', this]);
    165   }
    166   if (IS_UNDEFINED(key)) {
    167     key = undefined_sentinel;
    168   }
    169   return %MapSet(this, key, value);
    170 }
    171 
    172 
    173 function MapHas(key) {
    174   if (!IS_MAP(this)) {
    175     throw MakeTypeError('incompatible_method_receiver',
    176                         ['Map.prototype.has', this]);
    177   }
    178   if (IS_UNDEFINED(key)) {
    179     key = undefined_sentinel;
    180   }
    181   return %MapHas(this, key);
    182 }
    183 
    184 
    185 function MapDelete(key) {
    186   if (!IS_MAP(this)) {
    187     throw MakeTypeError('incompatible_method_receiver',
    188                         ['Map.prototype.delete', this]);
    189   }
    190   if (IS_UNDEFINED(key)) {
    191     key = undefined_sentinel;
    192   }
    193   return %MapDelete(this, key);
    194 }
    195 
    196 
    197 function MapGetSize() {
    198   if (!IS_MAP(this)) {
    199     throw MakeTypeError('incompatible_method_receiver',
    200                         ['Map.prototype.size', this]);
    201   }
    202   return %MapGetSize(this);
    203 }
    204 
    205 
    206 function MapClear() {
    207   if (!IS_MAP(this)) {
    208     throw MakeTypeError('incompatible_method_receiver',
    209                         ['Map.prototype.clear', this]);
    210   }
    211   // Replace the internal table with a new empty table.
    212   %MapInitialize(this);
    213 }
    214 
    215 
    216 // -------------------------------------------------------------------
    217 
    218 function SetUpMap() {
    219   %CheckIsBootstrapping();
    220 
    221   %SetCode($Map, MapConstructor);
    222   %FunctionSetPrototype($Map, new $Object());
    223   %SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
    224 
    225   // Set up the non-enumerable functions on the Map prototype object.
    226   InstallGetter($Map.prototype, "size", MapGetSize);
    227   InstallFunctions($Map.prototype, DONT_ENUM, $Array(
    228     "get", MapGet,
    229     "set", MapSet,
    230     "has", MapHas,
    231     "delete", MapDelete,
    232     "clear", MapClear
    233   ));
    234 }
    235 
    236 SetUpMap();
    237 
    238 
    239 // -------------------------------------------------------------------
    240 // Harmony WeakMap
    241 
    242 function WeakMapConstructor() {
    243   if (%_IsConstructCall()) {
    244     %WeakCollectionInitialize(this);
    245   } else {
    246     throw MakeTypeError('constructor_not_function', ['WeakMap']);
    247   }
    248 }
    249 
    250 
    251 function WeakMapGet(key) {
    252   if (!IS_WEAKMAP(this)) {
    253     throw MakeTypeError('incompatible_method_receiver',
    254                         ['WeakMap.prototype.get', this]);
    255   }
    256   if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
    257     throw %MakeTypeError('invalid_weakmap_key', [this, key]);
    258   }
    259   return %WeakCollectionGet(this, key);
    260 }
    261 
    262 
    263 function WeakMapSet(key, value) {
    264   if (!IS_WEAKMAP(this)) {
    265     throw MakeTypeError('incompatible_method_receiver',
    266                         ['WeakMap.prototype.set', this]);
    267   }
    268   if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
    269     throw %MakeTypeError('invalid_weakmap_key', [this, key]);
    270   }
    271   return %WeakCollectionSet(this, key, value);
    272 }
    273 
    274 
    275 function WeakMapHas(key) {
    276   if (!IS_WEAKMAP(this)) {
    277     throw MakeTypeError('incompatible_method_receiver',
    278                         ['WeakMap.prototype.has', this]);
    279   }
    280   if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
    281     throw %MakeTypeError('invalid_weakmap_key', [this, key]);
    282   }
    283   return %WeakCollectionHas(this, key);
    284 }
    285 
    286 
    287 function WeakMapDelete(key) {
    288   if (!IS_WEAKMAP(this)) {
    289     throw MakeTypeError('incompatible_method_receiver',
    290                         ['WeakMap.prototype.delete', this]);
    291   }
    292   if (!(IS_SPEC_OBJECT(key) || IS_SYMBOL(key))) {
    293     throw %MakeTypeError('invalid_weakmap_key', [this, key]);
    294   }
    295   return %WeakCollectionDelete(this, key);
    296 }
    297 
    298 
    299 function WeakMapClear() {
    300   if (!IS_WEAKMAP(this)) {
    301     throw MakeTypeError('incompatible_method_receiver',
    302                         ['WeakMap.prototype.clear', this]);
    303   }
    304   // Replace the internal table with a new empty table.
    305   %WeakCollectionInitialize(this);
    306 }
    307 
    308 
    309 // -------------------------------------------------------------------
    310 
    311 function SetUpWeakMap() {
    312   %CheckIsBootstrapping();
    313 
    314   %SetCode($WeakMap, WeakMapConstructor);
    315   %FunctionSetPrototype($WeakMap, new $Object());
    316   %SetProperty($WeakMap.prototype, "constructor", $WeakMap, DONT_ENUM);
    317 
    318   // Set up the non-enumerable functions on the WeakMap prototype object.
    319   InstallFunctions($WeakMap.prototype, DONT_ENUM, $Array(
    320     "get", WeakMapGet,
    321     "set", WeakMapSet,
    322     "has", WeakMapHas,
    323     "delete", WeakMapDelete,
    324     "clear", WeakMapClear
    325   ));
    326 }
    327 
    328 SetUpWeakMap();
    329 
    330 
    331 // -------------------------------------------------------------------
    332 // Harmony WeakSet
    333 
    334 function WeakSetConstructor() {
    335   if (%_IsConstructCall()) {
    336     %WeakCollectionInitialize(this);
    337   } else {
    338     throw MakeTypeError('constructor_not_function', ['WeakSet']);
    339   }
    340 }
    341 
    342 
    343 function WeakSetAdd(value) {
    344   if (!IS_WEAKSET(this)) {
    345     throw MakeTypeError('incompatible_method_receiver',
    346                         ['WeakSet.prototype.add', this]);
    347   }
    348   if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
    349     throw %MakeTypeError('invalid_weakset_value', [this, value]);
    350   }
    351   return %WeakCollectionSet(this, value, true);
    352 }
    353 
    354 
    355 function WeakSetHas(value) {
    356   if (!IS_WEAKSET(this)) {
    357     throw MakeTypeError('incompatible_method_receiver',
    358                         ['WeakSet.prototype.has', this]);
    359   }
    360   if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
    361     throw %MakeTypeError('invalid_weakset_value', [this, value]);
    362   }
    363   return %WeakCollectionHas(this, value);
    364 }
    365 
    366 
    367 function WeakSetDelete(value) {
    368   if (!IS_WEAKSET(this)) {
    369     throw MakeTypeError('incompatible_method_receiver',
    370                         ['WeakSet.prototype.delete', this]);
    371   }
    372   if (!(IS_SPEC_OBJECT(value) || IS_SYMBOL(value))) {
    373     throw %MakeTypeError('invalid_weakset_value', [this, value]);
    374   }
    375   return %WeakCollectionDelete(this, value);
    376 }
    377 
    378 
    379 function WeakSetClear() {
    380   if (!IS_WEAKSET(this)) {
    381     throw MakeTypeError('incompatible_method_receiver',
    382                         ['WeakSet.prototype.clear', this]);
    383   }
    384   // Replace the internal table with a new empty table.
    385   %WeakCollectionInitialize(this);
    386 }
    387 
    388 
    389 // -------------------------------------------------------------------
    390 
    391 function SetUpWeakSet() {
    392   %CheckIsBootstrapping();
    393 
    394   %SetCode($WeakSet, WeakSetConstructor);
    395   %FunctionSetPrototype($WeakSet, new $Object());
    396   %SetProperty($WeakSet.prototype, "constructor", $WeakSet, DONT_ENUM);
    397 
    398   // Set up the non-enumerable functions on the WeakSet prototype object.
    399   InstallFunctions($WeakSet.prototype, DONT_ENUM, $Array(
    400     "add", WeakSetAdd,
    401     "has", WeakSetHas,
    402     "delete", WeakSetDelete,
    403     "clear", WeakSetClear
    404   ));
    405 }
    406 
    407 SetUpWeakSet();
    408