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