blob: f1e8084a53038dff8d8c33a888d2e1bf41311af4 [file] [log] [blame]
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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//
30// in runtime.js:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010031// var $Object = global.Object;
32// var $Boolean = global.Boolean;
33// var $Number = global.Number;
34// var $Function = global.Function;
35// var $Array = global.Array;
36// var $NaN = 0/0;
Steve Blocka7e24c12009-10-30 11:49:00 +000037//
38// in math.js:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010039// var $floor = MathFloor
Steve Blocka7e24c12009-10-30 11:49:00 +000040
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010041var $isNaN = GlobalIsNaN;
42var $isFinite = GlobalIsFinite;
Steve Blocka7e24c12009-10-30 11:49:00 +000043
44// ----------------------------------------------------------------------------
45
46
47// Helper function used to install functions on objects.
48function InstallFunctions(object, attributes, functions) {
49 if (functions.length >= 8) {
50 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
51 }
52 for (var i = 0; i < functions.length; i += 2) {
53 var key = functions[i];
54 var f = functions[i + 1];
55 %FunctionSetName(f, key);
Steve Block6ded16b2010-05-10 14:33:55 +010056 %FunctionRemovePrototype(f);
Steve Blocka7e24c12009-10-30 11:49:00 +000057 %SetProperty(object, key, f, attributes);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000058 %SetNativeFlag(f);
Steve Blocka7e24c12009-10-30 11:49:00 +000059 }
Andrei Popescu402d9372010-02-26 13:31:12 +000060 %ToFastProperties(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000061}
62
Ben Murdoch589d6972011-11-30 16:04:58 +000063// Prevents changes to the prototype of a built-infunction.
64// The "prototype" property of the function object is made non-configurable,
65// and the prototype object is made non-extensible. The latter prevents
66// changing the __proto__ property.
67function SetUpLockedPrototype(constructor, fields, methods) {
68 %CheckIsBootstrapping();
69 var prototype = constructor.prototype;
70 // Install functions first, because this function is used to initialize
71 // PropertyDescriptor itself.
72 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
73 if (property_count >= 4) {
74 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
75 }
76 if (fields) {
77 for (var i = 0; i < fields.length; i++) {
78 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
79 }
80 }
81 for (var i = 0; i < methods.length; i += 2) {
82 var key = methods[i];
83 var f = methods[i + 1];
84 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
85 %SetNativeFlag(f);
86 }
87 prototype.__proto__ = null;
88 %ToFastProperties(prototype);
89}
90
91
Steve Blocka7e24c12009-10-30 11:49:00 +000092// ----------------------------------------------------------------------------
93
94
95// ECMA 262 - 15.1.4
96function GlobalIsNaN(number) {
Ben Murdoch589d6972011-11-30 16:04:58 +000097 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
98 return NUMBER_IS_NAN(number);
Steve Blocka7e24c12009-10-30 11:49:00 +000099}
100
101
102// ECMA 262 - 15.1.5
103function GlobalIsFinite(number) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100104 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
Ben Murdoch589d6972011-11-30 16:04:58 +0000105 return NUMBER_IS_FINITE(number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000106}
107
108
109// ECMA-262 - 15.1.2.2
110function GlobalParseInt(string, radix) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100111 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 // Some people use parseInt instead of Math.floor. This
113 // optimization makes parseInt on a Smi 12 times faster (60ns
114 // vs 800ns). The following optimization makes parseInt on a
115 // non-Smi number 9 times faster (230ns vs 2070ns). Together
116 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
117 if (%_IsSmi(string)) return string;
118 if (IS_NUMBER(string) &&
Steve Blockd0582a62009-12-15 09:54:21 +0000119 ((0.01 < string && string < 1e9) ||
120 (-1e9 < string && string < -0.01))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 // Truncate number.
122 return string | 0;
123 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000124 string = TO_STRING_INLINE(string);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000125 radix = radix | 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000127 // The spec says ToString should be evaluated before ToInt32.
128 string = TO_STRING_INLINE(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 radix = TO_INT32(radix);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000130 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 return $NaN;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000132 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000134
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100135 if (%_HasCachedArrayIndex(string) &&
136 (radix == 0 || radix == 10)) {
137 return %_GetCachedArrayIndex(string);
138 }
139 return %StringParseInt(string, radix);
Steve Blocka7e24c12009-10-30 11:49:00 +0000140}
141
142
143// ECMA-262 - 15.1.2.3
144function GlobalParseFloat(string) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100145 string = TO_STRING_INLINE(string);
146 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
147 return %StringParseFloat(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000148}
149
150
151function GlobalEval(x) {
152 if (!IS_STRING(x)) return x;
153
154 var global_receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000155 var global_is_detached = (global === global_receiver);
156
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000157 // For consistency with JSC we require the global object passed to
158 // eval to be the global object from which 'eval' originated. This
159 // is not mandated by the spec.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000160 // We only throw if the global has been detached, since we need the
161 // receiver as this-value for the call.
162 if (global_is_detached) {
163 throw new $EvalError('The "this" value passed to eval must ' +
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 'be the global object from which eval originated');
165 }
166
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800167 var f = %CompileString(x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 if (!IS_FUNCTION(f)) return f;
169
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000170 return %_CallFunction(global_receiver, f);
Steve Blocka7e24c12009-10-30 11:49:00 +0000171}
172
173
Steve Blocka7e24c12009-10-30 11:49:00 +0000174// ----------------------------------------------------------------------------
175
Ben Murdoch589d6972011-11-30 16:04:58 +0000176// Set up global object.
177function SetUpGlobal() {
178 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 // ECMA 262 - 15.1.1.1.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000180 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
Steve Blocka7e24c12009-10-30 11:49:00 +0000181
182 // ECMA-262 - 15.1.1.2.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000183 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
Steve Blocka7e24c12009-10-30 11:49:00 +0000184
185 // ECMA-262 - 15.1.1.3.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000186 %SetProperty(global, "undefined", void 0,
187 DONT_ENUM | DONT_DELETE | READ_ONLY);
Steve Blocka7e24c12009-10-30 11:49:00 +0000188
Ben Murdoch589d6972011-11-30 16:04:58 +0000189 // Set up non-enumerable function on the global object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000190 InstallFunctions(global, DONT_ENUM, $Array(
191 "isNaN", GlobalIsNaN,
192 "isFinite", GlobalIsFinite,
193 "parseInt", GlobalParseInt,
194 "parseFloat", GlobalParseFloat,
Steve Block053d10c2011-06-13 19:13:29 +0100195 "eval", GlobalEval
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 ));
197}
198
Ben Murdoch589d6972011-11-30 16:04:58 +0000199SetUpGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +0000200
201// ----------------------------------------------------------------------------
202// Boolean (first part of definition)
203
204
205%SetCode($Boolean, function(x) {
206 if (%_IsConstructCall()) {
207 %_SetValueOf(this, ToBoolean(x));
208 } else {
209 return ToBoolean(x);
210 }
211});
212
213%FunctionSetPrototype($Boolean, new $Boolean(false));
214
215%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
216
217// ----------------------------------------------------------------------------
218// Object
219
220$Object.prototype.constructor = $Object;
221
222// ECMA-262 - 15.2.4.2
223function ObjectToString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000224 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
225 return '[object Undefined]';
226 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000227 if (IS_NULL(this)) return '[object Null]';
Leon Clarked91b9f72010-01-27 17:25:45 +0000228 return "[object " + %_ClassOf(ToObject(this)) + "]";
Steve Blocka7e24c12009-10-30 11:49:00 +0000229}
230
231
232// ECMA-262 - 15.2.4.3
233function ObjectToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000234 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
235 throw MakeTypeError("called_on_null_or_undefined",
236 ["Object.prototype.toLocaleString"]);
237 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 return this.toString();
239}
240
241
242// ECMA-262 - 15.2.4.4
243function ObjectValueOf() {
Leon Clarked91b9f72010-01-27 17:25:45 +0000244 return ToObject(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000245}
246
247
248// ECMA-262 - 15.2.4.5
249function ObjectHasOwnProperty(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000250 if (%IsJSProxy(this)) {
251 var handler = %GetHandler(this);
252 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
253 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000254 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
Steve Blocka7e24c12009-10-30 11:49:00 +0000255}
256
257
258// ECMA-262 - 15.2.4.6
259function ObjectIsPrototypeOf(V) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000260 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
261 throw MakeTypeError("called_on_null_or_undefined",
262 ["Object.prototype.isPrototypeOf"]);
263 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100264 if (!IS_SPEC_OBJECT(V)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 return %IsInPrototypeChain(this, V);
266}
267
268
269// ECMA-262 - 15.2.4.6
270function ObjectPropertyIsEnumerable(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000271 var P = ToString(V);
272 if (%IsJSProxy(this)) {
273 var desc = GetOwnProperty(this, P);
274 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
275 }
276 return %IsPropertyEnumerable(ToObject(this), P);
Steve Blocka7e24c12009-10-30 11:49:00 +0000277}
278
279
280// Extensions for providing property getters and setters.
281function ObjectDefineGetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000282 var receiver = this;
283 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
284 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000286 if (!IS_SPEC_FUNCTION(fun)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000287 throw new $TypeError(
288 'Object.prototype.__defineGetter__: Expecting function');
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 }
Steve Block44f0eee2011-05-26 01:26:41 +0100290 var desc = new PropertyDescriptor();
291 desc.setGet(fun);
292 desc.setEnumerable(true);
293 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000294 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000295}
296
297
298function ObjectLookupGetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000299 var receiver = this;
300 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
301 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000303 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000304}
305
306
307function ObjectDefineSetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000308 var receiver = this;
309 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
310 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000312 if (!IS_SPEC_FUNCTION(fun)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000313 throw new $TypeError(
314 'Object.prototype.__defineSetter__: Expecting function');
315 }
Steve Block44f0eee2011-05-26 01:26:41 +0100316 var desc = new PropertyDescriptor();
317 desc.setSet(fun);
318 desc.setEnumerable(true);
319 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000320 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000321}
322
323
324function ObjectLookupSetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000325 var receiver = this;
326 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
327 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000328 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000329 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000330}
331
332
333function ObjectKeys(obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000334 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100335 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000336 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000337 if (%IsJSProxy(obj)) {
338 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000339 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000340 return ToStringArray(names);
341 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 return %LocalKeys(obj);
343}
344
345
Leon Clarkee46be812010-01-19 14:06:41 +0000346// ES5 8.10.1.
347function IsAccessorDescriptor(desc) {
348 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000349 return desc.hasGetter() || desc.hasSetter();
Leon Clarkee46be812010-01-19 14:06:41 +0000350}
351
352
353// ES5 8.10.2.
354function IsDataDescriptor(desc) {
355 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000356 return desc.hasValue() || desc.hasWritable();
Leon Clarkee46be812010-01-19 14:06:41 +0000357}
358
359
360// ES5 8.10.3.
361function IsGenericDescriptor(desc) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000362 if (IS_UNDEFINED(desc)) return false;
Leon Clarkee46be812010-01-19 14:06:41 +0000363 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
364}
365
366
367function IsInconsistentDescriptor(desc) {
368 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
369}
370
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000371
Leon Clarkee46be812010-01-19 14:06:41 +0000372// ES5 8.10.4
373function FromPropertyDescriptor(desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000374 if (IS_UNDEFINED(desc)) return desc;
Ben Murdoch257744e2011-11-30 15:57:28 +0000375
Leon Clarkee46be812010-01-19 14:06:41 +0000376 if (IsDataDescriptor(desc)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000377 return { value: desc.getValue(),
378 writable: desc.isWritable(),
379 enumerable: desc.isEnumerable(),
380 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000381 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000382 // Must be an AccessorDescriptor then. We never return a generic descriptor.
383 return { get: desc.getGet(),
384 set: desc.getSet(),
385 enumerable: desc.isEnumerable(),
386 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000387}
388
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000389
390// Harmony Proxies
391function FromGenericPropertyDescriptor(desc) {
392 if (IS_UNDEFINED(desc)) return desc;
393 var obj = new $Object();
394
395 if (desc.hasValue()) {
396 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
397 }
398 if (desc.hasWritable()) {
399 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
400 }
401 if (desc.hasGetter()) {
402 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
403 }
404 if (desc.hasSetter()) {
405 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
406 }
407 if (desc.hasEnumerable()) {
408 %IgnoreAttributesAndSetProperty(obj, "enumerable",
409 desc.isEnumerable(), NONE);
410 }
411 if (desc.hasConfigurable()) {
412 %IgnoreAttributesAndSetProperty(obj, "configurable",
413 desc.isConfigurable(), NONE);
414 }
415 return obj;
416}
417
418
Leon Clarkee46be812010-01-19 14:06:41 +0000419// ES5 8.10.5.
420function ToPropertyDescriptor(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100421 if (!IS_SPEC_OBJECT(obj)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000422 throw MakeTypeError("property_desc_object", [obj]);
423 }
424 var desc = new PropertyDescriptor();
425
426 if ("enumerable" in obj) {
427 desc.setEnumerable(ToBoolean(obj.enumerable));
428 }
429
Leon Clarkee46be812010-01-19 14:06:41 +0000430 if ("configurable" in obj) {
431 desc.setConfigurable(ToBoolean(obj.configurable));
432 }
433
434 if ("value" in obj) {
435 desc.setValue(obj.value);
436 }
437
438 if ("writable" in obj) {
439 desc.setWritable(ToBoolean(obj.writable));
440 }
441
442 if ("get" in obj) {
443 var get = obj.get;
Ben Murdoch589d6972011-11-30 16:04:58 +0000444 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000445 throw MakeTypeError("getter_must_be_callable", [get]);
446 }
447 desc.setGet(get);
448 }
449
450 if ("set" in obj) {
451 var set = obj.set;
Ben Murdoch589d6972011-11-30 16:04:58 +0000452 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000453 throw MakeTypeError("setter_must_be_callable", [set]);
454 }
455 desc.setSet(set);
456 }
457
458 if (IsInconsistentDescriptor(desc)) {
459 throw MakeTypeError("value_and_accessor", [obj]);
460 }
461 return desc;
462}
463
464
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000465// For Harmony proxies.
466function ToCompletePropertyDescriptor(obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000467 var desc = ToPropertyDescriptor(obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000468 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
469 if (!desc.hasValue()) desc.setValue(void 0);
470 if (!desc.hasWritable()) desc.setWritable(false);
471 } else {
472 // Is accessor descriptor.
473 if (!desc.hasGetter()) desc.setGet(void 0);
474 if (!desc.hasSetter()) desc.setSet(void 0);
475 }
476 if (!desc.hasEnumerable()) desc.setEnumerable(false);
477 if (!desc.hasConfigurable()) desc.setConfigurable(false);
478 return desc;
479}
480
481
Leon Clarkee46be812010-01-19 14:06:41 +0000482function PropertyDescriptor() {
483 // Initialize here so they are all in-object and have the same map.
484 // Default values from ES5 8.6.1.
485 this.value_ = void 0;
486 this.hasValue_ = false;
487 this.writable_ = false;
488 this.hasWritable_ = false;
489 this.enumerable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000490 this.hasEnumerable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000491 this.configurable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000492 this.hasConfigurable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000493 this.get_ = void 0;
494 this.hasGetter_ = false;
495 this.set_ = void 0;
496 this.hasSetter_ = false;
497}
498
Ben Murdoch589d6972011-11-30 16:04:58 +0000499SetUpLockedPrototype(PropertyDescriptor, $Array(
500 "value_",
501 "hasValue_",
502 "writable_",
503 "hasWritable_",
504 "enumerable_",
505 "hasEnumerable_",
506 "configurable_",
507 "hasConfigurable_",
508 "get_",
509 "hasGetter_",
510 "set_",
511 "hasSetter_"
512 ), $Array(
513 "toString", function() {
514 return "[object PropertyDescriptor]";
515 },
516 "setValue", function(value) {
517 this.value_ = value;
518 this.hasValue_ = true;
519 },
520 "getValue", function() {
521 return this.value_;
522 },
523 "hasValue", function() {
524 return this.hasValue_;
525 },
526 "setEnumerable", function(enumerable) {
527 this.enumerable_ = enumerable;
528 this.hasEnumerable_ = true;
529 },
530 "isEnumerable", function () {
531 return this.enumerable_;
532 },
533 "hasEnumerable", function() {
534 return this.hasEnumerable_;
535 },
536 "setWritable", function(writable) {
537 this.writable_ = writable;
538 this.hasWritable_ = true;
539 },
540 "isWritable", function() {
541 return this.writable_;
542 },
543 "hasWritable", function() {
544 return this.hasWritable_;
545 },
546 "setConfigurable", function(configurable) {
547 this.configurable_ = configurable;
548 this.hasConfigurable_ = true;
549 },
550 "hasConfigurable", function() {
551 return this.hasConfigurable_;
552 },
553 "isConfigurable", function() {
554 return this.configurable_;
555 },
556 "setGet", function(get) {
557 this.get_ = get;
558 this.hasGetter_ = true;
559 },
560 "getGet", function() {
561 return this.get_;
562 },
563 "hasGetter", function() {
564 return this.hasGetter_;
565 },
566 "setSet", function(set) {
567 this.set_ = set;
568 this.hasSetter_ = true;
569 },
570 "getSet", function() {
571 return this.set_;
572 },
573 "hasSetter", function() {
574 return this.hasSetter_;
575 }));
Andrei Popescu31002712010-02-23 13:46:05 +0000576
577
Steve Block1e0659c2011-05-24 12:43:12 +0100578// Converts an array returned from Runtime_GetOwnProperty to an actual
579// property descriptor. For a description of the array layout please
580// see the runtime.cc file.
581function ConvertDescriptorArrayToDescriptor(desc_array) {
Steve Block44f0eee2011-05-26 01:26:41 +0100582 if (desc_array === false) {
Steve Block1e0659c2011-05-24 12:43:12 +0100583 throw 'Internal error: invalid desc_array';
Steve Block103cc402011-02-16 13:27:44 +0000584 }
Steve Block1e0659c2011-05-24 12:43:12 +0100585
586 if (IS_UNDEFINED(desc_array)) {
587 return void 0;
588 }
589
590 var desc = new PropertyDescriptor();
591 // This is an accessor.
592 if (desc_array[IS_ACCESSOR_INDEX]) {
593 desc.setGet(desc_array[GETTER_INDEX]);
594 desc.setSet(desc_array[SETTER_INDEX]);
595 } else {
596 desc.setValue(desc_array[VALUE_INDEX]);
597 desc.setWritable(desc_array[WRITABLE_INDEX]);
598 }
599 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
600 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
Leon Clarkee46be812010-01-19 14:06:41 +0000601
602 return desc;
603}
604
605
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000606// For Harmony proxies.
607function GetTrap(handler, name, defaultTrap) {
608 var trap = handler[name];
609 if (IS_UNDEFINED(trap)) {
610 if (IS_UNDEFINED(defaultTrap)) {
611 throw MakeTypeError("handler_trap_missing", [handler, name]);
612 }
613 trap = defaultTrap;
Ben Murdoch589d6972011-11-30 16:04:58 +0000614 } else if (!IS_SPEC_FUNCTION(trap)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000615 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
616 }
617 return trap;
618}
619
620
621function CallTrap0(handler, name, defaultTrap) {
622 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
623}
624
625
626function CallTrap1(handler, name, defaultTrap, x) {
627 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
628}
629
630
631function CallTrap2(handler, name, defaultTrap, x, y) {
632 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
633}
634
635
Steve Block1e0659c2011-05-24 12:43:12 +0100636// ES5 section 8.12.1.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000637function GetOwnProperty(obj, v) {
638 var p = ToString(v);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000639 if (%IsJSProxy(obj)) {
640 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000641 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000642 if (IS_UNDEFINED(descriptor)) return descriptor;
643 var desc = ToCompletePropertyDescriptor(descriptor);
644 if (!desc.isConfigurable()) {
645 throw MakeTypeError("proxy_prop_not_configurable",
646 [handler, "getOwnPropertyDescriptor", p, descriptor]);
647 }
648 return desc;
649 }
650
Steve Block1e0659c2011-05-24 12:43:12 +0100651 // GetOwnProperty returns an array indexed by the constants
652 // defined in macros.py.
653 // If p is not a property on obj undefined is returned.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000654 var props = %GetOwnProperty(ToObject(obj), ToString(v));
Steve Block1e0659c2011-05-24 12:43:12 +0100655
656 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100657 if (props === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100658
659 return ConvertDescriptorArrayToDescriptor(props);
660}
661
662
Ben Murdochc7cc0282012-03-05 14:35:55 +0000663// ES5 section 8.12.7.
664function Delete(obj, p, should_throw) {
665 var desc = GetOwnProperty(obj, p);
666 if (IS_UNDEFINED(desc)) return true;
667 if (desc.isConfigurable()) {
668 %DeleteProperty(obj, p, 0);
669 return true;
670 } else if (should_throw) {
671 throw MakeTypeError("define_disallowed", [p]);
672 } else {
673 return;
674 }
675}
676
677
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000678// Harmony proxies.
679function DefineProxyProperty(obj, p, attributes, should_throw) {
680 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000681 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000682 if (!ToBoolean(result)) {
683 if (should_throw) {
684 throw MakeTypeError("handler_returned_false",
685 [handler, "defineProperty"]);
686 } else {
687 return false;
688 }
689 }
690 return true;
691}
692
693
Steve Block6ded16b2010-05-10 14:33:55 +0100694// ES5 8.12.9.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000695function DefineObjectProperty(obj, p, desc, should_throw) {
Steve Block1e0659c2011-05-24 12:43:12 +0100696 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
697 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100698 if (current_or_access === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100699
700 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
Andrei Popescu31002712010-02-23 13:46:05 +0000701 var extensible = %IsExtensible(ToObject(obj));
702
703 // Error handling according to spec.
704 // Step 3
Steve Block44f0eee2011-05-26 01:26:41 +0100705 if (IS_UNDEFINED(current) && !extensible) {
706 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000707 throw MakeTypeError("define_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100708 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000709 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100710 }
711 }
Andrei Popescu31002712010-02-23 13:46:05 +0000712
Steve Block1e0659c2011-05-24 12:43:12 +0100713 if (!IS_UNDEFINED(current)) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100714 // Step 5 and 6
Steve Block1e0659c2011-05-24 12:43:12 +0100715 if ((IsGenericDescriptor(desc) ||
716 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
717 (!desc.hasEnumerable() ||
718 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100719 (!desc.hasConfigurable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100720 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100721 (!desc.hasWritable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100722 SameValue(desc.isWritable(), current.isWritable())) &&
723 (!desc.hasValue() ||
724 SameValue(desc.getValue(), current.getValue())) &&
725 (!desc.hasGetter() ||
726 SameValue(desc.getGet(), current.getGet())) &&
727 (!desc.hasSetter() ||
728 SameValue(desc.getSet(), current.getSet()))) {
729 return true;
730 }
Steve Block1e0659c2011-05-24 12:43:12 +0100731 if (!current.isConfigurable()) {
732 // Step 7
733 if (desc.isConfigurable() ||
734 (desc.hasEnumerable() &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100735 desc.isEnumerable() != current.isEnumerable())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100736 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000737 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100738 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000739 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100740 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100741 }
Steve Block1e0659c2011-05-24 12:43:12 +0100742 // Step 8
743 if (!IsGenericDescriptor(desc)) {
744 // Step 9a
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100745 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100746 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000747 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100748 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000749 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100750 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100751 }
Steve Block1e0659c2011-05-24 12:43:12 +0100752 // Step 10a
753 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100754 if (!current.isWritable() && desc.isWritable()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100755 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000756 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100757 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000758 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100759 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100760 }
Steve Block1e0659c2011-05-24 12:43:12 +0100761 if (!current.isWritable() && desc.hasValue() &&
762 !SameValue(desc.getValue(), current.getValue())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100763 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000764 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100765 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000766 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100767 }
Steve Block1e0659c2011-05-24 12:43:12 +0100768 }
769 }
770 // Step 11
771 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100772 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100773 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000774 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100775 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000776 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100777 }
Steve Block1e0659c2011-05-24 12:43:12 +0100778 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100779 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100780 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000781 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100782 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000783 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100784 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100785 }
Steve Block1e0659c2011-05-24 12:43:12 +0100786 }
Andrei Popescu31002712010-02-23 13:46:05 +0000787 }
788 }
Andrei Popescu31002712010-02-23 13:46:05 +0000789 }
790
Steve Block6ded16b2010-05-10 14:33:55 +0100791 // Send flags - enumerable and configurable are common - writable is
Andrei Popescu31002712010-02-23 13:46:05 +0000792 // only send to the data descriptor.
793 // Take special care if enumerable and configurable is not defined on
794 // desc (we need to preserve the existing values from current).
795 var flag = NONE;
796 if (desc.hasEnumerable()) {
797 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
798 } else if (!IS_UNDEFINED(current)) {
799 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
Leon Clarkee46be812010-01-19 14:06:41 +0000800 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000801 flag |= DONT_ENUM;
802 }
803
804 if (desc.hasConfigurable()) {
805 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
806 } else if (!IS_UNDEFINED(current)) {
807 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
808 } else
809 flag |= DONT_DELETE;
810
Steve Block1e0659c2011-05-24 12:43:12 +0100811 if (IsDataDescriptor(desc) ||
812 (IsGenericDescriptor(desc) &&
813 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
814 // There are 3 cases that lead here:
815 // Step 4a - defining a new data property.
816 // Steps 9b & 12 - replacing an existing accessor property with a data
817 // property.
818 // Step 12 - updating an existing data property with a data or generic
819 // descriptor.
820
Leon Clarkef7060e22010-06-03 12:02:55 +0100821 if (desc.hasWritable()) {
822 flag |= desc.isWritable() ? 0 : READ_ONLY;
823 } else if (!IS_UNDEFINED(current)) {
824 flag |= current.isWritable() ? 0 : READ_ONLY;
825 } else {
826 flag |= READ_ONLY;
827 }
Steve Block1e0659c2011-05-24 12:43:12 +0100828
Ben Murdochb0fe1622011-05-05 13:52:32 +0100829 var value = void 0; // Default value is undefined.
830 if (desc.hasValue()) {
831 value = desc.getValue();
Steve Block1e0659c2011-05-24 12:43:12 +0100832 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100833 value = current.getValue();
834 }
Steve Block1e0659c2011-05-24 12:43:12 +0100835
Ben Murdochb0fe1622011-05-05 13:52:32 +0100836 %DefineOrRedefineDataProperty(obj, p, value, flag);
Andrei Popescu31002712010-02-23 13:46:05 +0000837 } else {
Steve Block1e0659c2011-05-24 12:43:12 +0100838 // There are 3 cases that lead here:
839 // Step 4b - defining a new accessor property.
840 // Steps 9c & 12 - replacing an existing data property with an accessor
841 // property.
842 // Step 12 - updating an existing accessor property with an accessor
843 // descriptor.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100844 var getter = desc.hasGetter() ? desc.getGet() : null;
845 var setter = desc.hasSetter() ? desc.getSet() : null;
846 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
Leon Clarkee46be812010-01-19 14:06:41 +0000847 }
848 return true;
849}
850
851
Ben Murdochc7cc0282012-03-05 14:35:55 +0000852// ES5 section 15.4.5.1.
853function DefineArrayProperty(obj, p, desc, should_throw) {
854 // Note that the length of an array is not actually stored as part of the
855 // property, hence we use generated code throughout this function instead of
856 // DefineObjectProperty() to modify its value.
857
858 // Step 3 - Special handling for length property.
859 if (p == "length") {
860 var length = obj.length;
861 if (!desc.hasValue()) {
862 return DefineObjectProperty(obj, "length", desc, should_throw);
863 }
864 var new_length = ToUint32(desc.getValue());
865 if (new_length != ToNumber(desc.getValue())) {
866 throw new $RangeError('defineProperty() array length out of range');
867 }
868 var length_desc = GetOwnProperty(obj, "length");
869 if (new_length != length && !length_desc.isWritable()) {
870 if (should_throw) {
871 throw MakeTypeError("redefine_disallowed", [p]);
872 } else {
873 return false;
874 }
875 }
876 var threw = false;
877 while (new_length < length--) {
878 if (!Delete(obj, ToString(length), false)) {
879 new_length = length + 1;
880 threw = true;
881 break;
882 }
883 }
884 // Make sure the below call to DefineObjectProperty() doesn't overwrite
885 // any magic "length" property by removing the value.
886 obj.length = new_length;
887 desc.value_ = void 0;
888 desc.hasValue_ = false;
889 if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) {
890 if (should_throw) {
891 throw MakeTypeError("redefine_disallowed", [p]);
892 } else {
893 return false;
894 }
895 }
896 return true;
897 }
898
899 // Step 4 - Special handling for array index.
900 var index = ToUint32(p);
901 if (index == ToNumber(p) && index != 4294967295) {
902 var length = obj.length;
903 var length_desc = GetOwnProperty(obj, "length");
904 if ((index >= length && !length_desc.isWritable()) ||
905 !DefineObjectProperty(obj, p, desc, true)) {
906 if (should_throw) {
907 throw MakeTypeError("define_disallowed", [p]);
908 } else {
909 return false;
910 }
911 }
912 if (index >= length) {
913 obj.length = index + 1;
914 }
915 return true;
916 }
917
918 // Step 5 - Fallback to default implementation.
919 return DefineObjectProperty(obj, p, desc, should_throw);
920}
921
922
923// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
924function DefineOwnProperty(obj, p, desc, should_throw) {
925 if (%IsJSProxy(obj)) {
926 var attributes = FromGenericPropertyDescriptor(desc);
927 return DefineProxyProperty(obj, p, attributes, should_throw);
928 } else if (IS_ARRAY(obj)) {
929 return DefineArrayProperty(obj, p, desc, should_throw);
930 } else {
931 return DefineObjectProperty(obj, p, desc, should_throw);
932 }
933}
934
935
Leon Clarkee46be812010-01-19 14:06:41 +0000936// ES5 section 15.2.3.2.
937function ObjectGetPrototypeOf(obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000938 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100939 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000940 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000941 return %GetPrototype(obj);
Leon Clarkee46be812010-01-19 14:06:41 +0000942}
943
944
Steve Block6ded16b2010-05-10 14:33:55 +0100945// ES5 section 15.2.3.3
Leon Clarkee46be812010-01-19 14:06:41 +0000946function ObjectGetOwnPropertyDescriptor(obj, p) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000947 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100948 throw MakeTypeError("called_on_non_object",
949 ["Object.getOwnPropertyDescriptor"]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000950 }
Leon Clarkee46be812010-01-19 14:06:41 +0000951 var desc = GetOwnProperty(obj, p);
952 return FromPropertyDescriptor(desc);
953}
954
955
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000956// For Harmony proxies
957function ToStringArray(obj, trap) {
958 if (!IS_SPEC_OBJECT(obj)) {
959 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
960 }
961 var n = ToUint32(obj.length);
962 var array = new $Array(n);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000963 var names = {}; // TODO(rossberg): use sets once they are ready.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000964 for (var index = 0; index < n; index++) {
965 var s = ToString(obj[index]);
966 if (s in names) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000967 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000968 }
969 array[index] = s;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000970 names[s] = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000971 }
972 return array;
973}
974
975
Leon Clarkee46be812010-01-19 14:06:41 +0000976// ES5 section 15.2.3.4.
977function ObjectGetOwnPropertyNames(obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000978 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100979 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000980 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000981 // Special handling for proxies.
982 if (%IsJSProxy(obj)) {
983 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000984 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000985 return ToStringArray(names, "getOwnPropertyNames");
986 }
987
Leon Clarkee46be812010-01-19 14:06:41 +0000988 // Find all the indexed properties.
989
990 // Get the local element names.
991 var propertyNames = %GetLocalElementNames(obj);
992
993 // Get names for indexed interceptor properties.
994 if (%GetInterceptorInfo(obj) & 1) {
995 var indexedInterceptorNames =
996 %GetIndexedInterceptorElementNames(obj);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000997 if (indexedInterceptorNames) {
Leon Clarkee46be812010-01-19 14:06:41 +0000998 propertyNames = propertyNames.concat(indexedInterceptorNames);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000999 }
Leon Clarkee46be812010-01-19 14:06:41 +00001000 }
1001
1002 // Find all the named properties.
1003
1004 // Get the local property names.
1005 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
1006
1007 // Get names for named interceptor properties if any.
1008
1009 if (%GetInterceptorInfo(obj) & 2) {
1010 var namedInterceptorNames =
1011 %GetNamedInterceptorPropertyNames(obj);
1012 if (namedInterceptorNames) {
1013 propertyNames = propertyNames.concat(namedInterceptorNames);
1014 }
1015 }
1016
Steve Block8defd9f2010-07-08 12:39:36 +01001017 // Property names are expected to be unique strings.
1018 var propertySet = {};
1019 var j = 0;
1020 for (var i = 0; i < propertyNames.length; ++i) {
1021 var name = ToString(propertyNames[i]);
1022 // We need to check for the exact property value since for intrinsic
1023 // properties like toString if(propertySet["toString"]) will always
1024 // succeed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001025 if (propertySet[name] === true) {
Steve Block8defd9f2010-07-08 12:39:36 +01001026 continue;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001027 }
Steve Block8defd9f2010-07-08 12:39:36 +01001028 propertySet[name] = true;
1029 propertyNames[j++] = name;
1030 }
1031 propertyNames.length = j;
Andrei Popescu402d9372010-02-26 13:31:12 +00001032
Leon Clarkee46be812010-01-19 14:06:41 +00001033 return propertyNames;
1034}
1035
1036
1037// ES5 section 15.2.3.5.
1038function ObjectCreate(proto, properties) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001039 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
Leon Clarkee46be812010-01-19 14:06:41 +00001040 throw MakeTypeError("proto_object_or_null", [proto]);
1041 }
1042 var obj = new $Object();
1043 obj.__proto__ = proto;
1044 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1045 return obj;
1046}
1047
1048
Andrei Popescu31002712010-02-23 13:46:05 +00001049// ES5 section 15.2.3.6.
1050function ObjectDefineProperty(obj, p, attributes) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001051 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001052 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
Leon Clarkef7060e22010-06-03 12:02:55 +01001053 }
Andrei Popescu31002712010-02-23 13:46:05 +00001054 var name = ToString(p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001055 if (%IsJSProxy(obj)) {
1056 // Clone the attributes object for protection.
1057 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1058 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
Ben Murdoch589d6972011-11-30 16:04:58 +00001059 var attributesClone = {};
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001060 for (var a in attributes) {
1061 attributesClone[a] = attributes[a];
1062 }
1063 DefineProxyProperty(obj, name, attributesClone, true);
1064 // The following would implement the spec as in the current proposal,
1065 // but after recent comments on es-discuss, is most likely obsolete.
1066 /*
1067 var defineObj = FromGenericPropertyDescriptor(desc);
1068 var names = ObjectGetOwnPropertyNames(attributes);
1069 var standardNames =
1070 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1071 for (var i = 0; i < names.length; i++) {
1072 var N = names[i];
1073 if (!(%HasLocalProperty(standardNames, N))) {
1074 var attr = GetOwnProperty(attributes, N);
1075 DefineOwnProperty(descObj, N, attr, true);
1076 }
1077 }
1078 // This is really confusing the types, but it is what the proxies spec
1079 // currently requires:
1080 desc = descObj;
1081 */
1082 } else {
1083 var desc = ToPropertyDescriptor(attributes);
1084 DefineOwnProperty(obj, name, desc, true);
1085 }
Andrei Popescu31002712010-02-23 13:46:05 +00001086 return obj;
1087}
1088
1089
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001090function GetOwnEnumerablePropertyNames(properties) {
1091 var names = new InternalArray();
1092 for (var key in properties) {
1093 if (%HasLocalProperty(properties, key)) {
1094 names.push(key);
1095 }
1096 }
1097 return names;
1098}
1099
1100
Andrei Popescu31002712010-02-23 13:46:05 +00001101// ES5 section 15.2.3.7.
Leon Clarkee46be812010-01-19 14:06:41 +00001102function ObjectDefineProperties(obj, properties) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001103 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001104 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001105 }
Leon Clarkee46be812010-01-19 14:06:41 +00001106 var props = ToObject(properties);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001107 var names = GetOwnEnumerablePropertyNames(props);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001108 var descriptors = new InternalArray();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001109 for (var i = 0; i < names.length; i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001110 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1111 }
1112 for (var i = 0; i < names.length; i++) {
1113 DefineOwnProperty(obj, names[i], descriptors[i], true);
Leon Clarkee46be812010-01-19 14:06:41 +00001114 }
Andrei Popescu31002712010-02-23 13:46:05 +00001115 return obj;
Leon Clarkee46be812010-01-19 14:06:41 +00001116}
1117
1118
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001119// Harmony proxies.
1120function ProxyFix(obj) {
1121 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001122 var props = CallTrap0(handler, "fix", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001123 if (IS_UNDEFINED(props)) {
1124 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1125 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001126
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001127 if (%IsJSFunctionProxy(obj)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001128 var callTrap = %GetCallTrap(obj);
1129 var constructTrap = %GetConstructTrap(obj);
1130 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1131 %Fix(obj); // becomes a regular function
1132 %SetCode(obj, code);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001133 // TODO(rossberg): What about length and other properties? Not specified.
1134 // We just put in some half-reasonable defaults for now.
1135 var prototype = new $Object();
1136 $Object.defineProperty(prototype, "constructor",
1137 {value: obj, writable: true, enumerable: false, configurable: true});
1138 // TODO(v8:1530): defineProperty does not handle prototype and length.
1139 %FunctionSetPrototype(obj, prototype);
1140 obj.length = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00001141 } else {
1142 %Fix(obj);
1143 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001144 ObjectDefineProperties(obj, props);
1145}
1146
1147
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001148// ES5 section 15.2.3.8.
1149function ObjectSeal(obj) {
1150 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001151 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001152 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001153 if (%IsJSProxy(obj)) {
1154 ProxyFix(obj);
1155 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001156 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001157 for (var i = 0; i < names.length; i++) {
1158 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001159 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001160 if (desc.isConfigurable()) {
1161 desc.setConfigurable(false);
1162 DefineOwnProperty(obj, name, desc, true);
1163 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001164 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001165 %PreventExtensions(obj);
1166 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001167}
1168
1169
1170// ES5 section 15.2.3.9.
1171function ObjectFreeze(obj) {
1172 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001173 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001174 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001175 if (%IsJSProxy(obj)) {
1176 ProxyFix(obj);
1177 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001178 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001179 for (var i = 0; i < names.length; i++) {
1180 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001181 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001182 if (desc.isWritable() || desc.isConfigurable()) {
1183 if (IsDataDescriptor(desc)) desc.setWritable(false);
1184 desc.setConfigurable(false);
1185 DefineOwnProperty(obj, name, desc, true);
1186 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001187 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001188 %PreventExtensions(obj);
1189 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001190}
1191
1192
Steve Block8defd9f2010-07-08 12:39:36 +01001193// ES5 section 15.2.3.10
1194function ObjectPreventExtension(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001195 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001196 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
Steve Block8defd9f2010-07-08 12:39:36 +01001197 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001198 if (%IsJSProxy(obj)) {
1199 ProxyFix(obj);
1200 }
Steve Block8defd9f2010-07-08 12:39:36 +01001201 %PreventExtensions(obj);
1202 return obj;
1203}
1204
1205
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001206// ES5 section 15.2.3.11
1207function ObjectIsSealed(obj) {
1208 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001209 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001210 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001211 if (%IsJSProxy(obj)) {
1212 return false;
1213 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001214 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001215 for (var i = 0; i < names.length; i++) {
1216 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001217 var desc = GetOwnProperty(obj, name);
1218 if (desc.isConfigurable()) return false;
1219 }
1220 if (!ObjectIsExtensible(obj)) {
1221 return true;
1222 }
1223 return false;
1224}
1225
1226
1227// ES5 section 15.2.3.12
1228function ObjectIsFrozen(obj) {
1229 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001230 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001231 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001232 if (%IsJSProxy(obj)) {
1233 return false;
1234 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001235 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001236 for (var i = 0; i < names.length; i++) {
1237 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001238 var desc = GetOwnProperty(obj, name);
1239 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1240 if (desc.isConfigurable()) return false;
1241 }
1242 if (!ObjectIsExtensible(obj)) {
1243 return true;
1244 }
1245 return false;
1246}
1247
1248
Steve Block8defd9f2010-07-08 12:39:36 +01001249// ES5 section 15.2.3.13
1250function ObjectIsExtensible(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001251 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001252 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001253 }
1254 if (%IsJSProxy(obj)) {
1255 return true;
Steve Block8defd9f2010-07-08 12:39:36 +01001256 }
1257 return %IsExtensible(obj);
1258}
1259
1260
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001261// Harmony egal.
1262function ObjectIs(obj1, obj2) {
1263 if (obj1 === obj2) {
1264 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1265 } else {
1266 return (obj1 !== obj1) && (obj2 !== obj2);
1267 }
1268}
1269
1270
Steve Blocka7e24c12009-10-30 11:49:00 +00001271%SetCode($Object, function(x) {
1272 if (%_IsConstructCall()) {
1273 if (x == null) return this;
1274 return ToObject(x);
1275 } else {
1276 if (x == null) return { };
1277 return ToObject(x);
1278 }
1279});
1280
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001281%SetExpectedNumberOfProperties($Object, 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001282
1283// ----------------------------------------------------------------------------
Ben Murdoch589d6972011-11-30 16:04:58 +00001284// Object
Steve Blocka7e24c12009-10-30 11:49:00 +00001285
Ben Murdoch589d6972011-11-30 16:04:58 +00001286function SetUpObject() {
1287 %CheckIsBootstrapping();
1288 // Set Up non-enumerable functions on the Object.prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1290 "toString", ObjectToString,
1291 "toLocaleString", ObjectToLocaleString,
1292 "valueOf", ObjectValueOf,
1293 "hasOwnProperty", ObjectHasOwnProperty,
1294 "isPrototypeOf", ObjectIsPrototypeOf,
1295 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1296 "__defineGetter__", ObjectDefineGetter,
1297 "__lookupGetter__", ObjectLookupGetter,
1298 "__defineSetter__", ObjectDefineSetter,
1299 "__lookupSetter__", ObjectLookupSetter
1300 ));
1301 InstallFunctions($Object, DONT_ENUM, $Array(
Leon Clarkee46be812010-01-19 14:06:41 +00001302 "keys", ObjectKeys,
1303 "create", ObjectCreate,
Andrei Popescu31002712010-02-23 13:46:05 +00001304 "defineProperty", ObjectDefineProperty,
1305 "defineProperties", ObjectDefineProperties,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001306 "freeze", ObjectFreeze,
Leon Clarkee46be812010-01-19 14:06:41 +00001307 "getPrototypeOf", ObjectGetPrototypeOf,
1308 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
Steve Block8defd9f2010-07-08 12:39:36 +01001309 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001310 "is", ObjectIs,
Steve Block8defd9f2010-07-08 12:39:36 +01001311 "isExtensible", ObjectIsExtensible,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001312 "isFrozen", ObjectIsFrozen,
1313 "isSealed", ObjectIsSealed,
1314 "preventExtensions", ObjectPreventExtension,
1315 "seal", ObjectSeal
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 ));
1317}
1318
Ben Murdoch589d6972011-11-30 16:04:58 +00001319SetUpObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00001320
1321// ----------------------------------------------------------------------------
1322// Boolean
1323
1324function BooleanToString() {
1325 // NOTE: Both Boolean objects and values can enter here as
1326 // 'this'. This is not as dictated by ECMA-262.
Ben Murdoch086aeea2011-05-13 15:57:08 +01001327 var b = this;
1328 if (!IS_BOOLEAN(b)) {
1329 if (!IS_BOOLEAN_WRAPPER(b)) {
1330 throw new $TypeError('Boolean.prototype.toString is not generic');
1331 }
1332 b = %_ValueOf(b);
1333 }
1334 return b ? 'true' : 'false';
Steve Blocka7e24c12009-10-30 11:49:00 +00001335}
1336
1337
1338function BooleanValueOf() {
1339 // NOTE: Both Boolean objects and values can enter here as
1340 // 'this'. This is not as dictated by ECMA-262.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001341 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001342 throw new $TypeError('Boolean.prototype.valueOf is not generic');
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001343 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001344 return %_ValueOf(this);
1345}
1346
1347
Steve Blocka7e24c12009-10-30 11:49:00 +00001348// ----------------------------------------------------------------------------
1349
1350
Ben Murdoch589d6972011-11-30 16:04:58 +00001351function SetUpBoolean () {
1352 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1354 "toString", BooleanToString,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001355 "valueOf", BooleanValueOf
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 ));
1357}
1358
Ben Murdoch589d6972011-11-30 16:04:58 +00001359SetUpBoolean();
1360
Steve Blocka7e24c12009-10-30 11:49:00 +00001361
1362// ----------------------------------------------------------------------------
1363// Number
1364
1365// Set the Number function and constructor.
1366%SetCode($Number, function(x) {
1367 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1368 if (%_IsConstructCall()) {
1369 %_SetValueOf(this, value);
1370 } else {
1371 return value;
1372 }
1373});
1374
1375%FunctionSetPrototype($Number, new $Number(0));
1376
1377// ECMA-262 section 15.7.4.2.
1378function NumberToString(radix) {
1379 // NOTE: Both Number objects and values can enter here as
1380 // 'this'. This is not as dictated by ECMA-262.
1381 var number = this;
1382 if (!IS_NUMBER(this)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001383 if (!IS_NUMBER_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001384 throw new $TypeError('Number.prototype.toString is not generic');
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001385 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001386 // Get the value of this number in case it's an object.
1387 number = %_ValueOf(this);
1388 }
1389 // Fast case: Convert number in radix 10.
1390 if (IS_UNDEFINED(radix) || radix === 10) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001391 return %_NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 }
1393
1394 // Convert the radix to an integer and check the range.
1395 radix = TO_INTEGER(radix);
1396 if (radix < 2 || radix > 36) {
1397 throw new $RangeError('toString() radix argument must be between 2 and 36');
1398 }
1399 // Convert the number to a string in the given radix.
1400 return %NumberToRadixString(number, radix);
1401}
1402
1403
1404// ECMA-262 section 15.7.4.3
1405function NumberToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001406 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1407 throw MakeTypeError("called_on_null_or_undefined",
1408 ["Number.prototype.toLocaleString"]);
1409 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001410 return this.toString();
1411}
1412
1413
1414// ECMA-262 section 15.7.4.4
1415function NumberValueOf() {
1416 // NOTE: Both Number objects and values can enter here as
1417 // 'this'. This is not as dictated by ECMA-262.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001418 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001419 throw new $TypeError('Number.prototype.valueOf is not generic');
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001420 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001421 return %_ValueOf(this);
1422}
1423
1424
1425// ECMA-262 section 15.7.4.5
1426function NumberToFixed(fractionDigits) {
1427 var f = TO_INTEGER(fractionDigits);
1428 if (f < 0 || f > 20) {
1429 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1430 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001431 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1432 throw MakeTypeError("called_on_null_or_undefined",
1433 ["Number.prototype.toFixed"]);
1434 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 var x = ToNumber(this);
1436 return %NumberToFixed(x, f);
1437}
1438
1439
1440// ECMA-262 section 15.7.4.6
1441function NumberToExponential(fractionDigits) {
1442 var f = -1;
1443 if (!IS_UNDEFINED(fractionDigits)) {
1444 f = TO_INTEGER(fractionDigits);
1445 if (f < 0 || f > 20) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001446 throw new $RangeError(
1447 "toExponential() argument must be between 0 and 20");
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 }
1449 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001450 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1451 throw MakeTypeError("called_on_null_or_undefined",
1452 ["Number.prototype.toExponential"]);
1453 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001454 var x = ToNumber(this);
1455 return %NumberToExponential(x, f);
1456}
1457
1458
1459// ECMA-262 section 15.7.4.7
1460function NumberToPrecision(precision) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001461 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1462 throw MakeTypeError("called_on_null_or_undefined",
1463 ["Number.prototype.toPrecision"]);
1464 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1466 var p = TO_INTEGER(precision);
1467 if (p < 1 || p > 21) {
1468 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1469 }
1470 var x = ToNumber(this);
1471 return %NumberToPrecision(x, p);
1472}
1473
1474
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001475// Harmony isFinite.
1476function NumberIsFinite(number) {
1477 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1478}
1479
1480
1481// Harmony isNaN.
1482function NumberIsNaN(number) {
1483 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1484}
1485
1486
Steve Blocka7e24c12009-10-30 11:49:00 +00001487// ----------------------------------------------------------------------------
1488
Ben Murdoch589d6972011-11-30 16:04:58 +00001489function SetUpNumber() {
1490 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001491 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
Ben Murdoch589d6972011-11-30 16:04:58 +00001492 // Set up the constructor property on the Number prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1494
1495 %OptimizeObjectForAddingMultipleProperties($Number, 5);
1496 // ECMA-262 section 15.7.3.1.
1497 %SetProperty($Number,
1498 "MAX_VALUE",
1499 1.7976931348623157e+308,
1500 DONT_ENUM | DONT_DELETE | READ_ONLY);
1501
1502 // ECMA-262 section 15.7.3.2.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001503 %SetProperty($Number, "MIN_VALUE", 5e-324,
1504 DONT_ENUM | DONT_DELETE | READ_ONLY);
Steve Blocka7e24c12009-10-30 11:49:00 +00001505
1506 // ECMA-262 section 15.7.3.3.
1507 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1508
1509 // ECMA-262 section 15.7.3.4.
1510 %SetProperty($Number,
1511 "NEGATIVE_INFINITY",
1512 -1/0,
1513 DONT_ENUM | DONT_DELETE | READ_ONLY);
1514
1515 // ECMA-262 section 15.7.3.5.
1516 %SetProperty($Number,
1517 "POSITIVE_INFINITY",
1518 1/0,
1519 DONT_ENUM | DONT_DELETE | READ_ONLY);
Andrei Popescu402d9372010-02-26 13:31:12 +00001520 %ToFastProperties($Number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001521
Ben Murdoch589d6972011-11-30 16:04:58 +00001522 // Set up non-enumerable functions on the Number prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001523 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1524 "toString", NumberToString,
1525 "toLocaleString", NumberToLocaleString,
1526 "valueOf", NumberValueOf,
1527 "toFixed", NumberToFixed,
1528 "toExponential", NumberToExponential,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001529 "toPrecision", NumberToPrecision
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 ));
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001531 InstallFunctions($Number, DONT_ENUM, $Array(
1532 "isFinite", NumberIsFinite,
1533 "isNaN", NumberIsNaN
1534 ));
Steve Blocka7e24c12009-10-30 11:49:00 +00001535}
1536
Ben Murdoch589d6972011-11-30 16:04:58 +00001537SetUpNumber();
Steve Blocka7e24c12009-10-30 11:49:00 +00001538
1539
Steve Blocka7e24c12009-10-30 11:49:00 +00001540// ----------------------------------------------------------------------------
1541// Function
1542
1543$Function.prototype.constructor = $Function;
1544
1545function FunctionSourceString(func) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001546 while (%IsJSFunctionProxy(func)) {
1547 func = %GetCallTrap(func);
1548 }
1549
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 if (!IS_FUNCTION(func)) {
1551 throw new $TypeError('Function.prototype.toString is not generic');
1552 }
1553
1554 var source = %FunctionGetSourceCode(func);
1555 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1556 var name = %FunctionGetName(func);
1557 if (name) {
1558 // Mimic what KJS does.
1559 return 'function ' + name + '() { [native code] }';
1560 } else {
1561 return 'function () { [native code] }';
1562 }
1563 }
1564
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001565 var name = %FunctionNameShouldPrintAsAnonymous(func)
1566 ? 'anonymous'
1567 : %FunctionGetName(func);
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 return 'function ' + name + source;
1569}
1570
1571
1572function FunctionToString() {
1573 return FunctionSourceString(this);
1574}
1575
1576
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001577// ES5 15.3.4.5
1578function FunctionBind(this_arg) { // Length is 1.
Ben Murdoch589d6972011-11-30 16:04:58 +00001579 if (!IS_SPEC_FUNCTION(this)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001580 throw new $TypeError('Bind must be called on a function');
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001581 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001582 var boundFunction = function () {
1583 // Poison .arguments and .caller, but is otherwise not detectable.
1584 "use strict";
1585 // This function must not use any object literals (Object, Array, RegExp),
1586 // since the literals-array is being used to store the bound data.
1587 if (%_IsConstructCall()) {
1588 return %NewObjectFromBound(boundFunction);
Ben Murdochf87a2032010-10-22 12:50:53 +01001589 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001590 var bindings = %BoundFunctionGetBindings(boundFunction);
Steve Block1e0659c2011-05-24 12:43:12 +01001591
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001592 var argc = %_ArgumentsLength();
1593 if (argc == 0) {
1594 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1595 }
1596 if (bindings.length === 2) {
1597 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1598 }
1599 var bound_argc = bindings.length - 2;
1600 var argv = new InternalArray(bound_argc + argc);
1601 for (var i = 0; i < bound_argc; i++) {
1602 argv[i] = bindings[i + 2];
1603 }
1604 for (var j = 0; j < argc; j++) {
1605 argv[i++] = %_Arguments(j);
1606 }
1607 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1608 };
Steve Block1e0659c2011-05-24 12:43:12 +01001609
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001610 %FunctionRemovePrototype(boundFunction);
1611 var new_length = 0;
1612 if (%_ClassOf(this) == "Function") {
1613 // Function or FunctionProxy.
1614 var old_length = this.length;
1615 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1616 if ((typeof old_length === "number") &&
1617 ((old_length >>> 0) === old_length)) {
Steve Block1e0659c2011-05-24 12:43:12 +01001618 var argc = %_ArgumentsLength();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001619 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1620 new_length = old_length - argc;
1621 if (new_length < 0) new_length = 0;
1622 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001623 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001624 // This runtime function finds any remaining arguments on the stack,
1625 // so we don't pass the arguments object.
1626 var result = %FunctionBindArguments(boundFunction, this,
1627 this_arg, new_length);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001628
1629 // We already have caller and arguments properties on functions,
1630 // which are non-configurable. It therefore makes no sence to
1631 // try to redefine these as defined by the spec. The spec says
1632 // that bind should make these throw a TypeError if get or set
1633 // is called and make them non-enumerable and non-configurable.
Ben Murdochf87a2032010-10-22 12:50:53 +01001634 // To be consistent with our normal functions we leave this as it is.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001635 // TODO(lrn): Do set these to be thrower.
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001636 return result;
1637}
1638
1639
Steve Blocka7e24c12009-10-30 11:49:00 +00001640function NewFunction(arg1) { // length == 1
1641 var n = %_ArgumentsLength();
1642 var p = '';
1643 if (n > 1) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001644 p = new InternalArray(n - 1);
Ben Murdoch086aeea2011-05-13 15:57:08 +01001645 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1646 p = Join(p, n - 1, ',', NonStringToString);
Steve Blocka7e24c12009-10-30 11:49:00 +00001647 // If the formal parameters string include ) - an illegal
1648 // character - it may make the combined function expression
1649 // compile. We avoid this problem by checking for this early on.
1650 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1651 }
1652 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
1653 var source = '(function(' + p + ') {\n' + body + '\n})';
1654
1655 // The call to SetNewFunctionAttributes will ensure the prototype
1656 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001657 var f = %CompileString(source)();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001658 %FunctionMarkNameShouldPrintAsAnonymous(f);
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 return %SetNewFunctionAttributes(f);
1660}
1661
1662%SetCode($Function, NewFunction);
1663
1664// ----------------------------------------------------------------------------
1665
Ben Murdoch589d6972011-11-30 16:04:58 +00001666function SetUpFunction() {
1667 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001668 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001669 "bind", FunctionBind,
Steve Blocka7e24c12009-10-30 11:49:00 +00001670 "toString", FunctionToString
1671 ));
1672}
1673
Ben Murdoch589d6972011-11-30 16:04:58 +00001674SetUpFunction();