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 34var $Set = global.Set; 35var $Map = global.Map; 36var $WeakMap = global.WeakMap; 37var $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. 41var undefined_sentinel = {}; 42 43// ------------------------------------------------------------------- 44// Harmony Set 45 46function SetConstructor() { 47 if (%_IsConstructCall()) { 48 %SetInitialize(this); 49 } else { 50 throw MakeTypeError('constructor_not_function', ['Set']); 51 } 52} 53 54 55function 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 67function 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 79function 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 96function 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 105function 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 117function 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 134SetUpSet(); 135 136 137// ------------------------------------------------------------------- 138// Harmony Map 139 140function MapConstructor() { 141 if (%_IsConstructCall()) { 142 %MapInitialize(this); 143 } else { 144 throw MakeTypeError('constructor_not_function', ['Map']); 145 } 146} 147 148 149function 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 161function 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 173function 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 185function 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 197function 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 206function 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 218function 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 236SetUpMap(); 237 238 239// ------------------------------------------------------------------- 240// Harmony WeakMap 241 242function WeakMapConstructor() { 243 if (%_IsConstructCall()) { 244 %WeakCollectionInitialize(this); 245 } else { 246 throw MakeTypeError('constructor_not_function', ['WeakMap']); 247 } 248} 249 250 251function 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 263function 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 275function 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 287function 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 299function 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 311function 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 328SetUpWeakMap(); 329 330 331// ------------------------------------------------------------------- 332// Harmony WeakSet 333 334function WeakSetConstructor() { 335 if (%_IsConstructCall()) { 336 %WeakCollectionInitialize(this); 337 } else { 338 throw MakeTypeError('constructor_not_function', ['WeakSet']); 339 } 340} 341 342 343function 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 355function 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 367function 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 379function 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 391function 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 407SetUpWeakSet(); 408