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