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