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