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