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 // This file relies on the fact that the following declarations have been made
     29 // in runtime.js:
     30 // var $Object = global.Object;
     31 // var $Boolean = global.Boolean;
     32 // var $Number = global.Number;
     33 // var $Function = global.Function;
     34 // var $Array = global.Array;
     35 // var $NaN = 0/0;
     36 //
     37 // in math.js:
     38 // var $floor = MathFloor
     39 
     40 var $isNaN = GlobalIsNaN;
     41 var $isFinite = GlobalIsFinite;
     42 
     43 // ----------------------------------------------------------------------------
     44 
     45 // Helper function used to install functions on objects.
     46 function InstallFunctions(object, attributes, functions) {
     47   if (functions.length >= 8) {
     48     %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
     49   }
     50   for (var i = 0; i < functions.length; i += 2) {
     51     var key = functions[i];
     52     var f = functions[i + 1];
     53     %FunctionSetName(f, key);
     54     %FunctionRemovePrototype(f);
     55     %SetProperty(object, key, f, attributes);
     56     %SetNativeFlag(f);
     57   }
     58   %ToFastProperties(object);
     59 }
     60 
     61 
     62 // Helper function to install a getter-only accessor property.
     63 function InstallGetter(object, name, getter) {
     64   %FunctionSetName(getter, name);
     65   %FunctionRemovePrototype(getter);
     66   %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
     67   %SetNativeFlag(getter);
     68 }
     69 
     70 
     71 // Helper function to install a getter/setter accessor property.
     72 function InstallGetterSetter(object, name, getter, setter) {
     73   %FunctionSetName(getter, name);
     74   %FunctionSetName(setter, name);
     75   %FunctionRemovePrototype(getter);
     76   %FunctionRemovePrototype(setter);
     77   %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
     78   %SetNativeFlag(getter);
     79   %SetNativeFlag(setter);
     80 }
     81 
     82 
     83 // Prevents changes to the prototype of a built-in function.
     84 // The "prototype" property of the function object is made non-configurable,
     85 // and the prototype object is made non-extensible. The latter prevents
     86 // changing the __proto__ property.
     87 function SetUpLockedPrototype(constructor, fields, methods) {
     88   %CheckIsBootstrapping();
     89   var prototype = constructor.prototype;
     90   // Install functions first, because this function is used to initialize
     91   // PropertyDescriptor itself.
     92   var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
     93   if (property_count >= 4) {
     94     %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
     95   }
     96   if (fields) {
     97     for (var i = 0; i < fields.length; i++) {
     98       %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
     99     }
    100   }
    101   for (var i = 0; i < methods.length; i += 2) {
    102     var key = methods[i];
    103     var f = methods[i + 1];
    104     %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
    105     %SetNativeFlag(f);
    106   }
    107   %SetPrototype(prototype, null);
    108   %ToFastProperties(prototype);
    109 }
    110 
    111 
    112 // ----------------------------------------------------------------------------
    113 
    114 
    115 // ECMA 262 - 15.1.4
    116 function GlobalIsNaN(number) {
    117   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
    118   return NUMBER_IS_NAN(number);
    119 }
    120 
    121 
    122 // ECMA 262 - 15.1.5
    123 function GlobalIsFinite(number) {
    124   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
    125   return NUMBER_IS_FINITE(number);
    126 }
    127 
    128 
    129 // ECMA-262 - 15.1.2.2
    130 function GlobalParseInt(string, radix) {
    131   if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
    132     // Some people use parseInt instead of Math.floor.  This
    133     // optimization makes parseInt on a Smi 12 times faster (60ns
    134     // vs 800ns).  The following optimization makes parseInt on a
    135     // non-Smi number 9 times faster (230ns vs 2070ns).  Together
    136     // they make parseInt on a string 1.4% slower (274ns vs 270ns).
    137     if (%_IsSmi(string)) return string;
    138     if (IS_NUMBER(string) &&
    139         ((0.01 < string && string < 1e9) ||
    140             (-1e9 < string && string < -0.01))) {
    141       // Truncate number.
    142       return string | 0;
    143     }
    144     string = TO_STRING_INLINE(string);
    145     radix = radix | 0;
    146   } else {
    147     // The spec says ToString should be evaluated before ToInt32.
    148     string = TO_STRING_INLINE(string);
    149     radix = TO_INT32(radix);
    150     if (!(radix == 0 || (2 <= radix && radix <= 36))) {
    151       return $NaN;
    152     }
    153   }
    154 
    155   if (%_HasCachedArrayIndex(string) &&
    156       (radix == 0 || radix == 10)) {
    157     return %_GetCachedArrayIndex(string);
    158   }
    159   return %StringParseInt(string, radix);
    160 }
    161 
    162 
    163 // ECMA-262 - 15.1.2.3
    164 function GlobalParseFloat(string) {
    165   string = TO_STRING_INLINE(string);
    166   if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
    167   return %StringParseFloat(string);
    168 }
    169 
    170 
    171 function GlobalEval(x) {
    172   if (!IS_STRING(x)) return x;
    173 
    174   var global_receiver = %GlobalReceiver(global);
    175   var global_is_detached = (global === global_receiver);
    176 
    177   // For consistency with JSC we require the global object passed to
    178   // eval to be the global object from which 'eval' originated. This
    179   // is not mandated by the spec.
    180   // We only throw if the global has been detached, since we need the
    181   // receiver as this-value for the call.
    182   if (global_is_detached) {
    183     throw new $EvalError('The "this" value passed to eval must ' +
    184                          'be the global object from which eval originated');
    185   }
    186 
    187   var f = %CompileString(x, false);
    188   if (!IS_FUNCTION(f)) return f;
    189 
    190   return %_CallFunction(global_receiver, f);
    191 }
    192 
    193 
    194 // ----------------------------------------------------------------------------
    195 
    196 // Set up global object.
    197 function SetUpGlobal() {
    198   %CheckIsBootstrapping();
    199 
    200   // ECMA 262 - 15.1.1.1.
    201   %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
    202 
    203   // ECMA-262 - 15.1.1.2.
    204   %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
    205 
    206   // ECMA-262 - 15.1.1.3.
    207   %SetProperty(global, "undefined", void 0,
    208                DONT_ENUM | DONT_DELETE | READ_ONLY);
    209 
    210   // Set up non-enumerable function on the global object.
    211   InstallFunctions(global, DONT_ENUM, $Array(
    212     "isNaN", GlobalIsNaN,
    213     "isFinite", GlobalIsFinite,
    214     "parseInt", GlobalParseInt,
    215     "parseFloat", GlobalParseFloat,
    216     "eval", GlobalEval
    217   ));
    218 }
    219 
    220 SetUpGlobal();
    221 
    222 
    223 // ----------------------------------------------------------------------------
    224 // Object
    225 
    226 // ECMA-262 - 15.2.4.2
    227 function ObjectToString() {
    228   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
    229   if (IS_NULL(this)) return "[object Null]";
    230   return "[object " + %_ClassOf(ToObject(this)) + "]";
    231 }
    232 
    233 
    234 // ECMA-262 - 15.2.4.3
    235 function ObjectToLocaleString() {
    236   if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    237     throw MakeTypeError("called_on_null_or_undefined",
    238                         ["Object.prototype.toLocaleString"]);
    239   }
    240   return this.toString();
    241 }
    242 
    243 
    244 // ECMA-262 - 15.2.4.4
    245 function ObjectValueOf() {
    246   return ToObject(this);
    247 }
    248 
    249 
    250 // ECMA-262 - 15.2.4.5
    251 function ObjectHasOwnProperty(V) {
    252   if (%IsJSProxy(this)) {
    253     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    254     if (IS_SYMBOL(V)) return false;
    255 
    256     var handler = %GetHandler(this);
    257     return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
    258   }
    259   return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
    260 }
    261 
    262 
    263 // ECMA-262 - 15.2.4.6
    264 function ObjectIsPrototypeOf(V) {
    265   if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    266     throw MakeTypeError("called_on_null_or_undefined",
    267                         ["Object.prototype.isPrototypeOf"]);
    268   }
    269   if (!IS_SPEC_OBJECT(V)) return false;
    270   return %IsInPrototypeChain(this, V);
    271 }
    272 
    273 
    274 // ECMA-262 - 15.2.4.6
    275 function ObjectPropertyIsEnumerable(V) {
    276   var P = ToName(V);
    277   if (%IsJSProxy(this)) {
    278     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    279     if (IS_SYMBOL(V)) return false;
    280 
    281     var desc = GetOwnProperty(this, P);
    282     return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
    283   }
    284   return %IsPropertyEnumerable(ToObject(this), P);
    285 }
    286 
    287 
    288 // Extensions for providing property getters and setters.
    289 function ObjectDefineGetter(name, fun) {
    290   var receiver = this;
    291   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    292     receiver = %GlobalReceiver(global);
    293   }
    294   if (!IS_SPEC_FUNCTION(fun)) {
    295     throw new $TypeError(
    296         'Object.prototype.__defineGetter__: Expecting function');
    297   }
    298   var desc = new PropertyDescriptor();
    299   desc.setGet(fun);
    300   desc.setEnumerable(true);
    301   desc.setConfigurable(true);
    302   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
    303 }
    304 
    305 
    306 function ObjectLookupGetter(name) {
    307   var receiver = this;
    308   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    309     receiver = %GlobalReceiver(global);
    310   }
    311   return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
    312 }
    313 
    314 
    315 function ObjectDefineSetter(name, fun) {
    316   var receiver = this;
    317   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    318     receiver = %GlobalReceiver(global);
    319   }
    320   if (!IS_SPEC_FUNCTION(fun)) {
    321     throw new $TypeError(
    322         'Object.prototype.__defineSetter__: Expecting function');
    323   }
    324   var desc = new PropertyDescriptor();
    325   desc.setSet(fun);
    326   desc.setEnumerable(true);
    327   desc.setConfigurable(true);
    328   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
    329 }
    330 
    331 
    332 function ObjectLookupSetter(name) {
    333   var receiver = this;
    334   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    335     receiver = %GlobalReceiver(global);
    336   }
    337   return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
    338 }
    339 
    340 
    341 function ObjectKeys(obj) {
    342   if (!IS_SPEC_OBJECT(obj)) {
    343     throw MakeTypeError("called_on_non_object", ["Object.keys"]);
    344   }
    345   if (%IsJSProxy(obj)) {
    346     var handler = %GetHandler(obj);
    347     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
    348     return ToNameArray(names, "keys", false);
    349   }
    350   return %LocalKeys(obj);
    351 }
    352 
    353 
    354 // ES5 8.10.1.
    355 function IsAccessorDescriptor(desc) {
    356   if (IS_UNDEFINED(desc)) return false;
    357   return desc.hasGetter() || desc.hasSetter();
    358 }
    359 
    360 
    361 // ES5 8.10.2.
    362 function IsDataDescriptor(desc) {
    363   if (IS_UNDEFINED(desc)) return false;
    364   return desc.hasValue() || desc.hasWritable();
    365 }
    366 
    367 
    368 // ES5 8.10.3.
    369 function IsGenericDescriptor(desc) {
    370   if (IS_UNDEFINED(desc)) return false;
    371   return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
    372 }
    373 
    374 
    375 function IsInconsistentDescriptor(desc) {
    376   return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
    377 }
    378 
    379 
    380 // ES5 8.10.4
    381 function FromPropertyDescriptor(desc) {
    382   if (IS_UNDEFINED(desc)) return desc;
    383 
    384   if (IsDataDescriptor(desc)) {
    385     return { value: desc.getValue(),
    386              writable: desc.isWritable(),
    387              enumerable: desc.isEnumerable(),
    388              configurable: desc.isConfigurable() };
    389   }
    390   // Must be an AccessorDescriptor then. We never return a generic descriptor.
    391   return { get: desc.getGet(),
    392            set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
    393                                                  : desc.getSet(),
    394            enumerable: desc.isEnumerable(),
    395            configurable: desc.isConfigurable() };
    396 }
    397 
    398 
    399 // Harmony Proxies
    400 function FromGenericPropertyDescriptor(desc) {
    401   if (IS_UNDEFINED(desc)) return desc;
    402   var obj = new $Object();
    403 
    404   if (desc.hasValue()) {
    405     %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
    406   }
    407   if (desc.hasWritable()) {
    408     %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
    409   }
    410   if (desc.hasGetter()) {
    411     %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
    412   }
    413   if (desc.hasSetter()) {
    414     %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
    415   }
    416   if (desc.hasEnumerable()) {
    417     %IgnoreAttributesAndSetProperty(obj, "enumerable",
    418                                     desc.isEnumerable(), NONE);
    419   }
    420   if (desc.hasConfigurable()) {
    421     %IgnoreAttributesAndSetProperty(obj, "configurable",
    422                                     desc.isConfigurable(), NONE);
    423   }
    424   return obj;
    425 }
    426 
    427 
    428 // ES5 8.10.5.
    429 function ToPropertyDescriptor(obj) {
    430   if (!IS_SPEC_OBJECT(obj)) {
    431     throw MakeTypeError("property_desc_object", [obj]);
    432   }
    433   var desc = new PropertyDescriptor();
    434 
    435   if ("enumerable" in obj) {
    436     desc.setEnumerable(ToBoolean(obj.enumerable));
    437   }
    438 
    439   if ("configurable" in obj) {
    440     desc.setConfigurable(ToBoolean(obj.configurable));
    441   }
    442 
    443   if ("value" in obj) {
    444     desc.setValue(obj.value);
    445   }
    446 
    447   if ("writable" in obj) {
    448     desc.setWritable(ToBoolean(obj.writable));
    449   }
    450 
    451   if ("get" in obj) {
    452     var get = obj.get;
    453     if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
    454       throw MakeTypeError("getter_must_be_callable", [get]);
    455     }
    456     desc.setGet(get);
    457   }
    458 
    459   if ("set" in obj) {
    460     var set = obj.set;
    461     if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
    462       throw MakeTypeError("setter_must_be_callable", [set]);
    463     }
    464     desc.setSet(set);
    465   }
    466 
    467   if (IsInconsistentDescriptor(desc)) {
    468     throw MakeTypeError("value_and_accessor", [obj]);
    469   }
    470   return desc;
    471 }
    472 
    473 
    474 // For Harmony proxies.
    475 function ToCompletePropertyDescriptor(obj) {
    476   var desc = ToPropertyDescriptor(obj);
    477   if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
    478     if (!desc.hasValue()) desc.setValue(void 0);
    479     if (!desc.hasWritable()) desc.setWritable(false);
    480   } else {
    481     // Is accessor descriptor.
    482     if (!desc.hasGetter()) desc.setGet(void 0);
    483     if (!desc.hasSetter()) desc.setSet(void 0);
    484   }
    485   if (!desc.hasEnumerable()) desc.setEnumerable(false);
    486   if (!desc.hasConfigurable()) desc.setConfigurable(false);
    487   return desc;
    488 }
    489 
    490 
    491 function PropertyDescriptor() {
    492   // Initialize here so they are all in-object and have the same map.
    493   // Default values from ES5 8.6.1.
    494   this.value_ = void 0;
    495   this.hasValue_ = false;
    496   this.writable_ = false;
    497   this.hasWritable_ = false;
    498   this.enumerable_ = false;
    499   this.hasEnumerable_ = false;
    500   this.configurable_ = false;
    501   this.hasConfigurable_ = false;
    502   this.get_ = void 0;
    503   this.hasGetter_ = false;
    504   this.set_ = void 0;
    505   this.hasSetter_ = false;
    506 }
    507 
    508 SetUpLockedPrototype(PropertyDescriptor, $Array(
    509     "value_",
    510     "hasValue_",
    511     "writable_",
    512     "hasWritable_",
    513     "enumerable_",
    514     "hasEnumerable_",
    515     "configurable_",
    516     "hasConfigurable_",
    517     "get_",
    518     "hasGetter_",
    519     "set_",
    520     "hasSetter_"
    521   ), $Array(
    522     "toString", function() {
    523       return "[object PropertyDescriptor]";
    524     },
    525     "setValue", function(value) {
    526       this.value_ = value;
    527       this.hasValue_ = true;
    528     },
    529     "getValue", function() {
    530       return this.value_;
    531     },
    532     "hasValue", function() {
    533       return this.hasValue_;
    534     },
    535     "setEnumerable", function(enumerable) {
    536       this.enumerable_ = enumerable;
    537         this.hasEnumerable_ = true;
    538     },
    539     "isEnumerable", function () {
    540       return this.enumerable_;
    541     },
    542     "hasEnumerable", function() {
    543       return this.hasEnumerable_;
    544     },
    545     "setWritable", function(writable) {
    546       this.writable_ = writable;
    547       this.hasWritable_ = true;
    548     },
    549     "isWritable", function() {
    550       return this.writable_;
    551     },
    552     "hasWritable", function() {
    553       return this.hasWritable_;
    554     },
    555     "setConfigurable", function(configurable) {
    556       this.configurable_ = configurable;
    557       this.hasConfigurable_ = true;
    558     },
    559     "hasConfigurable", function() {
    560       return this.hasConfigurable_;
    561     },
    562     "isConfigurable", function() {
    563       return this.configurable_;
    564     },
    565     "setGet", function(get) {
    566       this.get_ = get;
    567         this.hasGetter_ = true;
    568     },
    569     "getGet", function() {
    570       return this.get_;
    571     },
    572     "hasGetter", function() {
    573       return this.hasGetter_;
    574     },
    575     "setSet", function(set) {
    576       this.set_ = set;
    577       this.hasSetter_ = true;
    578     },
    579     "getSet", function() {
    580       return this.set_;
    581     },
    582     "hasSetter", function() {
    583       return this.hasSetter_;
    584   }));
    585 
    586 
    587 // Converts an array returned from Runtime_GetOwnProperty to an actual
    588 // property descriptor. For a description of the array layout please
    589 // see the runtime.cc file.
    590 function ConvertDescriptorArrayToDescriptor(desc_array) {
    591   if (desc_array === false) {
    592     throw 'Internal error: invalid desc_array';
    593   }
    594 
    595   if (IS_UNDEFINED(desc_array)) {
    596     return void 0;
    597   }
    598 
    599   var desc = new PropertyDescriptor();
    600   // This is an accessor.
    601   if (desc_array[IS_ACCESSOR_INDEX]) {
    602     desc.setGet(desc_array[GETTER_INDEX]);
    603     desc.setSet(desc_array[SETTER_INDEX]);
    604   } else {
    605     desc.setValue(desc_array[VALUE_INDEX]);
    606     desc.setWritable(desc_array[WRITABLE_INDEX]);
    607   }
    608   desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
    609   desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
    610 
    611   return desc;
    612 }
    613 
    614 
    615 // For Harmony proxies.
    616 function GetTrap(handler, name, defaultTrap) {
    617   var trap = handler[name];
    618   if (IS_UNDEFINED(trap)) {
    619     if (IS_UNDEFINED(defaultTrap)) {
    620       throw MakeTypeError("handler_trap_missing", [handler, name]);
    621     }
    622     trap = defaultTrap;
    623   } else if (!IS_SPEC_FUNCTION(trap)) {
    624     throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
    625   }
    626   return trap;
    627 }
    628 
    629 
    630 function CallTrap0(handler, name, defaultTrap) {
    631   return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
    632 }
    633 
    634 
    635 function CallTrap1(handler, name, defaultTrap, x) {
    636   return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
    637 }
    638 
    639 
    640 function CallTrap2(handler, name, defaultTrap, x, y) {
    641   return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
    642 }
    643 
    644 
    645 // ES5 section 8.12.1.
    646 function GetOwnProperty(obj, v) {
    647   var p = ToName(v);
    648   if (%IsJSProxy(obj)) {
    649     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    650     if (IS_SYMBOL(v)) return void 0;
    651 
    652     var handler = %GetHandler(obj);
    653     var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
    654     if (IS_UNDEFINED(descriptor)) return descriptor;
    655     var desc = ToCompletePropertyDescriptor(descriptor);
    656     if (!desc.isConfigurable()) {
    657       throw MakeTypeError("proxy_prop_not_configurable",
    658                           [handler, "getOwnPropertyDescriptor", p, descriptor]);
    659     }
    660     return desc;
    661   }
    662 
    663   // GetOwnProperty returns an array indexed by the constants
    664   // defined in macros.py.
    665   // If p is not a property on obj undefined is returned.
    666   var props = %GetOwnProperty(ToObject(obj), p);
    667 
    668   // A false value here means that access checks failed.
    669   if (props === false) return void 0;
    670 
    671   return ConvertDescriptorArrayToDescriptor(props);
    672 }
    673 
    674 
    675 // ES5 section 8.12.7.
    676 function Delete(obj, p, should_throw) {
    677   var desc = GetOwnProperty(obj, p);
    678   if (IS_UNDEFINED(desc)) return true;
    679   if (desc.isConfigurable()) {
    680     %DeleteProperty(obj, p, 0);
    681     return true;
    682   } else if (should_throw) {
    683     throw MakeTypeError("define_disallowed", [p]);
    684   } else {
    685     return;
    686   }
    687 }
    688 
    689 
    690 // Harmony proxies.
    691 function DefineProxyProperty(obj, p, attributes, should_throw) {
    692   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    693   if (IS_SYMBOL(p)) return false;
    694 
    695   var handler = %GetHandler(obj);
    696   var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
    697   if (!ToBoolean(result)) {
    698     if (should_throw) {
    699       throw MakeTypeError("handler_returned_false",
    700                           [handler, "defineProperty"]);
    701     } else {
    702       return false;
    703     }
    704   }
    705   return true;
    706 }
    707 
    708 
    709 // ES5 8.12.9.
    710 function DefineObjectProperty(obj, p, desc, should_throw) {
    711   var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
    712   // A false value here means that access checks failed.
    713   if (current_or_access === false) return void 0;
    714 
    715   var current = ConvertDescriptorArrayToDescriptor(current_or_access);
    716   var extensible = %IsExtensible(ToObject(obj));
    717 
    718   // Error handling according to spec.
    719   // Step 3
    720   if (IS_UNDEFINED(current) && !extensible) {
    721     if (should_throw) {
    722       throw MakeTypeError("define_disallowed", [p]);
    723     } else {
    724       return false;
    725     }
    726   }
    727 
    728   if (!IS_UNDEFINED(current)) {
    729     // Step 5 and 6
    730     if ((IsGenericDescriptor(desc) ||
    731          IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
    732         (!desc.hasEnumerable() ||
    733          SameValue(desc.isEnumerable(), current.isEnumerable())) &&
    734         (!desc.hasConfigurable() ||
    735          SameValue(desc.isConfigurable(), current.isConfigurable())) &&
    736         (!desc.hasWritable() ||
    737          SameValue(desc.isWritable(), current.isWritable())) &&
    738         (!desc.hasValue() ||
    739          SameValue(desc.getValue(), current.getValue())) &&
    740         (!desc.hasGetter() ||
    741          SameValue(desc.getGet(), current.getGet())) &&
    742         (!desc.hasSetter() ||
    743          SameValue(desc.getSet(), current.getSet()))) {
    744       return true;
    745     }
    746     if (!current.isConfigurable()) {
    747       // Step 7
    748       if (desc.isConfigurable() ||
    749           (desc.hasEnumerable() &&
    750            desc.isEnumerable() != current.isEnumerable())) {
    751         if (should_throw) {
    752           throw MakeTypeError("redefine_disallowed", [p]);
    753         } else {
    754           return false;
    755         }
    756       }
    757       // Step 8
    758       if (!IsGenericDescriptor(desc)) {
    759         // Step 9a
    760         if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
    761           if (should_throw) {
    762             throw MakeTypeError("redefine_disallowed", [p]);
    763           } else {
    764             return false;
    765           }
    766         }
    767         // Step 10a
    768         if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
    769           if (!current.isWritable() && desc.isWritable()) {
    770             if (should_throw) {
    771               throw MakeTypeError("redefine_disallowed", [p]);
    772             } else {
    773               return false;
    774             }
    775           }
    776           if (!current.isWritable() && desc.hasValue() &&
    777               !SameValue(desc.getValue(), current.getValue())) {
    778             if (should_throw) {
    779               throw MakeTypeError("redefine_disallowed", [p]);
    780             } else {
    781               return false;
    782             }
    783           }
    784         }
    785         // Step 11
    786         if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
    787           if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
    788             if (should_throw) {
    789               throw MakeTypeError("redefine_disallowed", [p]);
    790             } else {
    791               return false;
    792             }
    793           }
    794           if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
    795             if (should_throw) {
    796               throw MakeTypeError("redefine_disallowed", [p]);
    797             } else {
    798               return false;
    799             }
    800           }
    801         }
    802       }
    803     }
    804   }
    805 
    806   // Send flags - enumerable and configurable are common - writable is
    807   // only send to the data descriptor.
    808   // Take special care if enumerable and configurable is not defined on
    809   // desc (we need to preserve the existing values from current).
    810   var flag = NONE;
    811   if (desc.hasEnumerable()) {
    812     flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
    813   } else if (!IS_UNDEFINED(current)) {
    814     flag |= current.isEnumerable() ? 0 : DONT_ENUM;
    815   } else {
    816     flag |= DONT_ENUM;
    817   }
    818 
    819   if (desc.hasConfigurable()) {
    820     flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
    821   } else if (!IS_UNDEFINED(current)) {
    822     flag |= current.isConfigurable() ? 0 : DONT_DELETE;
    823   } else
    824     flag |= DONT_DELETE;
    825 
    826   if (IsDataDescriptor(desc) ||
    827       (IsGenericDescriptor(desc) &&
    828        (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
    829     // There are 3 cases that lead here:
    830     // Step 4a - defining a new data property.
    831     // Steps 9b & 12 - replacing an existing accessor property with a data
    832     //                 property.
    833     // Step 12 - updating an existing data property with a data or generic
    834     //           descriptor.
    835 
    836     if (desc.hasWritable()) {
    837       flag |= desc.isWritable() ? 0 : READ_ONLY;
    838     } else if (!IS_UNDEFINED(current)) {
    839       flag |= current.isWritable() ? 0 : READ_ONLY;
    840     } else {
    841       flag |= READ_ONLY;
    842     }
    843 
    844     var value = void 0;  // Default value is undefined.
    845     if (desc.hasValue()) {
    846       value = desc.getValue();
    847     } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
    848       value = current.getValue();
    849     }
    850 
    851     %DefineOrRedefineDataProperty(obj, p, value, flag);
    852   } else {
    853     // There are 3 cases that lead here:
    854     // Step 4b - defining a new accessor property.
    855     // Steps 9c & 12 - replacing an existing data property with an accessor
    856     //                 property.
    857     // Step 12 - updating an existing accessor property with an accessor
    858     //           descriptor.
    859     var getter = desc.hasGetter() ? desc.getGet() : null;
    860     var setter = desc.hasSetter() ? desc.getSet() : null;
    861     %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
    862   }
    863   return true;
    864 }
    865 
    866 
    867 // ES5 section 15.4.5.1.
    868 function DefineArrayProperty(obj, p, desc, should_throw) {
    869   // Note that the length of an array is not actually stored as part of the
    870   // property, hence we use generated code throughout this function instead of
    871   // DefineObjectProperty() to modify its value.
    872 
    873   // Step 3 - Special handling for length property.
    874   if (p === "length") {
    875     var length = obj.length;
    876     var old_length = length;
    877     if (!desc.hasValue()) {
    878       return DefineObjectProperty(obj, "length", desc, should_throw);
    879     }
    880     var new_length = ToUint32(desc.getValue());
    881     if (new_length != ToNumber(desc.getValue())) {
    882       throw new $RangeError('defineProperty() array length out of range');
    883     }
    884     var length_desc = GetOwnProperty(obj, "length");
    885     if (new_length != length && !length_desc.isWritable()) {
    886       if (should_throw) {
    887         throw MakeTypeError("redefine_disallowed", [p]);
    888       } else {
    889         return false;
    890       }
    891     }
    892     var threw = false;
    893 
    894     var emit_splice = %IsObserved(obj) && new_length !== old_length;
    895     var removed;
    896     if (emit_splice) {
    897       BeginPerformSplice(obj);
    898       removed = [];
    899       if (new_length < old_length)
    900         removed.length = old_length - new_length;
    901     }
    902 
    903     while (new_length < length--) {
    904       var index = ToString(length);
    905       if (emit_splice) {
    906         var deletedDesc = GetOwnProperty(obj, index);
    907         if (deletedDesc && deletedDesc.hasValue())
    908           removed[length - new_length] = deletedDesc.getValue();
    909       }
    910       if (!Delete(obj, index, false)) {
    911         new_length = length + 1;
    912         threw = true;
    913         break;
    914       }
    915     }
    916     // Make sure the below call to DefineObjectProperty() doesn't overwrite
    917     // any magic "length" property by removing the value.
    918     // TODO(mstarzinger): This hack should be removed once we have addressed the
    919     // respective TODO in Runtime_DefineOrRedefineDataProperty.
    920     // For the time being, we need a hack to prevent Object.observe from
    921     // generating two change records.
    922     obj.length = new_length;
    923     desc.value_ = void 0;
    924     desc.hasValue_ = false;
    925     threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
    926     if (emit_splice) {
    927       EndPerformSplice(obj);
    928       EnqueueSpliceRecord(obj,
    929           new_length < old_length ? new_length : old_length,
    930           removed,
    931           new_length > old_length ? new_length - old_length : 0);
    932     }
    933     if (threw) {
    934       if (should_throw) {
    935         throw MakeTypeError("redefine_disallowed", [p]);
    936       } else {
    937         return false;
    938       }
    939     }
    940     return true;
    941   }
    942 
    943   // Step 4 - Special handling for array index.
    944   var index = ToUint32(p);
    945   var emit_splice = false;
    946   if (ToString(index) == p && index != 4294967295) {
    947     var length = obj.length;
    948     if (index >= length && %IsObserved(obj)) {
    949       emit_splice = true;
    950       BeginPerformSplice(obj);
    951     }
    952 
    953     var length_desc = GetOwnProperty(obj, "length");
    954     if ((index >= length && !length_desc.isWritable()) ||
    955         !DefineObjectProperty(obj, p, desc, true)) {
    956       if (emit_splice)
    957         EndPerformSplice(obj);
    958       if (should_throw) {
    959         throw MakeTypeError("define_disallowed", [p]);
    960       } else {
    961         return false;
    962       }
    963     }
    964     if (index >= length) {
    965       obj.length = index + 1;
    966     }
    967     if (emit_splice) {
    968       EndPerformSplice(obj);
    969       EnqueueSpliceRecord(obj, length, [], index + 1 - length);
    970     }
    971     return true;
    972   }
    973 
    974   // Step 5 - Fallback to default implementation.
    975   return DefineObjectProperty(obj, p, desc, should_throw);
    976 }
    977 
    978 
    979 // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
    980 function DefineOwnProperty(obj, p, desc, should_throw) {
    981   if (%IsJSProxy(obj)) {
    982     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    983     if (IS_SYMBOL(p)) return false;
    984 
    985     var attributes = FromGenericPropertyDescriptor(desc);
    986     return DefineProxyProperty(obj, p, attributes, should_throw);
    987   } else if (IS_ARRAY(obj)) {
    988     return DefineArrayProperty(obj, p, desc, should_throw);
    989   } else {
    990     return DefineObjectProperty(obj, p, desc, should_throw);
    991   }
    992 }
    993 
    994 
    995 // ES5 section 15.2.3.2.
    996 function ObjectGetPrototypeOf(obj) {
    997   if (!IS_SPEC_OBJECT(obj)) {
    998     throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
    999   }
   1000   return %GetPrototype(obj);
   1001 }
   1002 
   1003 
   1004 // ES5 section 15.2.3.3
   1005 function ObjectGetOwnPropertyDescriptor(obj, p) {
   1006   if (!IS_SPEC_OBJECT(obj)) {
   1007     throw MakeTypeError("called_on_non_object",
   1008                         ["Object.getOwnPropertyDescriptor"]);
   1009   }
   1010   var desc = GetOwnProperty(obj, p);
   1011   return FromPropertyDescriptor(desc);
   1012 }
   1013 
   1014 
   1015 // For Harmony proxies
   1016 function ToNameArray(obj, trap, includeSymbols) {
   1017   if (!IS_SPEC_OBJECT(obj)) {
   1018     throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
   1019   }
   1020   var n = ToUint32(obj.length);
   1021   var array = new $Array(n);
   1022   var realLength = 0;
   1023   var names = { __proto__: null };  // TODO(rossberg): use sets once ready.
   1024   for (var index = 0; index < n; index++) {
   1025     var s = ToName(obj[index]);
   1026     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
   1027     if (IS_SYMBOL(s) && !includeSymbols) continue;
   1028     if (%HasLocalProperty(names, s)) {
   1029       throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
   1030     }
   1031     array[index] = s;
   1032     ++realLength;
   1033     names[s] = 0;
   1034   }
   1035   array.length = realLength;
   1036   return array;
   1037 }
   1038 
   1039 
   1040 // ES5 section 15.2.3.4.
   1041 function ObjectGetOwnPropertyNames(obj) {
   1042   if (!IS_SPEC_OBJECT(obj)) {
   1043     throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
   1044   }
   1045   // Special handling for proxies.
   1046   if (%IsJSProxy(obj)) {
   1047     var handler = %GetHandler(obj);
   1048     var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
   1049     return ToNameArray(names, "getOwnPropertyNames", false);
   1050   }
   1051 
   1052   var nameArrays = new InternalArray();
   1053 
   1054   // Find all the indexed properties.
   1055 
   1056   // Get the local element names.
   1057   var localElementNames = %GetLocalElementNames(obj);
   1058   for (var i = 0; i < localElementNames.length; ++i) {
   1059     localElementNames[i] = %_NumberToString(localElementNames[i]);
   1060   }
   1061   nameArrays.push(localElementNames);
   1062 
   1063   // Get names for indexed interceptor properties.
   1064   var interceptorInfo = %GetInterceptorInfo(obj);
   1065   if ((interceptorInfo & 1) != 0) {
   1066     var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
   1067     if (!IS_UNDEFINED(indexedInterceptorNames)) {
   1068       nameArrays.push(indexedInterceptorNames);
   1069     }
   1070   }
   1071 
   1072   // Find all the named properties.
   1073 
   1074   // Get the local property names.
   1075   nameArrays.push(%GetLocalPropertyNames(obj, false));
   1076 
   1077   // Get names for named interceptor properties if any.
   1078   if ((interceptorInfo & 2) != 0) {
   1079     var namedInterceptorNames = %GetNamedInterceptorPropertyNames(obj);
   1080     if (!IS_UNDEFINED(namedInterceptorNames)) {
   1081       nameArrays.push(namedInterceptorNames);
   1082     }
   1083   }
   1084 
   1085   var propertyNames =
   1086       %Apply(InternalArray.prototype.concat,
   1087              nameArrays[0], nameArrays, 1, nameArrays.length - 1);
   1088 
   1089   // Property names are expected to be unique strings,
   1090   // but interceptors can interfere with that assumption.
   1091   if (interceptorInfo != 0) {
   1092     var propertySet = { __proto__: null };
   1093     var j = 0;
   1094     for (var i = 0; i < propertyNames.length; ++i) {
   1095       if (IS_SYMBOL(propertyNames[i])) continue;
   1096       var name = ToString(propertyNames[i]);
   1097       // We need to check for the exact property value since for intrinsic
   1098       // properties like toString if(propertySet["toString"]) will always
   1099       // succeed.
   1100       if (propertySet[name] === true) {
   1101         continue;
   1102       }
   1103       propertySet[name] = true;
   1104       propertyNames[j++] = name;
   1105     }
   1106     propertyNames.length = j;
   1107   }
   1108 
   1109   return propertyNames;
   1110 }
   1111 
   1112 
   1113 // ES5 section 15.2.3.5.
   1114 function ObjectCreate(proto, properties) {
   1115   if (!IS_SPEC_OBJECT(proto) && proto !== null) {
   1116     throw MakeTypeError("proto_object_or_null", [proto]);
   1117   }
   1118   var obj = { __proto__: proto };
   1119   if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
   1120   return obj;
   1121 }
   1122 
   1123 
   1124 // ES5 section 15.2.3.6.
   1125 function ObjectDefineProperty(obj, p, attributes) {
   1126   if (!IS_SPEC_OBJECT(obj)) {
   1127     throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
   1128   }
   1129   var name = ToName(p);
   1130   if (%IsJSProxy(obj)) {
   1131     // Clone the attributes object for protection.
   1132     // TODO(rossberg): not spec'ed yet, so not sure if this should involve
   1133     // non-own properties as it does (or non-enumerable ones, as it doesn't?).
   1134     var attributesClone = { __proto__: null };
   1135     for (var a in attributes) {
   1136       attributesClone[a] = attributes[a];
   1137     }
   1138     DefineProxyProperty(obj, name, attributesClone, true);
   1139     // The following would implement the spec as in the current proposal,
   1140     // but after recent comments on es-discuss, is most likely obsolete.
   1141     /*
   1142     var defineObj = FromGenericPropertyDescriptor(desc);
   1143     var names = ObjectGetOwnPropertyNames(attributes);
   1144     var standardNames =
   1145       {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
   1146     for (var i = 0; i < names.length; i++) {
   1147       var N = names[i];
   1148       if (!(%HasLocalProperty(standardNames, N))) {
   1149         var attr = GetOwnProperty(attributes, N);
   1150         DefineOwnProperty(descObj, N, attr, true);
   1151       }
   1152     }
   1153     // This is really confusing the types, but it is what the proxies spec
   1154     // currently requires:
   1155     desc = descObj;
   1156     */
   1157   } else {
   1158     var desc = ToPropertyDescriptor(attributes);
   1159     DefineOwnProperty(obj, name, desc, true);
   1160   }
   1161   return obj;
   1162 }
   1163 
   1164 
   1165 function GetOwnEnumerablePropertyNames(properties) {
   1166   var names = new InternalArray();
   1167   for (var key in properties) {
   1168     if (%HasLocalProperty(properties, key)) {
   1169       names.push(key);
   1170     }
   1171   }
   1172   return names;
   1173 }
   1174 
   1175 
   1176 // ES5 section 15.2.3.7.
   1177 function ObjectDefineProperties(obj, properties) {
   1178   if (!IS_SPEC_OBJECT(obj)) {
   1179     throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
   1180   }
   1181   var props = ToObject(properties);
   1182   var names = GetOwnEnumerablePropertyNames(props);
   1183   var descriptors = new InternalArray();
   1184   for (var i = 0; i < names.length; i++) {
   1185     descriptors.push(ToPropertyDescriptor(props[names[i]]));
   1186   }
   1187   for (var i = 0; i < names.length; i++) {
   1188     DefineOwnProperty(obj, names[i], descriptors[i], true);
   1189   }
   1190   return obj;
   1191 }
   1192 
   1193 
   1194 // Harmony proxies.
   1195 function ProxyFix(obj) {
   1196   var handler = %GetHandler(obj);
   1197   var props = CallTrap0(handler, "fix", void 0);
   1198   if (IS_UNDEFINED(props)) {
   1199     throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
   1200   }
   1201 
   1202   if (%IsJSFunctionProxy(obj)) {
   1203     var callTrap = %GetCallTrap(obj);
   1204     var constructTrap = %GetConstructTrap(obj);
   1205     var code = DelegateCallAndConstruct(callTrap, constructTrap);
   1206     %Fix(obj);  // becomes a regular function
   1207     %SetCode(obj, code);
   1208     // TODO(rossberg): What about length and other properties? Not specified.
   1209     // We just put in some half-reasonable defaults for now.
   1210     var prototype = new $Object();
   1211     $Object.defineProperty(prototype, "constructor",
   1212       {value: obj, writable: true, enumerable: false, configurable: true});
   1213     // TODO(v8:1530): defineProperty does not handle prototype and length.
   1214     %FunctionSetPrototype(obj, prototype);
   1215     obj.length = 0;
   1216   } else {
   1217     %Fix(obj);
   1218   }
   1219   ObjectDefineProperties(obj, props);
   1220 }
   1221 
   1222 
   1223 // ES5 section 15.2.3.8.
   1224 function ObjectSeal(obj) {
   1225   if (!IS_SPEC_OBJECT(obj)) {
   1226     throw MakeTypeError("called_on_non_object", ["Object.seal"]);
   1227   }
   1228   if (%IsJSProxy(obj)) {
   1229     ProxyFix(obj);
   1230   }
   1231   var names = ObjectGetOwnPropertyNames(obj);
   1232   for (var i = 0; i < names.length; i++) {
   1233     var name = names[i];
   1234     var desc = GetOwnProperty(obj, name);
   1235     if (desc.isConfigurable()) {
   1236       desc.setConfigurable(false);
   1237       DefineOwnProperty(obj, name, desc, true);
   1238     }
   1239   }
   1240   %PreventExtensions(obj);
   1241   return obj;
   1242 }
   1243 
   1244 
   1245 // ES5 section 15.2.3.9.
   1246 function ObjectFreeze(obj) {
   1247   if (!IS_SPEC_OBJECT(obj)) {
   1248     throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
   1249   }
   1250   var isProxy = %IsJSProxy(obj);
   1251   if (isProxy || %HasNonStrictArgumentsElements(obj)) {
   1252     if (isProxy) {
   1253       ProxyFix(obj);
   1254     }
   1255     var names = ObjectGetOwnPropertyNames(obj);
   1256     for (var i = 0; i < names.length; i++) {
   1257       var name = names[i];
   1258       var desc = GetOwnProperty(obj, name);
   1259       if (desc.isWritable() || desc.isConfigurable()) {
   1260         if (IsDataDescriptor(desc)) desc.setWritable(false);
   1261         desc.setConfigurable(false);
   1262         DefineOwnProperty(obj, name, desc, true);
   1263       }
   1264     }
   1265     %PreventExtensions(obj);
   1266   } else {
   1267     // TODO(adamk): Is it worth going to this fast path if the
   1268     // object's properties are already in dictionary mode?
   1269     %ObjectFreeze(obj);
   1270   }
   1271   return obj;
   1272 }
   1273 
   1274 
   1275 // ES5 section 15.2.3.10
   1276 function ObjectPreventExtension(obj) {
   1277   if (!IS_SPEC_OBJECT(obj)) {
   1278     throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
   1279   }
   1280   if (%IsJSProxy(obj)) {
   1281     ProxyFix(obj);
   1282   }
   1283   %PreventExtensions(obj);
   1284   return obj;
   1285 }
   1286 
   1287 
   1288 // ES5 section 15.2.3.11
   1289 function ObjectIsSealed(obj) {
   1290   if (!IS_SPEC_OBJECT(obj)) {
   1291     throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
   1292   }
   1293   if (%IsJSProxy(obj)) {
   1294     return false;
   1295   }
   1296   if (%IsExtensible(obj)) {
   1297     return false;
   1298   }
   1299   var names = ObjectGetOwnPropertyNames(obj);
   1300   for (var i = 0; i < names.length; i++) {
   1301     var name = names[i];
   1302     var desc = GetOwnProperty(obj, name);
   1303     if (desc.isConfigurable()) return false;
   1304   }
   1305   return true;
   1306 }
   1307 
   1308 
   1309 // ES5 section 15.2.3.12
   1310 function ObjectIsFrozen(obj) {
   1311   if (!IS_SPEC_OBJECT(obj)) {
   1312     throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
   1313   }
   1314   if (%IsJSProxy(obj)) {
   1315     return false;
   1316   }
   1317   if (%IsExtensible(obj)) {
   1318     return false;
   1319   }
   1320   var names = ObjectGetOwnPropertyNames(obj);
   1321   for (var i = 0; i < names.length; i++) {
   1322     var name = names[i];
   1323     var desc = GetOwnProperty(obj, name);
   1324     if (IsDataDescriptor(desc) && desc.isWritable()) return false;
   1325     if (desc.isConfigurable()) return false;
   1326   }
   1327   return true;
   1328 }
   1329 
   1330 
   1331 // ES5 section 15.2.3.13
   1332 function ObjectIsExtensible(obj) {
   1333   if (!IS_SPEC_OBJECT(obj)) {
   1334     throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
   1335   }
   1336   if (%IsJSProxy(obj)) {
   1337     return true;
   1338   }
   1339   return %IsExtensible(obj);
   1340 }
   1341 
   1342 
   1343 // Harmony egal.
   1344 function ObjectIs(obj1, obj2) {
   1345   if (obj1 === obj2) {
   1346     return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
   1347   } else {
   1348     return (obj1 !== obj1) && (obj2 !== obj2);
   1349   }
   1350 }
   1351 
   1352 
   1353 // Harmony __proto__ getter.
   1354 function ObjectGetProto() {
   1355   return %GetPrototype(this);
   1356 }
   1357 
   1358 
   1359 // Harmony __proto__ setter.
   1360 function ObjectSetProto(obj) {
   1361   return %SetPrototype(this, obj);
   1362 }
   1363 
   1364 
   1365 // Harmony __proto__ poison pill.
   1366 function ObjectPoisonProto(obj) {
   1367   throw MakeTypeError("proto_poison_pill", []);
   1368 }
   1369 
   1370 
   1371 function ObjectConstructor(x) {
   1372   if (%_IsConstructCall()) {
   1373     if (x == null) return this;
   1374     return ToObject(x);
   1375   } else {
   1376     if (x == null) return { };
   1377     return ToObject(x);
   1378   }
   1379 }
   1380 
   1381 
   1382 // ----------------------------------------------------------------------------
   1383 // Object
   1384 
   1385 function SetUpObject() {
   1386   %CheckIsBootstrapping();
   1387 
   1388   %SetNativeFlag($Object);
   1389   %SetCode($Object, ObjectConstructor);
   1390   %FunctionSetName(ObjectPoisonProto, "__proto__");
   1391   %FunctionRemovePrototype(ObjectPoisonProto);
   1392   %SetExpectedNumberOfProperties($Object, 4);
   1393 
   1394   %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
   1395 
   1396   // Set up non-enumerable functions on the Object.prototype object.
   1397   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
   1398     "toString", ObjectToString,
   1399     "toLocaleString", ObjectToLocaleString,
   1400     "valueOf", ObjectValueOf,
   1401     "hasOwnProperty", ObjectHasOwnProperty,
   1402     "isPrototypeOf", ObjectIsPrototypeOf,
   1403     "propertyIsEnumerable", ObjectPropertyIsEnumerable,
   1404     "__defineGetter__", ObjectDefineGetter,
   1405     "__lookupGetter__", ObjectLookupGetter,
   1406     "__defineSetter__", ObjectDefineSetter,
   1407     "__lookupSetter__", ObjectLookupSetter
   1408   ));
   1409   InstallGetterSetter($Object.prototype, "__proto__",
   1410                       ObjectGetProto, ObjectSetProto);
   1411 
   1412   // Set up non-enumerable functions in the Object object.
   1413   InstallFunctions($Object, DONT_ENUM, $Array(
   1414     "keys", ObjectKeys,
   1415     "create", ObjectCreate,
   1416     "defineProperty", ObjectDefineProperty,
   1417     "defineProperties", ObjectDefineProperties,
   1418     "freeze", ObjectFreeze,
   1419     "getPrototypeOf", ObjectGetPrototypeOf,
   1420     "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
   1421     "getOwnPropertyNames", ObjectGetOwnPropertyNames,
   1422     "is", ObjectIs,
   1423     "isExtensible", ObjectIsExtensible,
   1424     "isFrozen", ObjectIsFrozen,
   1425     "isSealed", ObjectIsSealed,
   1426     "preventExtensions", ObjectPreventExtension,
   1427     "seal", ObjectSeal
   1428   ));
   1429 }
   1430 
   1431 SetUpObject();
   1432 
   1433 
   1434 // ----------------------------------------------------------------------------
   1435 // Boolean
   1436 
   1437 function BooleanConstructor(x) {
   1438   if (%_IsConstructCall()) {
   1439     %_SetValueOf(this, ToBoolean(x));
   1440   } else {
   1441     return ToBoolean(x);
   1442   }
   1443 }
   1444 
   1445 
   1446 function BooleanToString() {
   1447   // NOTE: Both Boolean objects and values can enter here as
   1448   // 'this'. This is not as dictated by ECMA-262.
   1449   var b = this;
   1450   if (!IS_BOOLEAN(b)) {
   1451     if (!IS_BOOLEAN_WRAPPER(b)) {
   1452       throw new $TypeError('Boolean.prototype.toString is not generic');
   1453     }
   1454     b = %_ValueOf(b);
   1455   }
   1456   return b ? 'true' : 'false';
   1457 }
   1458 
   1459 
   1460 function BooleanValueOf() {
   1461   // NOTE: Both Boolean objects and values can enter here as
   1462   // 'this'. This is not as dictated by ECMA-262.
   1463   if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
   1464     throw new $TypeError('Boolean.prototype.valueOf is not generic');
   1465   }
   1466   return %_ValueOf(this);
   1467 }
   1468 
   1469 
   1470 // ----------------------------------------------------------------------------
   1471 
   1472 function SetUpBoolean () {
   1473   %CheckIsBootstrapping();
   1474 
   1475   %SetCode($Boolean, BooleanConstructor);
   1476   %FunctionSetPrototype($Boolean, new $Boolean(false));
   1477   %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
   1478 
   1479   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
   1480     "toString", BooleanToString,
   1481     "valueOf", BooleanValueOf
   1482   ));
   1483 }
   1484 
   1485 SetUpBoolean();
   1486 
   1487 
   1488 // ----------------------------------------------------------------------------
   1489 // Number
   1490 
   1491 function NumberConstructor(x) {
   1492   var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
   1493   if (%_IsConstructCall()) {
   1494     %_SetValueOf(this, value);
   1495   } else {
   1496     return value;
   1497   }
   1498 }
   1499 
   1500 
   1501 // ECMA-262 section 15.7.4.2.
   1502 function NumberToString(radix) {
   1503   // NOTE: Both Number objects and values can enter here as
   1504   // 'this'. This is not as dictated by ECMA-262.
   1505   var number = this;
   1506   if (!IS_NUMBER(this)) {
   1507     if (!IS_NUMBER_WRAPPER(this)) {
   1508       throw new $TypeError('Number.prototype.toString is not generic');
   1509     }
   1510     // Get the value of this number in case it's an object.
   1511     number = %_ValueOf(this);
   1512   }
   1513   // Fast case: Convert number in radix 10.
   1514   if (IS_UNDEFINED(radix) || radix === 10) {
   1515     return %_NumberToString(number);
   1516   }
   1517 
   1518   // Convert the radix to an integer and check the range.
   1519   radix = TO_INTEGER(radix);
   1520   if (radix < 2 || radix > 36) {
   1521     throw new $RangeError('toString() radix argument must be between 2 and 36');
   1522   }
   1523   // Convert the number to a string in the given radix.
   1524   return %NumberToRadixString(number, radix);
   1525 }
   1526 
   1527 
   1528 // ECMA-262 section 15.7.4.3
   1529 function NumberToLocaleString() {
   1530   return %_CallFunction(this, NumberToString);
   1531 }
   1532 
   1533 
   1534 // ECMA-262 section 15.7.4.4
   1535 function NumberValueOf() {
   1536   // NOTE: Both Number objects and values can enter here as
   1537   // 'this'. This is not as dictated by ECMA-262.
   1538   if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
   1539     throw new $TypeError('Number.prototype.valueOf is not generic');
   1540   }
   1541   return %_ValueOf(this);
   1542 }
   1543 
   1544 
   1545 // ECMA-262 section 15.7.4.5
   1546 function NumberToFixed(fractionDigits) {
   1547   var x = this;
   1548   if (!IS_NUMBER(this)) {
   1549     if (!IS_NUMBER_WRAPPER(this)) {
   1550       throw MakeTypeError("incompatible_method_receiver",
   1551                           ["Number.prototype.toFixed", this]);
   1552     }
   1553     // Get the value of this number in case it's an object.
   1554     x = %_ValueOf(this);
   1555   }
   1556   var f = TO_INTEGER(fractionDigits);
   1557 
   1558   if (f < 0 || f > 20) {
   1559     throw new $RangeError("toFixed() digits argument must be between 0 and 20");
   1560   }
   1561 
   1562   if (NUMBER_IS_NAN(x)) return "NaN";
   1563   if (x == 1/0) return "Infinity";
   1564   if (x == -1/0) return "-Infinity";
   1565 
   1566   return %NumberToFixed(x, f);
   1567 }
   1568 
   1569 
   1570 // ECMA-262 section 15.7.4.6
   1571 function NumberToExponential(fractionDigits) {
   1572   var x = this;
   1573   if (!IS_NUMBER(this)) {
   1574     if (!IS_NUMBER_WRAPPER(this)) {
   1575       throw MakeTypeError("incompatible_method_receiver",
   1576                           ["Number.prototype.toExponential", this]);
   1577     }
   1578     // Get the value of this number in case it's an object.
   1579     x = %_ValueOf(this);
   1580   }
   1581   var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
   1582 
   1583   if (NUMBER_IS_NAN(x)) return "NaN";
   1584   if (x == 1/0) return "Infinity";
   1585   if (x == -1/0) return "-Infinity";
   1586 
   1587   if (IS_UNDEFINED(f)) {
   1588     f = -1;  // Signal for runtime function that f is not defined.
   1589   } else if (f < 0 || f > 20) {
   1590     throw new $RangeError("toExponential() argument must be between 0 and 20");
   1591   }
   1592   return %NumberToExponential(x, f);
   1593 }
   1594 
   1595 
   1596 // ECMA-262 section 15.7.4.7
   1597 function NumberToPrecision(precision) {
   1598   var x = this;
   1599   if (!IS_NUMBER(this)) {
   1600     if (!IS_NUMBER_WRAPPER(this)) {
   1601       throw MakeTypeError("incompatible_method_receiver",
   1602                           ["Number.prototype.toPrecision", this]);
   1603     }
   1604     // Get the value of this number in case it's an object.
   1605     x = %_ValueOf(this);
   1606   }
   1607   if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
   1608   var p = TO_INTEGER(precision);
   1609 
   1610   if (NUMBER_IS_NAN(x)) return "NaN";
   1611   if (x == 1/0) return "Infinity";
   1612   if (x == -1/0) return "-Infinity";
   1613 
   1614   if (p < 1 || p > 21) {
   1615     throw new $RangeError("toPrecision() argument must be between 1 and 21");
   1616   }
   1617   return %NumberToPrecision(x, p);
   1618 }
   1619 
   1620 
   1621 // Harmony isFinite.
   1622 function NumberIsFinite(number) {
   1623   return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
   1624 }
   1625 
   1626 
   1627 // Harmony isNaN.
   1628 function NumberIsNaN(number) {
   1629   return IS_NUMBER(number) && NUMBER_IS_NAN(number);
   1630 }
   1631 
   1632 
   1633 // ----------------------------------------------------------------------------
   1634 
   1635 function SetUpNumber() {
   1636   %CheckIsBootstrapping();
   1637 
   1638   %SetCode($Number, NumberConstructor);
   1639   %FunctionSetPrototype($Number, new $Number(0));
   1640 
   1641   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
   1642   // Set up the constructor property on the Number prototype object.
   1643   %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
   1644 
   1645   %OptimizeObjectForAddingMultipleProperties($Number, 5);
   1646   // ECMA-262 section 15.7.3.1.
   1647   %SetProperty($Number,
   1648                "MAX_VALUE",
   1649                1.7976931348623157e+308,
   1650                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1651 
   1652   // ECMA-262 section 15.7.3.2.
   1653   %SetProperty($Number, "MIN_VALUE", 5e-324,
   1654                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1655 
   1656   // ECMA-262 section 15.7.3.3.
   1657   %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
   1658 
   1659   // ECMA-262 section 15.7.3.4.
   1660   %SetProperty($Number,
   1661                "NEGATIVE_INFINITY",
   1662                -1/0,
   1663                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1664 
   1665   // ECMA-262 section 15.7.3.5.
   1666   %SetProperty($Number,
   1667                "POSITIVE_INFINITY",
   1668                1/0,
   1669                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1670   %ToFastProperties($Number);
   1671 
   1672   // Set up non-enumerable functions on the Number prototype object.
   1673   InstallFunctions($Number.prototype, DONT_ENUM, $Array(
   1674     "toString", NumberToString,
   1675     "toLocaleString", NumberToLocaleString,
   1676     "valueOf", NumberValueOf,
   1677     "toFixed", NumberToFixed,
   1678     "toExponential", NumberToExponential,
   1679     "toPrecision", NumberToPrecision
   1680   ));
   1681   InstallFunctions($Number, DONT_ENUM, $Array(
   1682     "isFinite", NumberIsFinite,
   1683     "isNaN", NumberIsNaN
   1684   ));
   1685 }
   1686 
   1687 SetUpNumber();
   1688 
   1689 
   1690 // ----------------------------------------------------------------------------
   1691 // Function
   1692 
   1693 function FunctionSourceString(func) {
   1694   while (%IsJSFunctionProxy(func)) {
   1695     func = %GetCallTrap(func);
   1696   }
   1697 
   1698   if (!IS_FUNCTION(func)) {
   1699     throw new $TypeError('Function.prototype.toString is not generic');
   1700   }
   1701 
   1702   var source = %FunctionGetSourceCode(func);
   1703   if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
   1704     var name = %FunctionGetName(func);
   1705     if (name) {
   1706       // Mimic what KJS does.
   1707       return 'function ' + name + '() { [native code] }';
   1708     } else {
   1709       return 'function () { [native code] }';
   1710     }
   1711   }
   1712 
   1713   var name = %FunctionNameShouldPrintAsAnonymous(func)
   1714       ? 'anonymous'
   1715       : %FunctionGetName(func);
   1716   var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
   1717   return head + name + source;
   1718 }
   1719 
   1720 
   1721 function FunctionToString() {
   1722   return FunctionSourceString(this);
   1723 }
   1724 
   1725 
   1726 // ES5 15.3.4.5
   1727 function FunctionBind(this_arg) { // Length is 1.
   1728   if (!IS_SPEC_FUNCTION(this)) {
   1729     throw new $TypeError('Bind must be called on a function');
   1730   }
   1731   var boundFunction = function () {
   1732     // Poison .arguments and .caller, but is otherwise not detectable.
   1733     "use strict";
   1734     // This function must not use any object literals (Object, Array, RegExp),
   1735     // since the literals-array is being used to store the bound data.
   1736     if (%_IsConstructCall()) {
   1737       return %NewObjectFromBound(boundFunction);
   1738     }
   1739     var bindings = %BoundFunctionGetBindings(boundFunction);
   1740 
   1741     var argc = %_ArgumentsLength();
   1742     if (argc == 0) {
   1743       return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
   1744     }
   1745     if (bindings.length === 2) {
   1746       return %Apply(bindings[0], bindings[1], arguments, 0, argc);
   1747     }
   1748     var bound_argc = bindings.length - 2;
   1749     var argv = new InternalArray(bound_argc + argc);
   1750     for (var i = 0; i < bound_argc; i++) {
   1751       argv[i] = bindings[i + 2];
   1752     }
   1753     for (var j = 0; j < argc; j++) {
   1754       argv[i++] = %_Arguments(j);
   1755     }
   1756     return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
   1757   };
   1758 
   1759   %FunctionRemovePrototype(boundFunction);
   1760   var new_length = 0;
   1761   if (%_ClassOf(this) == "Function") {
   1762     // Function or FunctionProxy.
   1763     var old_length = this.length;
   1764     // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
   1765     if ((typeof old_length === "number") &&
   1766         ((old_length >>> 0) === old_length)) {
   1767       var argc = %_ArgumentsLength();
   1768       if (argc > 0) argc--;  // Don't count the thisArg as parameter.
   1769       new_length = old_length - argc;
   1770       if (new_length < 0) new_length = 0;
   1771     }
   1772   }
   1773   // This runtime function finds any remaining arguments on the stack,
   1774   // so we don't pass the arguments object.
   1775   var result = %FunctionBindArguments(boundFunction, this,
   1776                                       this_arg, new_length);
   1777 
   1778   // We already have caller and arguments properties on functions,
   1779   // which are non-configurable. It therefore makes no sence to
   1780   // try to redefine these as defined by the spec. The spec says
   1781   // that bind should make these throw a TypeError if get or set
   1782   // is called and make them non-enumerable and non-configurable.
   1783   // To be consistent with our normal functions we leave this as it is.
   1784   // TODO(lrn): Do set these to be thrower.
   1785   return result;
   1786 }
   1787 
   1788 
   1789 function NewFunctionString(arguments, function_token) {
   1790   var n = arguments.length;
   1791   var p = '';
   1792   if (n > 1) {
   1793     p = ToString(arguments[0]);
   1794     for (var i = 1; i < n - 1; i++) {
   1795       p += ',' + ToString(arguments[i]);
   1796     }
   1797     // If the formal parameters string include ) - an illegal
   1798     // character - it may make the combined function expression
   1799     // compile. We avoid this problem by checking for this early on.
   1800     if (%_CallFunction(p, ')', StringIndexOf) != -1) {
   1801       throw MakeSyntaxError('paren_in_arg_string', []);
   1802     }
   1803     // If the formal parameters include an unbalanced block comment, the
   1804     // function must be rejected. Since JavaScript does not allow nested
   1805     // comments we can include a trailing block comment to catch this.
   1806     p += '\n/' + '**/';
   1807   }
   1808   var body = (n > 0) ? ToString(arguments[n - 1]) : '';
   1809   return '(' + function_token + '(' + p + ') {\n' + body + '\n})';
   1810 }
   1811 
   1812 
   1813 function FunctionConstructor(arg1) {  // length == 1
   1814   var source = NewFunctionString(arguments, 'function');
   1815   var global_receiver = %GlobalReceiver(global);
   1816   // Compile the string in the constructor and not a helper so that errors
   1817   // appear to come from here.
   1818   var f = %_CallFunction(global_receiver, %CompileString(source, true));
   1819   %FunctionMarkNameShouldPrintAsAnonymous(f);
   1820   return f;
   1821 }
   1822 
   1823 
   1824 // ----------------------------------------------------------------------------
   1825 
   1826 function SetUpFunction() {
   1827   %CheckIsBootstrapping();
   1828 
   1829   %SetCode($Function, FunctionConstructor);
   1830   %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
   1831 
   1832   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
   1833     "bind", FunctionBind,
   1834     "toString", FunctionToString
   1835   ));
   1836 }
   1837 
   1838 SetUpFunction();
   1839