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