Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 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 // const $Object = global.Object;
     32 // const $Boolean = global.Boolean;
     33 // const $Number = global.Number;
     34 // const $Function = global.Function;
     35 // const $Array = global.Array;
     36 // const $NaN = 0/0;
     37 //
     38 // in math.js:
     39 // const $floor = MathFloor
     40 
     41 const $isNaN = GlobalIsNaN;
     42 const $isFinite = GlobalIsFinite;
     43 
     44 
     45 // ----------------------------------------------------------------------------
     46 
     47 
     48 // Helper function used to install functions on objects.
     49 function InstallFunctions(object, attributes, functions) {
     50   if (functions.length >= 8) {
     51     %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
     52   }
     53   for (var i = 0; i < functions.length; i += 2) {
     54     var key = functions[i];
     55     var f = functions[i + 1];
     56     %FunctionSetName(f, key);
     57     %FunctionRemovePrototype(f);
     58     %SetProperty(object, key, f, attributes);
     59   }
     60   %ToFastProperties(object);
     61 }
     62 
     63 // Emulates JSC by installing functions on a hidden prototype that
     64 // lies above the current object/prototype.  This lets you override
     65 // functions on String.prototype etc. and then restore the old function
     66 // with delete.  See http://code.google.com/p/chromium/issues/detail?id=1717
     67 function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
     68   var hidden_prototype = new $Object();
     69   %SetHiddenPrototype(object, hidden_prototype);
     70   InstallFunctions(hidden_prototype, attributes, functions);
     71 }
     72 
     73 
     74 // ----------------------------------------------------------------------------
     75 
     76 
     77 // ECMA 262 - 15.1.4
     78 function GlobalIsNaN(number) {
     79   var n = ToNumber(number);
     80   return NUMBER_IS_NAN(n);
     81 }
     82 
     83 
     84 // ECMA 262 - 15.1.5
     85 function GlobalIsFinite(number) {
     86   if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
     87 
     88   // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
     89   return %_IsSmi(number) || number - number == 0;
     90 }
     91 
     92 
     93 // ECMA-262 - 15.1.2.2
     94 function GlobalParseInt(string, radix) {
     95   if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
     96     // Some people use parseInt instead of Math.floor.  This
     97     // optimization makes parseInt on a Smi 12 times faster (60ns
     98     // vs 800ns).  The following optimization makes parseInt on a
     99     // non-Smi number 9 times faster (230ns vs 2070ns).  Together
    100     // they make parseInt on a string 1.4% slower (274ns vs 270ns).
    101     if (%_IsSmi(string)) return string;
    102     if (IS_NUMBER(string) &&
    103         ((0.01 < string && string < 1e9) ||
    104             (-1e9 < string && string < -0.01))) {
    105       // Truncate number.
    106       return string | 0;
    107     }
    108     if (IS_UNDEFINED(radix)) radix = 0;
    109   } else {
    110     radix = TO_INT32(radix);
    111     if (!(radix == 0 || (2 <= radix && radix <= 36)))
    112       return $NaN;
    113   }
    114   string = TO_STRING_INLINE(string);
    115   if (%_HasCachedArrayIndex(string) &&
    116       (radix == 0 || radix == 10)) {
    117     return %_GetCachedArrayIndex(string);
    118   }
    119   return %StringParseInt(string, radix);
    120 }
    121 
    122 
    123 // ECMA-262 - 15.1.2.3
    124 function GlobalParseFloat(string) {
    125   string = TO_STRING_INLINE(string);
    126   if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
    127   return %StringParseFloat(string);
    128 }
    129 
    130 
    131 function GlobalEval(x) {
    132   if (!IS_STRING(x)) return x;
    133 
    134   var global_receiver = %GlobalReceiver(global);
    135   var this_is_global_receiver = (this === global_receiver);
    136   var global_is_detached = (global === global_receiver);
    137 
    138   if (!this_is_global_receiver || global_is_detached) {
    139     throw new $EvalError('The "this" object passed to eval must ' +
    140                          'be the global object from which eval originated');
    141   }
    142 
    143   var f = %CompileString(x);
    144   if (!IS_FUNCTION(f)) return f;
    145 
    146   return %_CallFunction(this, f);
    147 }
    148 
    149 
    150 // ----------------------------------------------------------------------------
    151 
    152 
    153 function SetupGlobal() {
    154   // ECMA 262 - 15.1.1.1.
    155   %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
    156 
    157   // ECMA-262 - 15.1.1.2.
    158   %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
    159 
    160   // ECMA-262 - 15.1.1.3.
    161   %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
    162 
    163   // Setup non-enumerable function on the global object.
    164   InstallFunctions(global, DONT_ENUM, $Array(
    165     "isNaN", GlobalIsNaN,
    166     "isFinite", GlobalIsFinite,
    167     "parseInt", GlobalParseInt,
    168     "parseFloat", GlobalParseFloat,
    169     "eval", GlobalEval
    170   ));
    171 }
    172 
    173 SetupGlobal();
    174 
    175 
    176 // ----------------------------------------------------------------------------
    177 // Boolean (first part of definition)
    178 
    179 
    180 %SetCode($Boolean, function(x) {
    181   if (%_IsConstructCall()) {
    182     %_SetValueOf(this, ToBoolean(x));
    183   } else {
    184     return ToBoolean(x);
    185   }
    186 });
    187 
    188 %FunctionSetPrototype($Boolean, new $Boolean(false));
    189 
    190 %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
    191 
    192 // ----------------------------------------------------------------------------
    193 // Object
    194 
    195 $Object.prototype.constructor = $Object;
    196 
    197 // ECMA-262 - 15.2.4.2
    198 function ObjectToString() {
    199   return "[object " + %_ClassOf(ToObject(this)) + "]";
    200 }
    201 
    202 
    203 // ECMA-262 - 15.2.4.3
    204 function ObjectToLocaleString() {
    205   return this.toString();
    206 }
    207 
    208 
    209 // ECMA-262 - 15.2.4.4
    210 function ObjectValueOf() {
    211   return ToObject(this);
    212 }
    213 
    214 
    215 // ECMA-262 - 15.2.4.5
    216 function ObjectHasOwnProperty(V) {
    217   return %HasLocalProperty(ToObject(this), ToString(V));
    218 }
    219 
    220 
    221 // ECMA-262 - 15.2.4.6
    222 function ObjectIsPrototypeOf(V) {
    223   if (!IS_SPEC_OBJECT(V)) return false;
    224   return %IsInPrototypeChain(this, V);
    225 }
    226 
    227 
    228 // ECMA-262 - 15.2.4.6
    229 function ObjectPropertyIsEnumerable(V) {
    230   return %IsPropertyEnumerable(ToObject(this), ToString(V));
    231 }
    232 
    233 
    234 // Extensions for providing property getters and setters.
    235 function ObjectDefineGetter(name, fun) {
    236   if (this == null && !IS_UNDETECTABLE(this)) {
    237     throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
    238   }
    239   if (!IS_FUNCTION(fun)) {
    240     throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
    241   }
    242   var desc = new PropertyDescriptor();
    243   desc.setGet(fun);
    244   desc.setEnumerable(true);
    245   desc.setConfigurable(true);
    246   DefineOwnProperty(ToObject(this), ToString(name), desc, false);
    247 }
    248 
    249 
    250 function ObjectLookupGetter(name) {
    251   if (this == null && !IS_UNDETECTABLE(this)) {
    252     throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
    253   }
    254   return %LookupAccessor(ToObject(this), ToString(name), GETTER);
    255 }
    256 
    257 
    258 function ObjectDefineSetter(name, fun) {
    259   if (this == null && !IS_UNDETECTABLE(this)) {
    260     throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
    261   }
    262   if (!IS_FUNCTION(fun)) {
    263     throw new $TypeError(
    264         'Object.prototype.__defineSetter__: Expecting function');
    265   }
    266   var desc = new PropertyDescriptor();
    267   desc.setSet(fun);
    268   desc.setEnumerable(true);
    269   desc.setConfigurable(true);
    270   DefineOwnProperty(ToObject(this), ToString(name), desc, false);
    271 }
    272 
    273 
    274 function ObjectLookupSetter(name) {
    275   if (this == null && !IS_UNDETECTABLE(this)) {
    276     throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
    277   }
    278   return %LookupAccessor(ToObject(this), ToString(name), SETTER);
    279 }
    280 
    281 
    282 function ObjectKeys(obj) {
    283   if (!IS_SPEC_OBJECT(obj))
    284     throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
    285   return %LocalKeys(obj);
    286 }
    287 
    288 
    289 // ES5 8.10.1.
    290 function IsAccessorDescriptor(desc) {
    291   if (IS_UNDEFINED(desc)) return false;
    292   return desc.hasGetter_ || desc.hasSetter_;
    293 }
    294 
    295 
    296 // ES5 8.10.2.
    297 function IsDataDescriptor(desc) {
    298   if (IS_UNDEFINED(desc)) return false;
    299   return desc.hasValue_ || desc.hasWritable_;
    300 }
    301 
    302 
    303 // ES5 8.10.3.
    304 function IsGenericDescriptor(desc) {
    305   return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
    306 }
    307 
    308 
    309 function IsInconsistentDescriptor(desc) {
    310   return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
    311 }
    312 
    313 // ES5 8.10.4
    314 function FromPropertyDescriptor(desc) {
    315   if (IS_UNDEFINED(desc)) return desc;
    316   var obj = new $Object();
    317   if (IsDataDescriptor(desc)) {
    318     obj.value = desc.getValue();
    319     obj.writable = desc.isWritable();
    320   }
    321   if (IsAccessorDescriptor(desc)) {
    322     obj.get = desc.getGet();
    323     obj.set = desc.getSet();
    324   }
    325   obj.enumerable = desc.isEnumerable();
    326   obj.configurable = desc.isConfigurable();
    327   return obj;
    328 }
    329 
    330 // ES5 8.10.5.
    331 function ToPropertyDescriptor(obj) {
    332   if (!IS_SPEC_OBJECT(obj)) {
    333     throw MakeTypeError("property_desc_object", [obj]);
    334   }
    335   var desc = new PropertyDescriptor();
    336 
    337   if ("enumerable" in obj) {
    338     desc.setEnumerable(ToBoolean(obj.enumerable));
    339   }
    340 
    341   if ("configurable" in obj) {
    342     desc.setConfigurable(ToBoolean(obj.configurable));
    343   }
    344 
    345   if ("value" in obj) {
    346     desc.setValue(obj.value);
    347   }
    348 
    349   if ("writable" in obj) {
    350     desc.setWritable(ToBoolean(obj.writable));
    351   }
    352 
    353   if ("get" in obj) {
    354     var get = obj.get;
    355     if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
    356       throw MakeTypeError("getter_must_be_callable", [get]);
    357     }
    358     desc.setGet(get);
    359   }
    360 
    361   if ("set" in obj) {
    362     var set = obj.set;
    363     if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
    364       throw MakeTypeError("setter_must_be_callable", [set]);
    365     }
    366     desc.setSet(set);
    367   }
    368 
    369   if (IsInconsistentDescriptor(desc)) {
    370     throw MakeTypeError("value_and_accessor", [obj]);
    371   }
    372   return desc;
    373 }
    374 
    375 
    376 function PropertyDescriptor() {
    377   // Initialize here so they are all in-object and have the same map.
    378   // Default values from ES5 8.6.1.
    379   this.value_ = void 0;
    380   this.hasValue_ = false;
    381   this.writable_ = false;
    382   this.hasWritable_ = false;
    383   this.enumerable_ = false;
    384   this.hasEnumerable_ = false;
    385   this.configurable_ = false;
    386   this.hasConfigurable_ = false;
    387   this.get_ = void 0;
    388   this.hasGetter_ = false;
    389   this.set_ = void 0;
    390   this.hasSetter_ = false;
    391 }
    392 
    393 PropertyDescriptor.prototype.__proto__ = null;
    394 PropertyDescriptor.prototype.toString = function() {
    395   return "[object PropertyDescriptor]";
    396 };
    397 
    398 PropertyDescriptor.prototype.setValue = function(value) {
    399   this.value_ = value;
    400   this.hasValue_ = true;
    401 }
    402 
    403 
    404 PropertyDescriptor.prototype.getValue = function() {
    405   return this.value_;
    406 }
    407 
    408 
    409 PropertyDescriptor.prototype.hasValue = function() {
    410   return this.hasValue_;
    411 }
    412 
    413 
    414 PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
    415   this.enumerable_ = enumerable;
    416   this.hasEnumerable_ = true;
    417 }
    418 
    419 
    420 PropertyDescriptor.prototype.isEnumerable = function () {
    421   return this.enumerable_;
    422 }
    423 
    424 
    425 PropertyDescriptor.prototype.hasEnumerable = function() {
    426   return this.hasEnumerable_;
    427 }
    428 
    429 
    430 PropertyDescriptor.prototype.setWritable = function(writable) {
    431   this.writable_ = writable;
    432   this.hasWritable_ = true;
    433 }
    434 
    435 
    436 PropertyDescriptor.prototype.isWritable = function() {
    437   return this.writable_;
    438 }
    439 
    440 
    441 PropertyDescriptor.prototype.hasWritable = function() {
    442   return this.hasWritable_;
    443 }
    444 
    445 
    446 PropertyDescriptor.prototype.setConfigurable = function(configurable) {
    447   this.configurable_ = configurable;
    448   this.hasConfigurable_ = true;
    449 }
    450 
    451 
    452 PropertyDescriptor.prototype.hasConfigurable = function() {
    453   return this.hasConfigurable_;
    454 }
    455 
    456 
    457 PropertyDescriptor.prototype.isConfigurable = function() {
    458   return this.configurable_;
    459 }
    460 
    461 
    462 PropertyDescriptor.prototype.setGet = function(get) {
    463   this.get_ = get;
    464   this.hasGetter_ = true;
    465 }
    466 
    467 
    468 PropertyDescriptor.prototype.getGet = function() {
    469   return this.get_;
    470 }
    471 
    472 
    473 PropertyDescriptor.prototype.hasGetter = function() {
    474   return this.hasGetter_;
    475 }
    476 
    477 
    478 PropertyDescriptor.prototype.setSet = function(set) {
    479   this.set_ = set;
    480   this.hasSetter_ = true;
    481 }
    482 
    483 
    484 PropertyDescriptor.prototype.getSet = function() {
    485   return this.set_;
    486 }
    487 
    488 
    489 PropertyDescriptor.prototype.hasSetter = function() {
    490   return this.hasSetter_;
    491 }
    492 
    493 
    494 // Converts an array returned from Runtime_GetOwnProperty to an actual
    495 // property descriptor. For a description of the array layout please
    496 // see the runtime.cc file.
    497 function ConvertDescriptorArrayToDescriptor(desc_array) {
    498   if (desc_array === false) {
    499     throw 'Internal error: invalid desc_array';
    500   }
    501 
    502   if (IS_UNDEFINED(desc_array)) {
    503     return void 0;
    504   }
    505 
    506   var desc = new PropertyDescriptor();
    507   // This is an accessor.
    508   if (desc_array[IS_ACCESSOR_INDEX]) {
    509     desc.setGet(desc_array[GETTER_INDEX]);
    510     desc.setSet(desc_array[SETTER_INDEX]);
    511   } else {
    512     desc.setValue(desc_array[VALUE_INDEX]);
    513     desc.setWritable(desc_array[WRITABLE_INDEX]);
    514   }
    515   desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
    516   desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
    517 
    518   return desc;
    519 }
    520 
    521 
    522 // ES5 section 8.12.2.
    523 function GetProperty(obj, p) {
    524   var prop = GetOwnProperty(obj);
    525   if (!IS_UNDEFINED(prop)) return prop;
    526   var proto = obj.__proto__;
    527   if (IS_NULL(proto)) return void 0;
    528   return GetProperty(proto, p);
    529 }
    530 
    531 
    532 // ES5 section 8.12.6
    533 function HasProperty(obj, p) {
    534   var desc = GetProperty(obj, p);
    535   return IS_UNDEFINED(desc) ? false : true;
    536 }
    537 
    538 
    539 // ES5 section 8.12.1.
    540 function GetOwnProperty(obj, p) {
    541   // GetOwnProperty returns an array indexed by the constants
    542   // defined in macros.py.
    543   // If p is not a property on obj undefined is returned.
    544   var props = %GetOwnProperty(ToObject(obj), ToString(p));
    545 
    546   // A false value here means that access checks failed.
    547   if (props === false) return void 0;
    548 
    549   return ConvertDescriptorArrayToDescriptor(props);
    550 }
    551 
    552 
    553 // ES5 8.12.9.
    554 function DefineOwnProperty(obj, p, desc, should_throw) {
    555   var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
    556   // A false value here means that access checks failed.
    557   if (current_or_access === false) return void 0;
    558 
    559   var current = ConvertDescriptorArrayToDescriptor(current_or_access);
    560   var extensible = %IsExtensible(ToObject(obj));
    561 
    562   // Error handling according to spec.
    563   // Step 3
    564   if (IS_UNDEFINED(current) && !extensible) {
    565     if (should_throw) {
    566       throw MakeTypeError("define_disallowed", ["defineProperty"]);
    567     } else {
    568       return;
    569     }
    570   }
    571 
    572   if (!IS_UNDEFINED(current)) {
    573     // Step 5 and 6
    574     if ((IsGenericDescriptor(desc) ||
    575          IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
    576         (!desc.hasEnumerable() ||
    577          SameValue(desc.isEnumerable(), current.isEnumerable())) &&
    578         (!desc.hasConfigurable() ||
    579          SameValue(desc.isConfigurable(), current.isConfigurable())) &&
    580         (!desc.hasWritable() ||
    581          SameValue(desc.isWritable(), current.isWritable())) &&
    582         (!desc.hasValue() ||
    583          SameValue(desc.getValue(), current.getValue())) &&
    584         (!desc.hasGetter() ||
    585          SameValue(desc.getGet(), current.getGet())) &&
    586         (!desc.hasSetter() ||
    587          SameValue(desc.getSet(), current.getSet()))) {
    588       return true;
    589     }
    590     if (!current.isConfigurable()) {
    591       // Step 7
    592       if (desc.isConfigurable() ||
    593           (desc.hasEnumerable() &&
    594            desc.isEnumerable() != current.isEnumerable())) {
    595         if (should_throw) {
    596           throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    597         } else {
    598           return;
    599         }
    600       }
    601       // Step 8
    602       if (!IsGenericDescriptor(desc)) {
    603         // Step 9a
    604         if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
    605           if (should_throw) {
    606             throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    607           } else {
    608             return;
    609           }
    610         }
    611         // Step 10a
    612         if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
    613           if (!current.isWritable() && desc.isWritable()) {
    614             if (should_throw) {
    615               throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    616             } else {
    617               return;
    618             }
    619           }
    620           if (!current.isWritable() && desc.hasValue() &&
    621               !SameValue(desc.getValue(), current.getValue())) {
    622             if (should_throw) {
    623               throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    624             } else {
    625               return;
    626             }
    627           }
    628         }
    629         // Step 11
    630         if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
    631           if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
    632             if (should_throw) {
    633               throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    634             } else {
    635               return;
    636             }
    637           }
    638           if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
    639             if (should_throw) {
    640               throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
    641             } else {
    642               return;
    643             }
    644           }
    645         }
    646       }
    647     }
    648   }
    649 
    650   // Send flags - enumerable and configurable are common - writable is
    651   // only send to the data descriptor.
    652   // Take special care if enumerable and configurable is not defined on
    653   // desc (we need to preserve the existing values from current).
    654   var flag = NONE;
    655   if (desc.hasEnumerable()) {
    656     flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
    657   } else if (!IS_UNDEFINED(current)) {
    658     flag |= current.isEnumerable() ? 0 : DONT_ENUM;
    659   } else {
    660     flag |= DONT_ENUM;
    661   }
    662 
    663   if (desc.hasConfigurable()) {
    664     flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
    665   } else if (!IS_UNDEFINED(current)) {
    666     flag |= current.isConfigurable() ? 0 : DONT_DELETE;
    667   } else
    668     flag |= DONT_DELETE;
    669 
    670   if (IsDataDescriptor(desc) ||
    671       (IsGenericDescriptor(desc) &&
    672        (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
    673     // There are 3 cases that lead here:
    674     // Step 4a - defining a new data property.
    675     // Steps 9b & 12 - replacing an existing accessor property with a data
    676     //                 property.
    677     // Step 12 - updating an existing data property with a data or generic
    678     //           descriptor.
    679 
    680     if (desc.hasWritable()) {
    681       flag |= desc.isWritable() ? 0 : READ_ONLY;
    682     } else if (!IS_UNDEFINED(current)) {
    683       flag |= current.isWritable() ? 0 : READ_ONLY;
    684     } else {
    685       flag |= READ_ONLY;
    686     }
    687 
    688     var value = void 0;  // Default value is undefined.
    689     if (desc.hasValue()) {
    690       value = desc.getValue();
    691     } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
    692       value = current.getValue();
    693     }
    694 
    695     %DefineOrRedefineDataProperty(obj, p, value, flag);
    696   } else if (IsGenericDescriptor(desc)) {
    697     // Step 12 - updating an existing accessor property with generic
    698     //           descriptor. Changing flags only.
    699     %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
    700   } else {
    701     // There are 3 cases that lead here:
    702     // Step 4b - defining a new accessor property.
    703     // Steps 9c & 12 - replacing an existing data property with an accessor
    704     //                 property.
    705     // Step 12 - updating an existing accessor property with an accessor
    706     //           descriptor.
    707     if (desc.hasGetter()) {
    708       %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
    709     }
    710     if (desc.hasSetter()) {
    711       %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
    712     }
    713   }
    714   return true;
    715 }
    716 
    717 
    718 // ES5 section 15.2.3.2.
    719 function ObjectGetPrototypeOf(obj) {
    720   if (!IS_SPEC_OBJECT(obj))
    721     throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
    722   return obj.__proto__;
    723 }
    724 
    725 
    726 // ES5 section 15.2.3.3
    727 function ObjectGetOwnPropertyDescriptor(obj, p) {
    728   if (!IS_SPEC_OBJECT(obj))
    729     throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]);
    730   var desc = GetOwnProperty(obj, p);
    731   return FromPropertyDescriptor(desc);
    732 }
    733 
    734 
    735 // ES5 section 15.2.3.4.
    736 function ObjectGetOwnPropertyNames(obj) {
    737   if (!IS_SPEC_OBJECT(obj))
    738     throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
    739 
    740   // Find all the indexed properties.
    741 
    742   // Get the local element names.
    743   var propertyNames = %GetLocalElementNames(obj);
    744 
    745   // Get names for indexed interceptor properties.
    746   if (%GetInterceptorInfo(obj) & 1) {
    747     var indexedInterceptorNames =
    748         %GetIndexedInterceptorElementNames(obj);
    749     if (indexedInterceptorNames)
    750       propertyNames = propertyNames.concat(indexedInterceptorNames);
    751   }
    752 
    753   // Find all the named properties.
    754 
    755   // Get the local property names.
    756   propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
    757 
    758   // Get names for named interceptor properties if any.
    759 
    760   if (%GetInterceptorInfo(obj) & 2) {
    761     var namedInterceptorNames =
    762         %GetNamedInterceptorPropertyNames(obj);
    763     if (namedInterceptorNames) {
    764       propertyNames = propertyNames.concat(namedInterceptorNames);
    765     }
    766   }
    767 
    768   // Property names are expected to be unique strings.
    769   var propertySet = {};
    770   var j = 0;
    771   for (var i = 0; i < propertyNames.length; ++i) {
    772     var name = ToString(propertyNames[i]);
    773     // We need to check for the exact property value since for intrinsic
    774     // properties like toString if(propertySet["toString"]) will always
    775     // succeed.
    776     if (propertySet[name] === true)
    777       continue;
    778     propertySet[name] = true;
    779     propertyNames[j++] = name;
    780   }
    781   propertyNames.length = j;
    782 
    783   return propertyNames;
    784 }
    785 
    786 
    787 // ES5 section 15.2.3.5.
    788 function ObjectCreate(proto, properties) {
    789   if (!IS_SPEC_OBJECT(proto) && proto !== null) {
    790     throw MakeTypeError("proto_object_or_null", [proto]);
    791   }
    792   var obj = new $Object();
    793   obj.__proto__ = proto;
    794   if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
    795   return obj;
    796 }
    797 
    798 
    799 // ES5 section 15.2.3.6.
    800 function ObjectDefineProperty(obj, p, attributes) {
    801   if (!IS_SPEC_OBJECT(obj)) {
    802     throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
    803   }
    804   var name = ToString(p);
    805   var desc = ToPropertyDescriptor(attributes);
    806   DefineOwnProperty(obj, name, desc, true);
    807   return obj;
    808 }
    809 
    810 
    811 // ES5 section 15.2.3.7.
    812 function ObjectDefineProperties(obj, properties) {
    813   if (!IS_SPEC_OBJECT(obj))
    814     throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
    815   var props = ToObject(properties);
    816   var key_values = [];
    817   for (var key in props) {
    818     if (%HasLocalProperty(props, key)) {
    819       key_values.push(key);
    820       var value = props[key];
    821       var desc = ToPropertyDescriptor(value);
    822       key_values.push(desc);
    823     }
    824   }
    825   for (var i = 0; i < key_values.length; i += 2) {
    826     var key = key_values[i];
    827     var desc = key_values[i + 1];
    828     DefineOwnProperty(obj, key, desc, true);
    829   }
    830   return obj;
    831 }
    832 
    833 
    834 // ES5 section 15.2.3.8.
    835 function ObjectSeal(obj) {
    836   if (!IS_SPEC_OBJECT(obj)) {
    837     throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
    838   }
    839   var names = ObjectGetOwnPropertyNames(obj);
    840   for (var i = 0; i < names.length; i++) {
    841     var name = names[i];
    842     var desc = GetOwnProperty(obj, name);
    843     if (desc.isConfigurable()) desc.setConfigurable(false);
    844     DefineOwnProperty(obj, name, desc, true);
    845   }
    846   return ObjectPreventExtension(obj);
    847 }
    848 
    849 
    850 // ES5 section 15.2.3.9.
    851 function ObjectFreeze(obj) {
    852   if (!IS_SPEC_OBJECT(obj)) {
    853     throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
    854   }
    855   var names = ObjectGetOwnPropertyNames(obj);
    856   for (var i = 0; i < names.length; i++) {
    857     var name = names[i];
    858     var desc = GetOwnProperty(obj, name);
    859     if (IsDataDescriptor(desc)) desc.setWritable(false);
    860     if (desc.isConfigurable()) desc.setConfigurable(false);
    861     DefineOwnProperty(obj, name, desc, true);
    862   }
    863   return ObjectPreventExtension(obj);
    864 }
    865 
    866 
    867 // ES5 section 15.2.3.10
    868 function ObjectPreventExtension(obj) {
    869   if (!IS_SPEC_OBJECT(obj)) {
    870     throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
    871   }
    872   %PreventExtensions(obj);
    873   return obj;
    874 }
    875 
    876 
    877 // ES5 section 15.2.3.11
    878 function ObjectIsSealed(obj) {
    879   if (!IS_SPEC_OBJECT(obj)) {
    880     throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
    881   }
    882   var names = ObjectGetOwnPropertyNames(obj);
    883   for (var i = 0; i < names.length; i++) {
    884     var name = names[i];
    885     var desc = GetOwnProperty(obj, name);
    886     if (desc.isConfigurable()) return false;
    887   }
    888   if (!ObjectIsExtensible(obj)) {
    889     return true;
    890   }
    891   return false;
    892 }
    893 
    894 
    895 // ES5 section 15.2.3.12
    896 function ObjectIsFrozen(obj) {
    897   if (!IS_SPEC_OBJECT(obj)) {
    898     throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
    899   }
    900   var names = ObjectGetOwnPropertyNames(obj);
    901   for (var i = 0; i < names.length; i++) {
    902     var name = names[i];
    903     var desc = GetOwnProperty(obj, name);
    904     if (IsDataDescriptor(desc) && desc.isWritable()) return false;
    905     if (desc.isConfigurable()) return false;
    906   }
    907   if (!ObjectIsExtensible(obj)) {
    908     return true;
    909   }
    910   return false;
    911 }
    912 
    913 
    914 // ES5 section 15.2.3.13
    915 function ObjectIsExtensible(obj) {
    916   if (!IS_SPEC_OBJECT(obj)) {
    917     throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
    918   }
    919   return %IsExtensible(obj);
    920 }
    921 
    922 
    923 %SetCode($Object, function(x) {
    924   if (%_IsConstructCall()) {
    925     if (x == null) return this;
    926     return ToObject(x);
    927   } else {
    928     if (x == null) return { };
    929     return ToObject(x);
    930   }
    931 });
    932 
    933 %SetExpectedNumberOfProperties($Object, 4);
    934 
    935 // ----------------------------------------------------------------------------
    936 
    937 
    938 function SetupObject() {
    939   // Setup non-enumerable functions on the Object.prototype object.
    940   InstallFunctions($Object.prototype, DONT_ENUM, $Array(
    941     "toString", ObjectToString,
    942     "toLocaleString", ObjectToLocaleString,
    943     "valueOf", ObjectValueOf,
    944     "hasOwnProperty", ObjectHasOwnProperty,
    945     "isPrototypeOf", ObjectIsPrototypeOf,
    946     "propertyIsEnumerable", ObjectPropertyIsEnumerable,
    947     "__defineGetter__", ObjectDefineGetter,
    948     "__lookupGetter__", ObjectLookupGetter,
    949     "__defineSetter__", ObjectDefineSetter,
    950     "__lookupSetter__", ObjectLookupSetter
    951   ));
    952   InstallFunctions($Object, DONT_ENUM, $Array(
    953     "keys", ObjectKeys,
    954     "create", ObjectCreate,
    955     "defineProperty", ObjectDefineProperty,
    956     "defineProperties", ObjectDefineProperties,
    957     "freeze", ObjectFreeze,
    958     "getPrototypeOf", ObjectGetPrototypeOf,
    959     "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
    960     "getOwnPropertyNames", ObjectGetOwnPropertyNames,
    961     "isExtensible", ObjectIsExtensible,
    962     "isFrozen", ObjectIsFrozen,
    963     "isSealed", ObjectIsSealed,
    964     "preventExtensions", ObjectPreventExtension,
    965     "seal", ObjectSeal
    966   ));
    967 }
    968 
    969 SetupObject();
    970 
    971 
    972 // ----------------------------------------------------------------------------
    973 // Boolean
    974 
    975 function BooleanToString() {
    976   // NOTE: Both Boolean objects and values can enter here as
    977   // 'this'. This is not as dictated by ECMA-262.
    978   var b = this;
    979   if (!IS_BOOLEAN(b)) {
    980     if (!IS_BOOLEAN_WRAPPER(b)) {
    981       throw new $TypeError('Boolean.prototype.toString is not generic');
    982     }
    983     b = %_ValueOf(b);
    984   }
    985   return b ? 'true' : 'false';
    986 }
    987 
    988 
    989 function BooleanValueOf() {
    990   // NOTE: Both Boolean objects and values can enter here as
    991   // 'this'. This is not as dictated by ECMA-262.
    992   if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
    993     throw new $TypeError('Boolean.prototype.valueOf is not generic');
    994   return %_ValueOf(this);
    995 }
    996 
    997 
    998 // ----------------------------------------------------------------------------
    999 
   1000 
   1001 function SetupBoolean() {
   1002   InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
   1003     "toString", BooleanToString,
   1004     "valueOf", BooleanValueOf
   1005   ));
   1006 }
   1007 
   1008 SetupBoolean();
   1009 
   1010 // ----------------------------------------------------------------------------
   1011 // Number
   1012 
   1013 // Set the Number function and constructor.
   1014 %SetCode($Number, function(x) {
   1015   var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
   1016   if (%_IsConstructCall()) {
   1017     %_SetValueOf(this, value);
   1018   } else {
   1019     return value;
   1020   }
   1021 });
   1022 
   1023 %FunctionSetPrototype($Number, new $Number(0));
   1024 
   1025 // ECMA-262 section 15.7.4.2.
   1026 function NumberToString(radix) {
   1027   // NOTE: Both Number objects and values can enter here as
   1028   // 'this'. This is not as dictated by ECMA-262.
   1029   var number = this;
   1030   if (!IS_NUMBER(this)) {
   1031     if (!IS_NUMBER_WRAPPER(this))
   1032       throw new $TypeError('Number.prototype.toString is not generic');
   1033     // Get the value of this number in case it's an object.
   1034     number = %_ValueOf(this);
   1035   }
   1036   // Fast case: Convert number in radix 10.
   1037   if (IS_UNDEFINED(radix) || radix === 10) {
   1038     return %_NumberToString(number);
   1039   }
   1040 
   1041   // Convert the radix to an integer and check the range.
   1042   radix = TO_INTEGER(radix);
   1043   if (radix < 2 || radix > 36) {
   1044     throw new $RangeError('toString() radix argument must be between 2 and 36');
   1045   }
   1046   // Convert the number to a string in the given radix.
   1047   return %NumberToRadixString(number, radix);
   1048 }
   1049 
   1050 
   1051 // ECMA-262 section 15.7.4.3
   1052 function NumberToLocaleString() {
   1053   return this.toString();
   1054 }
   1055 
   1056 
   1057 // ECMA-262 section 15.7.4.4
   1058 function NumberValueOf() {
   1059   // NOTE: Both Number objects and values can enter here as
   1060   // 'this'. This is not as dictated by ECMA-262.
   1061   if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
   1062     throw new $TypeError('Number.prototype.valueOf is not generic');
   1063   return %_ValueOf(this);
   1064 }
   1065 
   1066 
   1067 // ECMA-262 section 15.7.4.5
   1068 function NumberToFixed(fractionDigits) {
   1069   var f = TO_INTEGER(fractionDigits);
   1070   if (f < 0 || f > 20) {
   1071     throw new $RangeError("toFixed() digits argument must be between 0 and 20");
   1072   }
   1073   var x = ToNumber(this);
   1074   return %NumberToFixed(x, f);
   1075 }
   1076 
   1077 
   1078 // ECMA-262 section 15.7.4.6
   1079 function NumberToExponential(fractionDigits) {
   1080   var f = -1;
   1081   if (!IS_UNDEFINED(fractionDigits)) {
   1082     f = TO_INTEGER(fractionDigits);
   1083     if (f < 0 || f > 20) {
   1084       throw new $RangeError("toExponential() argument must be between 0 and 20");
   1085     }
   1086   }
   1087   var x = ToNumber(this);
   1088   return %NumberToExponential(x, f);
   1089 }
   1090 
   1091 
   1092 // ECMA-262 section 15.7.4.7
   1093 function NumberToPrecision(precision) {
   1094   if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
   1095   var p = TO_INTEGER(precision);
   1096   if (p < 1 || p > 21) {
   1097     throw new $RangeError("toPrecision() argument must be between 1 and 21");
   1098   }
   1099   var x = ToNumber(this);
   1100   return %NumberToPrecision(x, p);
   1101 }
   1102 
   1103 
   1104 // ----------------------------------------------------------------------------
   1105 
   1106 function SetupNumber() {
   1107   %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
   1108   // Setup the constructor property on the Number prototype object.
   1109   %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
   1110 
   1111   %OptimizeObjectForAddingMultipleProperties($Number, 5);
   1112   // ECMA-262 section 15.7.3.1.
   1113   %SetProperty($Number,
   1114                "MAX_VALUE",
   1115                1.7976931348623157e+308,
   1116                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1117 
   1118   // ECMA-262 section 15.7.3.2.
   1119   %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
   1120 
   1121   // ECMA-262 section 15.7.3.3.
   1122   %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
   1123 
   1124   // ECMA-262 section 15.7.3.4.
   1125   %SetProperty($Number,
   1126                "NEGATIVE_INFINITY",
   1127                -1/0,
   1128                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1129 
   1130   // ECMA-262 section 15.7.3.5.
   1131   %SetProperty($Number,
   1132                "POSITIVE_INFINITY",
   1133                1/0,
   1134                DONT_ENUM | DONT_DELETE | READ_ONLY);
   1135   %ToFastProperties($Number);
   1136 
   1137   // Setup non-enumerable functions on the Number prototype object.
   1138   InstallFunctions($Number.prototype, DONT_ENUM, $Array(
   1139     "toString", NumberToString,
   1140     "toLocaleString", NumberToLocaleString,
   1141     "valueOf", NumberValueOf,
   1142     "toFixed", NumberToFixed,
   1143     "toExponential", NumberToExponential,
   1144     "toPrecision", NumberToPrecision
   1145   ));
   1146 }
   1147 
   1148 SetupNumber();
   1149 
   1150 
   1151 // ----------------------------------------------------------------------------
   1152 // Function
   1153 
   1154 $Function.prototype.constructor = $Function;
   1155 
   1156 function FunctionSourceString(func) {
   1157   if (!IS_FUNCTION(func)) {
   1158     throw new $TypeError('Function.prototype.toString is not generic');
   1159   }
   1160 
   1161   var source = %FunctionGetSourceCode(func);
   1162   if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
   1163     var name = %FunctionGetName(func);
   1164     if (name) {
   1165       // Mimic what KJS does.
   1166       return 'function ' + name + '() { [native code] }';
   1167     } else {
   1168       return 'function () { [native code] }';
   1169     }
   1170   }
   1171 
   1172   var name = %FunctionGetName(func);
   1173   return 'function ' + name + source;
   1174 }
   1175 
   1176 
   1177 function FunctionToString() {
   1178   return FunctionSourceString(this);
   1179 }
   1180 
   1181 
   1182 // ES5 15.3.4.5
   1183 function FunctionBind(this_arg) { // Length is 1.
   1184   if (!IS_FUNCTION(this)) {
   1185       throw new $TypeError('Bind must be called on a function');
   1186   }
   1187   // this_arg is not an argument that should be bound.
   1188   var argc_bound = (%_ArgumentsLength() || 1) - 1;
   1189   var fn = this;
   1190   if (argc_bound == 0) {
   1191     var result = function() {
   1192       if (%_IsConstructCall()) {
   1193         // %NewObjectFromBound implicitly uses arguments passed to this
   1194         // function. We do not pass the arguments object explicitly to avoid
   1195         // materializing it and guarantee that this function will be optimized.
   1196         return %NewObjectFromBound(fn, null);
   1197       }
   1198 
   1199       return fn.apply(this_arg, arguments);
   1200     };
   1201   } else {
   1202     var bound_args = new InternalArray(argc_bound);
   1203     for(var i = 0; i < argc_bound; i++) {
   1204       bound_args[i] = %_Arguments(i+1);
   1205     }
   1206 
   1207     var result = function() {
   1208       // If this is a construct call we use a special runtime method
   1209       // to generate the actual object using the bound function.
   1210       if (%_IsConstructCall()) {
   1211         // %NewObjectFromBound implicitly uses arguments passed to this
   1212         // function. We do not pass the arguments object explicitly to avoid
   1213         // materializing it and guarantee that this function will be optimized.
   1214         return %NewObjectFromBound(fn, bound_args);
   1215       }
   1216 
   1217       // Combine the args we got from the bind call with the args
   1218       // given as argument to the invocation.
   1219       var argc = %_ArgumentsLength();
   1220       var args = new InternalArray(argc + argc_bound);
   1221       // Add bound arguments.
   1222       for (var i = 0; i < argc_bound; i++) {
   1223         args[i] = bound_args[i];
   1224       }
   1225       // Add arguments from call.
   1226       for (var i = 0; i < argc; i++) {
   1227         args[argc_bound + i] = %_Arguments(i);
   1228       }
   1229       return fn.apply(this_arg, args);
   1230     };
   1231   }
   1232 
   1233   // We already have caller and arguments properties on functions,
   1234   // which are non-configurable. It therefore makes no sence to
   1235   // try to redefine these as defined by the spec. The spec says
   1236   // that bind should make these throw a TypeError if get or set
   1237   // is called and make them non-enumerable and non-configurable.
   1238   // To be consistent with our normal functions we leave this as it is.
   1239 
   1240   // Set the correct length.
   1241   var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
   1242   %FunctionSetLength(result, length);
   1243 
   1244   return result;
   1245 }
   1246 
   1247 
   1248 function NewFunction(arg1) {  // length == 1
   1249   var n = %_ArgumentsLength();
   1250   var p = '';
   1251   if (n > 1) {
   1252     p = new InternalArray(n - 1);
   1253     for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
   1254     p = Join(p, n - 1, ',', NonStringToString);
   1255     // If the formal parameters string include ) - an illegal
   1256     // character - it may make the combined function expression
   1257     // compile. We avoid this problem by checking for this early on.
   1258     if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
   1259   }
   1260   var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
   1261   var source = '(function(' + p + ') {\n' + body + '\n})';
   1262 
   1263   // The call to SetNewFunctionAttributes will ensure the prototype
   1264   // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
   1265   var f = %CompileString(source)();
   1266   %FunctionSetName(f, "anonymous");
   1267   return %SetNewFunctionAttributes(f);
   1268 }
   1269 
   1270 %SetCode($Function, NewFunction);
   1271 
   1272 // ----------------------------------------------------------------------------
   1273 
   1274 function SetupFunction() {
   1275   InstallFunctions($Function.prototype, DONT_ENUM, $Array(
   1276     "bind", FunctionBind,
   1277     "toString", FunctionToString
   1278   ));
   1279 }
   1280 
   1281 SetupFunction();
   1282