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 //
     36 // in math.js:
     37 // var $floor = MathFloor
     38 
     39 var $isNaN = GlobalIsNaN;
     40 var $isFinite = GlobalIsFinite;
     41 
     42 // ----------------------------------------------------------------------------
     43 
     44 // Helper function used to install functions on objects.
     45 function InstallFunctions(object, attributes, functions) {
     46   if (functions.length >= 8) {
     47     %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
     48   }
     49   for (var i = 0; i < functions.length; i += 2) {
     50     var key = functions[i];
     51     var f = functions[i + 1];
     52     %FunctionSetName(f, key);
     53     %FunctionRemovePrototype(f);
     54     %SetProperty(object, key, f, attributes);
     55     %SetNativeFlag(f);
     56   }
     57   %ToFastProperties(object);
     58 }
     59 
     60 
     61 // Helper function to install a getter-only accessor property.
     62 function InstallGetter(object, name, getter) {
     63   %FunctionSetName(getter, name);
     64   %FunctionRemovePrototype(getter);
     65   %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
     66   %SetNativeFlag(getter);
     67 }
     68 
     69 
     70 // Helper function to install a getter/setter accessor property.
     71 function InstallGetterSetter(object, name, getter, setter) {
     72   %FunctionSetName(getter, name);
     73   %FunctionSetName(setter, name);
     74   %FunctionRemovePrototype(getter);
     75   %FunctionRemovePrototype(setter);
     76   %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
     77   %SetNativeFlag(getter);
     78   %SetNativeFlag(setter);
     79 }
     80 
     81 
     82 // Prevents changes to the prototype of a built-in function.
     83 // The "prototype" property of the function object is made non-configurable,
     84 // and the prototype object is made non-extensible. The latter prevents
     85 // changing the __proto__ property.
     86 function SetUpLockedPrototype(constructor, fields, methods) {
     87   %CheckIsBootstrapping();
     88   var prototype = constructor.prototype;
     89   // Install functions first, because this function is used to initialize
     90   // PropertyDescriptor itself.
     91   var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
     92   if (property_count >= 4) {
     93     %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
     94   }
     95   if (fields) {
     96     for (var i = 0; i < fields.length; i++) {
     97       %SetProperty(prototype, fields[i], UNDEFINED, DONT_ENUM | DONT_DELETE);
     98     }
     99   }
    100   for (var i = 0; i < methods.length; i += 2) {
    101     var key = methods[i];
    102     var f = methods[i + 1];
    103     %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
    104     %SetNativeFlag(f);
    105   }
    106   %SetPrototype(prototype, null);
    107   %ToFastProperties(prototype);
    108 }
    109 
    110 
    111 // ----------------------------------------------------------------------------
    112 
    113 
    114 // ECMA 262 - 15.1.4
    115 function GlobalIsNaN(number) {
    116   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
    117   return NUMBER_IS_NAN(number);
    118 }
    119 
    120 
    121 // ECMA 262 - 15.1.5
    122 function GlobalIsFinite(number) {
    123   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
    124   return NUMBER_IS_FINITE(number);
    125 }
    126 
    127 
    128 // ECMA-262 - 15.1.2.2
    129 function GlobalParseInt(string, radix) {
    130   if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
    131     // Some people use parseInt instead of Math.floor.  This
    132     // optimization makes parseInt on a Smi 12 times faster (60ns
    133     // vs 800ns).  The following optimization makes parseInt on a
    134     // non-Smi number 9 times faster (230ns vs 2070ns).  Together
    135     // they make parseInt on a string 1.4% slower (274ns vs 270ns).
    136     if (%_IsSmi(string)) return string;
    137     if (IS_NUMBER(string) &&
    138         ((0.01 < string && string < 1e9) ||
    139             (-1e9 < string && string < -0.01))) {
    140       // Truncate number.
    141       return string | 0;
    142     }
    143     string = TO_STRING_INLINE(string);
    144     radix = radix | 0;
    145   } else {
    146     // The spec says ToString should be evaluated before ToInt32.
    147     string = TO_STRING_INLINE(string);
    148     radix = TO_INT32(radix);
    149     if (!(radix == 0 || (2 <= radix && radix <= 36))) {
    150       return NAN;
    151     }
    152   }
    153 
    154   if (%_HasCachedArrayIndex(string) &&
    155       (radix == 0 || radix == 10)) {
    156     return %_GetCachedArrayIndex(string);
    157   }
    158   return %StringParseInt(string, radix);
    159 }
    160 
    161 
    162 // ECMA-262 - 15.1.2.3
    163 function GlobalParseFloat(string) {
    164   string = TO_STRING_INLINE(string);
    165   if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
    166   return %StringParseFloat(string);
    167 }
    168 
    169 
    170 function GlobalEval(x) {
    171   if (!IS_STRING(x)) return x;
    172 
    173   // For consistency with JSC we require the global object passed to
    174   // eval to be the global object from which 'eval' originated. This
    175   // is not mandated by the spec.
    176   // We only throw if the global has been detached, since we need the
    177   // receiver as this-value for the call.
    178   if (!%IsAttachedGlobal(global)) {
    179     throw new $EvalError('The "this" value passed to eval must ' +
    180                          'be the global object from which eval originated');
    181   }
    182 
    183   var global_receiver = %GlobalReceiver(global);
    184 
    185   var f = %CompileString(x, false);
    186   if (!IS_FUNCTION(f)) return f;
    187 
    188   return %_CallFunction(global_receiver, f);
    189 }
    190 
    191 
    192 // ----------------------------------------------------------------------------
    193 
    194 // Set up global object.
    195 function SetUpGlobal() {
    196   %CheckIsBootstrapping();
    197 
    198   var attributes = DONT_ENUM | DONT_DELETE | READ_ONLY;
    199 
    200   // ECMA 262 - 15.1.1.1.
    201   %SetProperty(global, "NaN", NAN, attributes);
    202 
    203   // ECMA-262 - 15.1.1.2.
    204   %SetProperty(global, "Infinity", INFINITY, attributes);
    205 
    206   // ECMA-262 - 15.1.1.3.
    207   %SetProperty(global, "undefined", UNDEFINED, attributes);
    208 
    209   // Set up non-enumerable function on the global object.
    210   InstallFunctions(global, DONT_ENUM, $Array(
    211     "isNaN", GlobalIsNaN,
    212     "isFinite", GlobalIsFinite,
    213     "parseInt", GlobalParseInt,
    214     "parseFloat", GlobalParseFloat,
    215     "eval", GlobalEval
    216   ));
    217 }
    218 
    219 SetUpGlobal();
    220 
    221 
    222 // ----------------------------------------------------------------------------
    223 // Object
    224 
    225 // ECMA-262 - 15.2.4.2
    226 function ObjectToString() {
    227   if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
    228   if (IS_NULL(this)) return "[object Null]";
    229   return "[object " + %_ClassOf(ToObject(this)) + "]";
    230 }
    231 
    232 
    233 // ECMA-262 - 15.2.4.3
    234 function ObjectToLocaleString() {
    235   if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    236     throw MakeTypeError("called_on_null_or_undefined",
    237                         ["Object.prototype.toLocaleString"]);
    238   }
    239   return this.toString();
    240 }
    241 
    242 
    243 // ECMA-262 - 15.2.4.4
    244 function ObjectValueOf() {
    245   return ToObject(this);
    246 }
    247 
    248 
    249 // ECMA-262 - 15.2.4.5
    250 function ObjectHasOwnProperty(V) {
    251   if (%IsJSProxy(this)) {
    252     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    253     if (IS_SYMBOL(V)) return false;
    254 
    255     var handler = %GetHandler(this);
    256     return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
    257   }
    258   return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
    259 }
    260 
    261 
    262 // ECMA-262 - 15.2.4.6
    263 function ObjectIsPrototypeOf(V) {
    264   if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    265     throw MakeTypeError("called_on_null_or_undefined",
    266                         ["Object.prototype.isPrototypeOf"]);
    267   }
    268   if (!IS_SPEC_OBJECT(V)) return false;
    269   return %IsInPrototypeChain(this, V);
    270 }
    271 
    272 
    273 // ECMA-262 - 15.2.4.6
    274 function ObjectPropertyIsEnumerable(V) {
    275   var P = ToName(V);
    276   if (%IsJSProxy(this)) {
    277     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    278     if (IS_SYMBOL(V)) return false;
    279 
    280     var desc = GetOwnProperty(this, P);
    281     return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
    282   }
    283   return %IsPropertyEnumerable(ToObject(this), P);
    284 }
    285 
    286 
    287 // Extensions for providing property getters and setters.
    288 function ObjectDefineGetter(name, fun) {
    289   var receiver = this;
    290   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    291     receiver = %GlobalReceiver(global);
    292   }
    293   if (!IS_SPEC_FUNCTION(fun)) {
    294     throw new $TypeError(
    295         'Object.prototype.__defineGetter__: Expecting function');
    296   }
    297   var desc = new PropertyDescriptor();
    298   desc.setGet(fun);
    299   desc.setEnumerable(true);
    300   desc.setConfigurable(true);
    301   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
    302 }
    303 
    304 
    305 function ObjectLookupGetter(name) {
    306   var receiver = this;
    307   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    308     receiver = %GlobalReceiver(global);
    309   }
    310   return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
    311 }
    312 
    313 
    314 function ObjectDefineSetter(name, fun) {
    315   var receiver = this;
    316   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    317     receiver = %GlobalReceiver(global);
    318   }
    319   if (!IS_SPEC_FUNCTION(fun)) {
    320     throw new $TypeError(
    321         'Object.prototype.__defineSetter__: Expecting function');
    322   }
    323   var desc = new PropertyDescriptor();
    324   desc.setSet(fun);
    325   desc.setEnumerable(true);
    326   desc.setConfigurable(true);
    327   DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
    328 }
    329 
    330 
    331 function ObjectLookupSetter(name) {
    332   var receiver = this;
    333   if (receiver == null && !IS_UNDETECTABLE(receiver)) {
    334     receiver = %GlobalReceiver(global);
    335   }
    336   return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
    337 }
    338 
    339 
    340 function ObjectKeys(obj) {
    341   if (!IS_SPEC_OBJECT(obj)) {
    342     throw MakeTypeError("called_on_non_object", ["Object.keys"]);
    343   }
    344   if (%IsJSProxy(obj)) {
    345     var handler = %GetHandler(obj);
    346     var names = CallTrap0(handler, "keys", DerivedKeysTrap);
    347     return ToNameArray(names, "keys", false);
    348   }
    349   return %LocalKeys(obj);
    350 }
    351 
    352 
    353 // ES5 8.10.1.
    354 function IsAccessorDescriptor(desc) {
    355   if (IS_UNDEFINED(desc)) return false;
    356   return desc.hasGetter() || desc.hasSetter();
    357 }
    358 
    359 
    360 // ES5 8.10.2.
    361 function IsDataDescriptor(desc) {
    362   if (IS_UNDEFINED(desc)) return false;
    363   return desc.hasValue() || desc.hasWritable();
    364 }
    365 
    366 
    367 // ES5 8.10.3.
    368 function IsGenericDescriptor(desc) {
    369   if (IS_UNDEFINED(desc)) return false;
    370   return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
    371 }
    372 
    373 
    374 function IsInconsistentDescriptor(desc) {
    375   return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
    376 }
    377 
    378 
    379 // ES5 8.10.4
    380 function FromPropertyDescriptor(desc) {
    381   if (IS_UNDEFINED(desc)) return desc;
    382 
    383   if (IsDataDescriptor(desc)) {
    384     return { value: desc.getValue(),
    385              writable: desc.isWritable(),
    386              enumerable: desc.isEnumerable(),
    387              configurable: desc.isConfigurable() };
    388   }
    389   // Must be an AccessorDescriptor then. We never return a generic descriptor.
    390   return { get: desc.getGet(),
    391            set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
    392                                                  : desc.getSet(),
    393            enumerable: desc.isEnumerable(),
    394            configurable: desc.isConfigurable() };
    395 }
    396 
    397 
    398 // Harmony Proxies
    399 function FromGenericPropertyDescriptor(desc) {
    400   if (IS_UNDEFINED(desc)) return desc;
    401   var obj = new $Object();
    402 
    403   if (desc.hasValue()) {
    404     %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
    405   }
    406   if (desc.hasWritable()) {
    407     %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
    408   }
    409   if (desc.hasGetter()) {
    410     %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
    411   }
    412   if (desc.hasSetter()) {
    413     %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
    414   }
    415   if (desc.hasEnumerable()) {
    416     %IgnoreAttributesAndSetProperty(obj, "enumerable",
    417                                     desc.isEnumerable(), NONE);
    418   }
    419   if (desc.hasConfigurable()) {
    420     %IgnoreAttributesAndSetProperty(obj, "configurable",
    421                                     desc.isConfigurable(), NONE);
    422   }
    423   return obj;
    424 }
    425 
    426 
    427 // ES5 8.10.5.
    428 function ToPropertyDescriptor(obj) {
    429   if (!IS_SPEC_OBJECT(obj)) {
    430     throw MakeTypeError("property_desc_object", [obj]);
    431   }
    432   var desc = new PropertyDescriptor();
    433 
    434   if ("enumerable" in obj) {
    435     desc.setEnumerable(ToBoolean(obj.enumerable));
    436   }
    437 
    438   if ("configurable" in obj) {
    439     desc.setConfigurable(ToBoolean(obj.configurable));
    440   }
    441 
    442   if ("value" in obj) {
    443     desc.setValue(obj.value);
    444   }
    445 
    446   if ("writable" in obj) {
    447     desc.setWritable(ToBoolean(obj.writable));
    448   }
    449 
    450   if ("get" in obj) {
    451     var get = obj.get;
    452     if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
    453       throw MakeTypeError("getter_must_be_callable", [get]);
    454     }
    455     desc.setGet(get);
    456   }
    457 
    458   if ("set" in obj) {
    459     var set = obj.set;
    460     if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
    461       throw MakeTypeError("setter_must_be_callable", [set]);
    462     }
    463     desc.setSet(set);
    464   }
    465 
    466   if (IsInconsistentDescriptor(desc)) {
    467     throw MakeTypeError("value_and_accessor", [obj]);
    468   }
    469   return desc;
    470 }
    471 
    472 
    473 // For Harmony proxies.
    474 function ToCompletePropertyDescriptor(obj) {
    475   var desc = ToPropertyDescriptor(obj);
    476   if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
    477     if (!desc.hasValue()) desc.setValue(UNDEFINED);
    478     if (!desc.hasWritable()) desc.setWritable(false);
    479   } else {
    480     // Is accessor descriptor.
    481     if (!desc.hasGetter()) desc.setGet(UNDEFINED);
    482     if (!desc.hasSetter()) desc.setSet(UNDEFINED);
    483   }
    484   if (!desc.hasEnumerable()) desc.setEnumerable(false);
    485   if (!desc.hasConfigurable()) desc.setConfigurable(false);
    486   return desc;
    487 }
    488 
    489 
    490 function PropertyDescriptor() {
    491   // Initialize here so they are all in-object and have the same map.
    492   // Default values from ES5 8.6.1.
    493   this.value_ = UNDEFINED;
    494   this.hasValue_ = false;
    495   this.writable_ = false;
    496   this.hasWritable_ = false;
    497   this.enumerable_ = false;
    498   this.hasEnumerable_ = false;
    499   this.configurable_ = false;
    500   this.hasConfigurable_ = false;
    501   this.get_ = UNDEFINED;
    502   this.hasGetter_ = false;
    503   this.set_ = UNDEFINED;
    504   this.hasSetter_ = false;
    505 }
    506 
    507 SetUpLockedPrototype(PropertyDescriptor, $Array(
    508     "value_",
    509     "hasValue_",
    510     "writable_",
    511     "hasWritable_",
    512     "enumerable_",
    513     "hasEnumerable_",
    514     "configurable_",
    515     "hasConfigurable_",
    516     "get_",
    517     "hasGetter_",
    518     "set_",
    519     "hasSetter_"
    520   ), $Array(
    521     "toString", function() {
    522       return "[object PropertyDescriptor]";
    523     },
    524     "setValue", function(value) {
    525       this.value_ = value;
    526       this.hasValue_ = true;
    527     },
    528     "getValue", function() {
    529       return this.value_;
    530     },
    531     "hasValue", function() {
    532       return this.hasValue_;
    533     },
    534     "setEnumerable", function(enumerable) {
    535       this.enumerable_ = enumerable;
    536         this.hasEnumerable_ = true;
    537     },
    538     "isEnumerable", function () {
    539       return this.enumerable_;
    540     },
    541     "hasEnumerable", function() {
    542       return this.hasEnumerable_;
    543     },
    544     "setWritable", function(writable) {
    545       this.writable_ = writable;
    546       this.hasWritable_ = true;
    547     },
    548     "isWritable", function() {
    549       return this.writable_;
    550     },
    551     "hasWritable", function() {
    552       return this.hasWritable_;
    553     },
    554     "setConfigurable", function(configurable) {
    555       this.configurable_ = configurable;
    556       this.hasConfigurable_ = true;
    557     },
    558     "hasConfigurable", function() {
    559       return this.hasConfigurable_;
    560     },
    561     "isConfigurable", function() {
    562       return this.configurable_;
    563     },
    564     "setGet", function(get) {
    565       this.get_ = get;
    566         this.hasGetter_ = true;
    567     },
    568     "getGet", function() {
    569       return this.get_;
    570     },
    571     "hasGetter", function() {
    572       return this.hasGetter_;
    573     },
    574     "setSet", function(set) {
    575       this.set_ = set;
    576       this.hasSetter_ = true;
    577     },
    578     "getSet", function() {
    579       return this.set_;
    580     },
    581     "hasSetter", function() {
    582       return this.hasSetter_;
    583   }));
    584 
    585 
    586 // Converts an array returned from Runtime_GetOwnProperty to an actual
    587 // property descriptor. For a description of the array layout please
    588 // see the runtime.cc file.
    589 function ConvertDescriptorArrayToDescriptor(desc_array) {
    590   if (desc_array === false) {
    591     throw 'Internal error: invalid desc_array';
    592   }
    593 
    594   if (IS_UNDEFINED(desc_array)) {
    595     return UNDEFINED;
    596   }
    597 
    598   var desc = new PropertyDescriptor();
    599   // This is an accessor.
    600   if (desc_array[IS_ACCESSOR_INDEX]) {
    601     desc.setGet(desc_array[GETTER_INDEX]);
    602     desc.setSet(desc_array[SETTER_INDEX]);
    603   } else {
    604     desc.setValue(desc_array[VALUE_INDEX]);
    605     desc.setWritable(desc_array[WRITABLE_INDEX]);
    606   }
    607   desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
    608   desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
    609 
    610   return desc;
    611 }
    612 
    613 
    614 // For Harmony proxies.
    615 function GetTrap(handler, name, defaultTrap) {
    616   var trap = handler[name];
    617   if (IS_UNDEFINED(trap)) {
    618     if (IS_UNDEFINED(defaultTrap)) {
    619       throw MakeTypeError("handler_trap_missing", [handler, name]);
    620     }
    621     trap = defaultTrap;
    622   } else if (!IS_SPEC_FUNCTION(trap)) {
    623     throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
    624   }
    625   return trap;
    626 }
    627 
    628 
    629 function CallTrap0(handler, name, defaultTrap) {
    630   return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
    631 }
    632 
    633 
    634 function CallTrap1(handler, name, defaultTrap, x) {
    635   return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
    636 }
    637 
    638 
    639 function CallTrap2(handler, name, defaultTrap, x, y) {
    640   return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
    641 }
    642 
    643 
    644 // ES5 section 8.12.1.
    645 function GetOwnProperty(obj, v) {
    646   var p = ToName(v);
    647   if (%IsJSProxy(obj)) {
    648     // TODO(rossberg): adjust once there is a story for symbols vs proxies.
    649     if (IS_SYMBOL(v)) return UNDEFINED;
    650 
    651     var handler = %GetHandler(obj);
    652     var descriptor = CallTrap1(
    653                          handler, "getOwnPropertyDescriptor", UNDEFINED, 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 UNDEFINED;
    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", UNDEFINED, 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 UNDEFINED;
    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 = UNDEFINED;  // 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_ = UNDEFINED;
    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", UNDEFINED);
   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", UNDEFINED);
   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) || %IsObserved(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 == INFINITY) return "Infinity";
   1564   if (x == -INFINITY) 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) ? UNDEFINED : TO_INTEGER(fractionDigits);
   1582 
   1583   if (NUMBER_IS_NAN(x)) return "NaN";
   1584   if (x == INFINITY) return "Infinity";
   1585   if (x == -INFINITY) 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 == INFINITY) return "Infinity";
   1612   if (x == -INFINITY) 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                -INFINITY,
   1663                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1664 
   1665   // ECMA-262 section 15.7.3.5.
   1666   %SetProperty($Number,
   1667                "POSITIVE_INFINITY",
   1668                INFINITY,
   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 
   1840 
   1841 //----------------------------------------------------------------------------
   1842 
   1843 // TODO(rossberg): very simple abstraction for generic microtask queue.
   1844 // Eventually, we should move to a real event queue that allows to maintain
   1845 // relative ordering of different kinds of tasks.
   1846 
   1847 RunMicrotasks.runners = new InternalArray;
   1848 
   1849 function RunMicrotasks() {
   1850   while (%SetMicrotaskPending(false)) {
   1851     for (var i in RunMicrotasks.runners) RunMicrotasks.runners[i]();
   1852   }
   1853 }
   1854