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