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