blob: 588bdb21bb0765d5297efca325bfdf1dcf1055bb [file] [log] [blame]
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001// Copyright 2011 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:
31// const $Object = global.Object;
32// const $Boolean = global.Boolean;
33// const $Number = global.Number;
34// const $Function = global.Function;
35// const $Array = global.Array;
36// const $NaN = 0/0;
37//
38// in math.js:
39// const $floor = MathFloor
40
41const $isNaN = GlobalIsNaN;
42const $isFinite = GlobalIsFinite;
43
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
63// Emulates JSC by installing functions on a hidden prototype that
64// lies above the current object/prototype. This lets you override
65// functions on String.prototype etc. and then restore the old function
66// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
67function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
Ben Murdoch589d6972011-11-30 16:04:58 +000068 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +000069 var hidden_prototype = new $Object();
70 %SetHiddenPrototype(object, hidden_prototype);
71 InstallFunctions(hidden_prototype, attributes, functions);
72}
73
74
Ben Murdoch589d6972011-11-30 16:04:58 +000075// Prevents changes to the prototype of a built-infunction.
76// The "prototype" property of the function object is made non-configurable,
77// and the prototype object is made non-extensible. The latter prevents
78// changing the __proto__ property.
79function SetUpLockedPrototype(constructor, fields, methods) {
80 %CheckIsBootstrapping();
81 var prototype = constructor.prototype;
82 // Install functions first, because this function is used to initialize
83 // PropertyDescriptor itself.
84 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
85 if (property_count >= 4) {
86 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
87 }
88 if (fields) {
89 for (var i = 0; i < fields.length; i++) {
90 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
91 }
92 }
93 for (var i = 0; i < methods.length; i += 2) {
94 var key = methods[i];
95 var f = methods[i + 1];
96 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
97 %SetNativeFlag(f);
98 }
99 prototype.__proto__ = null;
100 %ToFastProperties(prototype);
101}
102
103
Steve Blocka7e24c12009-10-30 11:49:00 +0000104// ----------------------------------------------------------------------------
105
106
107// ECMA 262 - 15.1.4
108function GlobalIsNaN(number) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000109 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
110 return NUMBER_IS_NAN(number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000111}
112
113
114// ECMA 262 - 15.1.5
115function GlobalIsFinite(number) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100116 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
Ben Murdoch589d6972011-11-30 16:04:58 +0000117 return NUMBER_IS_FINITE(number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000118}
119
120
121// ECMA-262 - 15.1.2.2
122function GlobalParseInt(string, radix) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100123 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 // Some people use parseInt instead of Math.floor. This
125 // optimization makes parseInt on a Smi 12 times faster (60ns
126 // vs 800ns). The following optimization makes parseInt on a
127 // non-Smi number 9 times faster (230ns vs 2070ns). Together
128 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
129 if (%_IsSmi(string)) return string;
130 if (IS_NUMBER(string) &&
Steve Blockd0582a62009-12-15 09:54:21 +0000131 ((0.01 < string && string < 1e9) ||
132 (-1e9 < string && string < -0.01))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 // Truncate number.
134 return string | 0;
135 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000136 string = TO_STRING_INLINE(string);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000137 radix = radix | 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000139 // The spec says ToString should be evaluated before ToInt32.
140 string = TO_STRING_INLINE(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 radix = TO_INT32(radix);
142 if (!(radix == 0 || (2 <= radix && radix <= 36)))
143 return $NaN;
144 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000145
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100146 if (%_HasCachedArrayIndex(string) &&
147 (radix == 0 || radix == 10)) {
148 return %_GetCachedArrayIndex(string);
149 }
150 return %StringParseInt(string, radix);
Steve Blocka7e24c12009-10-30 11:49:00 +0000151}
152
153
154// ECMA-262 - 15.1.2.3
155function GlobalParseFloat(string) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100156 string = TO_STRING_INLINE(string);
157 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
158 return %StringParseFloat(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000159}
160
161
162function GlobalEval(x) {
163 if (!IS_STRING(x)) return x;
164
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000165 var receiver = this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 var global_receiver = %GlobalReceiver(global);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000167
168 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
169 receiver = global_receiver;
170 }
171
172 var this_is_global_receiver = (receiver === global_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 var global_is_detached = (global === global_receiver);
174
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000175 // For consistency with JSC we require the global object passed to
176 // eval to be the global object from which 'eval' originated. This
177 // is not mandated by the spec.
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 if (!this_is_global_receiver || global_is_detached) {
179 throw new $EvalError('The "this" object passed to eval must ' +
180 'be the global object from which eval originated');
181 }
182
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800183 var f = %CompileString(x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000184 if (!IS_FUNCTION(f)) return f;
185
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000186 return %_CallFunction(receiver, f);
Steve Blocka7e24c12009-10-30 11:49:00 +0000187}
188
189
Steve Blocka7e24c12009-10-30 11:49:00 +0000190// ----------------------------------------------------------------------------
191
Ben Murdoch589d6972011-11-30 16:04:58 +0000192// Set up global object.
193function SetUpGlobal() {
194 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 // ECMA 262 - 15.1.1.1.
196 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
197
198 // ECMA-262 - 15.1.1.2.
199 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
200
201 // ECMA-262 - 15.1.1.3.
202 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
203
Ben Murdoch589d6972011-11-30 16:04:58 +0000204 // Set up non-enumerable function on the global object.
Steve Blocka7e24c12009-10-30 11:49:00 +0000205 InstallFunctions(global, DONT_ENUM, $Array(
206 "isNaN", GlobalIsNaN,
207 "isFinite", GlobalIsFinite,
208 "parseInt", GlobalParseInt,
209 "parseFloat", GlobalParseFloat,
Steve Block053d10c2011-06-13 19:13:29 +0100210 "eval", GlobalEval
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 ));
212}
213
Ben Murdoch589d6972011-11-30 16:04:58 +0000214SetUpGlobal();
Steve Blocka7e24c12009-10-30 11:49:00 +0000215
216// ----------------------------------------------------------------------------
217// Boolean (first part of definition)
218
219
220%SetCode($Boolean, function(x) {
221 if (%_IsConstructCall()) {
222 %_SetValueOf(this, ToBoolean(x));
223 } else {
224 return ToBoolean(x);
225 }
226});
227
228%FunctionSetPrototype($Boolean, new $Boolean(false));
229
230%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
231
232// ----------------------------------------------------------------------------
233// Object
234
235$Object.prototype.constructor = $Object;
236
237// ECMA-262 - 15.2.4.2
238function ObjectToString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000239 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
240 return '[object Undefined]';
241 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000242 if (IS_NULL(this)) return '[object Null]';
Leon Clarked91b9f72010-01-27 17:25:45 +0000243 return "[object " + %_ClassOf(ToObject(this)) + "]";
Steve Blocka7e24c12009-10-30 11:49:00 +0000244}
245
246
247// ECMA-262 - 15.2.4.3
248function ObjectToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000249 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
250 throw MakeTypeError("called_on_null_or_undefined",
251 ["Object.prototype.toLocaleString"]);
252 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000253 return this.toString();
254}
255
256
257// ECMA-262 - 15.2.4.4
258function ObjectValueOf() {
Leon Clarked91b9f72010-01-27 17:25:45 +0000259 return ToObject(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000260}
261
262
263// ECMA-262 - 15.2.4.5
264function ObjectHasOwnProperty(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000265 if (%IsJSProxy(this)) {
266 var handler = %GetHandler(this);
267 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
268 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000269 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
Steve Blocka7e24c12009-10-30 11:49:00 +0000270}
271
272
273// ECMA-262 - 15.2.4.6
274function ObjectIsPrototypeOf(V) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000275 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
276 throw MakeTypeError("called_on_null_or_undefined",
277 ["Object.prototype.isPrototypeOf"]);
278 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100279 if (!IS_SPEC_OBJECT(V)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 return %IsInPrototypeChain(this, V);
281}
282
283
284// ECMA-262 - 15.2.4.6
285function ObjectPropertyIsEnumerable(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000286 var P = ToString(V);
287 if (%IsJSProxy(this)) {
288 var desc = GetOwnProperty(this, P);
289 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
290 }
291 return %IsPropertyEnumerable(ToObject(this), P);
Steve Blocka7e24c12009-10-30 11:49:00 +0000292}
293
294
295// Extensions for providing property getters and setters.
296function ObjectDefineGetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000297 var receiver = this;
298 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
299 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000301 if (!IS_SPEC_FUNCTION(fun)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
303 }
Steve Block44f0eee2011-05-26 01:26:41 +0100304 var desc = new PropertyDescriptor();
305 desc.setGet(fun);
306 desc.setEnumerable(true);
307 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000308 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000309}
310
311
312function ObjectLookupGetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000313 var receiver = this;
314 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
315 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000316 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000317 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000318}
319
320
321function ObjectDefineSetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000322 var receiver = this;
323 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
324 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000326 if (!IS_SPEC_FUNCTION(fun)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 throw new $TypeError(
328 'Object.prototype.__defineSetter__: Expecting function');
329 }
Steve Block44f0eee2011-05-26 01:26:41 +0100330 var desc = new PropertyDescriptor();
331 desc.setSet(fun);
332 desc.setEnumerable(true);
333 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000334 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000335}
336
337
338function ObjectLookupSetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000339 var receiver = this;
340 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
341 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000343 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000344}
345
346
347function ObjectKeys(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100348 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000349 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000350 if (%IsJSProxy(obj)) {
351 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000352 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000353 return ToStringArray(names);
354 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 return %LocalKeys(obj);
356}
357
358
Leon Clarkee46be812010-01-19 14:06:41 +0000359// ES5 8.10.1.
360function IsAccessorDescriptor(desc) {
361 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000362 return desc.hasGetter() || desc.hasSetter();
Leon Clarkee46be812010-01-19 14:06:41 +0000363}
364
365
366// ES5 8.10.2.
367function IsDataDescriptor(desc) {
368 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000369 return desc.hasValue() || desc.hasWritable();
Leon Clarkee46be812010-01-19 14:06:41 +0000370}
371
372
373// ES5 8.10.3.
374function IsGenericDescriptor(desc) {
375 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
376}
377
378
379function IsInconsistentDescriptor(desc) {
380 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
381}
382
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000383
Leon Clarkee46be812010-01-19 14:06:41 +0000384// ES5 8.10.4
385function FromPropertyDescriptor(desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000386 if (IS_UNDEFINED(desc)) return desc;
Ben Murdoch257744e2011-11-30 15:57:28 +0000387
Leon Clarkee46be812010-01-19 14:06:41 +0000388 if (IsDataDescriptor(desc)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000389 return { value: desc.getValue(),
390 writable: desc.isWritable(),
391 enumerable: desc.isEnumerable(),
392 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000393 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000394 // Must be an AccessorDescriptor then. We never return a generic descriptor.
395 return { get: desc.getGet(),
396 set: desc.getSet(),
397 enumerable: desc.isEnumerable(),
398 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000399}
400
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000401
402// Harmony Proxies
403function FromGenericPropertyDescriptor(desc) {
404 if (IS_UNDEFINED(desc)) return desc;
405 var obj = new $Object();
406
407 if (desc.hasValue()) {
408 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
409 }
410 if (desc.hasWritable()) {
411 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
412 }
413 if (desc.hasGetter()) {
414 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
415 }
416 if (desc.hasSetter()) {
417 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
418 }
419 if (desc.hasEnumerable()) {
420 %IgnoreAttributesAndSetProperty(obj, "enumerable",
421 desc.isEnumerable(), NONE);
422 }
423 if (desc.hasConfigurable()) {
424 %IgnoreAttributesAndSetProperty(obj, "configurable",
425 desc.isConfigurable(), NONE);
426 }
427 return obj;
428}
429
430
Leon Clarkee46be812010-01-19 14:06:41 +0000431// ES5 8.10.5.
432function ToPropertyDescriptor(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100433 if (!IS_SPEC_OBJECT(obj)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000434 throw MakeTypeError("property_desc_object", [obj]);
435 }
436 var desc = new PropertyDescriptor();
437
438 if ("enumerable" in obj) {
439 desc.setEnumerable(ToBoolean(obj.enumerable));
440 }
441
Leon Clarkee46be812010-01-19 14:06:41 +0000442 if ("configurable" in obj) {
443 desc.setConfigurable(ToBoolean(obj.configurable));
444 }
445
446 if ("value" in obj) {
447 desc.setValue(obj.value);
448 }
449
450 if ("writable" in obj) {
451 desc.setWritable(ToBoolean(obj.writable));
452 }
453
454 if ("get" in obj) {
455 var get = obj.get;
Ben Murdoch589d6972011-11-30 16:04:58 +0000456 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000457 throw MakeTypeError("getter_must_be_callable", [get]);
458 }
459 desc.setGet(get);
460 }
461
462 if ("set" in obj) {
463 var set = obj.set;
Ben Murdoch589d6972011-11-30 16:04:58 +0000464 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000465 throw MakeTypeError("setter_must_be_callable", [set]);
466 }
467 desc.setSet(set);
468 }
469
470 if (IsInconsistentDescriptor(desc)) {
471 throw MakeTypeError("value_and_accessor", [obj]);
472 }
473 return desc;
474}
475
476
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000477// For Harmony proxies.
478function ToCompletePropertyDescriptor(obj) {
479 var desc = ToPropertyDescriptor(obj)
480 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
481 if (!desc.hasValue()) desc.setValue(void 0);
482 if (!desc.hasWritable()) desc.setWritable(false);
483 } else {
484 // Is accessor descriptor.
485 if (!desc.hasGetter()) desc.setGet(void 0);
486 if (!desc.hasSetter()) desc.setSet(void 0);
487 }
488 if (!desc.hasEnumerable()) desc.setEnumerable(false);
489 if (!desc.hasConfigurable()) desc.setConfigurable(false);
490 return desc;
491}
492
493
Leon Clarkee46be812010-01-19 14:06:41 +0000494function PropertyDescriptor() {
495 // Initialize here so they are all in-object and have the same map.
496 // Default values from ES5 8.6.1.
497 this.value_ = void 0;
498 this.hasValue_ = false;
499 this.writable_ = false;
500 this.hasWritable_ = false;
501 this.enumerable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000502 this.hasEnumerable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000503 this.configurable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000504 this.hasConfigurable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000505 this.get_ = void 0;
506 this.hasGetter_ = false;
507 this.set_ = void 0;
508 this.hasSetter_ = false;
509}
510
Ben Murdoch589d6972011-11-30 16:04:58 +0000511SetUpLockedPrototype(PropertyDescriptor, $Array(
512 "value_",
513 "hasValue_",
514 "writable_",
515 "hasWritable_",
516 "enumerable_",
517 "hasEnumerable_",
518 "configurable_",
519 "hasConfigurable_",
520 "get_",
521 "hasGetter_",
522 "set_",
523 "hasSetter_"
524 ), $Array(
525 "toString", function() {
526 return "[object PropertyDescriptor]";
527 },
528 "setValue", function(value) {
529 this.value_ = value;
530 this.hasValue_ = true;
531 },
532 "getValue", function() {
533 return this.value_;
534 },
535 "hasValue", function() {
536 return this.hasValue_;
537 },
538 "setEnumerable", function(enumerable) {
539 this.enumerable_ = enumerable;
540 this.hasEnumerable_ = true;
541 },
542 "isEnumerable", function () {
543 return this.enumerable_;
544 },
545 "hasEnumerable", function() {
546 return this.hasEnumerable_;
547 },
548 "setWritable", function(writable) {
549 this.writable_ = writable;
550 this.hasWritable_ = true;
551 },
552 "isWritable", function() {
553 return this.writable_;
554 },
555 "hasWritable", function() {
556 return this.hasWritable_;
557 },
558 "setConfigurable", function(configurable) {
559 this.configurable_ = configurable;
560 this.hasConfigurable_ = true;
561 },
562 "hasConfigurable", function() {
563 return this.hasConfigurable_;
564 },
565 "isConfigurable", function() {
566 return this.configurable_;
567 },
568 "setGet", function(get) {
569 this.get_ = get;
570 this.hasGetter_ = true;
571 },
572 "getGet", function() {
573 return this.get_;
574 },
575 "hasGetter", function() {
576 return this.hasGetter_;
577 },
578 "setSet", function(set) {
579 this.set_ = set;
580 this.hasSetter_ = true;
581 },
582 "getSet", function() {
583 return this.set_;
584 },
585 "hasSetter", function() {
586 return this.hasSetter_;
587 }));
Andrei Popescu31002712010-02-23 13:46:05 +0000588
589
Steve Block1e0659c2011-05-24 12:43:12 +0100590// Converts an array returned from Runtime_GetOwnProperty to an actual
591// property descriptor. For a description of the array layout please
592// see the runtime.cc file.
593function ConvertDescriptorArrayToDescriptor(desc_array) {
Steve Block44f0eee2011-05-26 01:26:41 +0100594 if (desc_array === false) {
Steve Block1e0659c2011-05-24 12:43:12 +0100595 throw 'Internal error: invalid desc_array';
Steve Block103cc402011-02-16 13:27:44 +0000596 }
Steve Block1e0659c2011-05-24 12:43:12 +0100597
598 if (IS_UNDEFINED(desc_array)) {
599 return void 0;
600 }
601
602 var desc = new PropertyDescriptor();
603 // This is an accessor.
604 if (desc_array[IS_ACCESSOR_INDEX]) {
605 desc.setGet(desc_array[GETTER_INDEX]);
606 desc.setSet(desc_array[SETTER_INDEX]);
607 } else {
608 desc.setValue(desc_array[VALUE_INDEX]);
609 desc.setWritable(desc_array[WRITABLE_INDEX]);
610 }
611 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
612 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
Leon Clarkee46be812010-01-19 14:06:41 +0000613
614 return desc;
615}
616
617
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000618// For Harmony proxies.
619function GetTrap(handler, name, defaultTrap) {
620 var trap = handler[name];
621 if (IS_UNDEFINED(trap)) {
622 if (IS_UNDEFINED(defaultTrap)) {
623 throw MakeTypeError("handler_trap_missing", [handler, name]);
624 }
625 trap = defaultTrap;
Ben Murdoch589d6972011-11-30 16:04:58 +0000626 } else if (!IS_SPEC_FUNCTION(trap)) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000627 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
628 }
629 return trap;
630}
631
632
633function CallTrap0(handler, name, defaultTrap) {
634 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
635}
636
637
638function CallTrap1(handler, name, defaultTrap, x) {
639 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
640}
641
642
643function CallTrap2(handler, name, defaultTrap, x, y) {
644 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
645}
646
647
Steve Block1e0659c2011-05-24 12:43:12 +0100648// ES5 section 8.12.1.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000649function GetOwnProperty(obj, v) {
650 var p = ToString(v);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000651 if (%IsJSProxy(obj)) {
652 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000653 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000654 if (IS_UNDEFINED(descriptor)) return descriptor;
655 var desc = ToCompletePropertyDescriptor(descriptor);
656 if (!desc.isConfigurable()) {
657 throw MakeTypeError("proxy_prop_not_configurable",
658 [handler, "getOwnPropertyDescriptor", p, descriptor]);
659 }
660 return desc;
661 }
662
Steve Block1e0659c2011-05-24 12:43:12 +0100663 // GetOwnProperty returns an array indexed by the constants
664 // defined in macros.py.
665 // If p is not a property on obj undefined is returned.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000666 var props = %GetOwnProperty(ToObject(obj), ToString(v));
Steve Block1e0659c2011-05-24 12:43:12 +0100667
668 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100669 if (props === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100670
671 return ConvertDescriptorArrayToDescriptor(props);
672}
673
674
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000675// Harmony proxies.
676function DefineProxyProperty(obj, p, attributes, should_throw) {
677 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000678 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000679 if (!ToBoolean(result)) {
680 if (should_throw) {
681 throw MakeTypeError("handler_returned_false",
682 [handler, "defineProperty"]);
683 } else {
684 return false;
685 }
686 }
687 return true;
688}
689
690
Steve Block6ded16b2010-05-10 14:33:55 +0100691// ES5 8.12.9.
Leon Clarkee46be812010-01-19 14:06:41 +0000692function DefineOwnProperty(obj, p, desc, should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000693 if (%IsJSProxy(obj)) {
694 var attributes = FromGenericPropertyDescriptor(desc);
695 return DefineProxyProperty(obj, p, attributes, should_throw);
696 }
697
Steve Block1e0659c2011-05-24 12:43:12 +0100698 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
699 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100700 if (current_or_access === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100701
702 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
Andrei Popescu31002712010-02-23 13:46:05 +0000703 var extensible = %IsExtensible(ToObject(obj));
704
705 // Error handling according to spec.
706 // Step 3
Steve Block44f0eee2011-05-26 01:26:41 +0100707 if (IS_UNDEFINED(current) && !extensible) {
708 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000709 throw MakeTypeError("define_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100710 } else {
711 return;
712 }
713 }
Andrei Popescu31002712010-02-23 13:46:05 +0000714
Steve Block1e0659c2011-05-24 12:43:12 +0100715 if (!IS_UNDEFINED(current)) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100716 // Step 5 and 6
Steve Block1e0659c2011-05-24 12:43:12 +0100717 if ((IsGenericDescriptor(desc) ||
718 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
719 (!desc.hasEnumerable() ||
720 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100721 (!desc.hasConfigurable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100722 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100723 (!desc.hasWritable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100724 SameValue(desc.isWritable(), current.isWritable())) &&
725 (!desc.hasValue() ||
726 SameValue(desc.getValue(), current.getValue())) &&
727 (!desc.hasGetter() ||
728 SameValue(desc.getGet(), current.getGet())) &&
729 (!desc.hasSetter() ||
730 SameValue(desc.getSet(), current.getSet()))) {
731 return true;
732 }
Steve Block1e0659c2011-05-24 12:43:12 +0100733 if (!current.isConfigurable()) {
734 // Step 7
735 if (desc.isConfigurable() ||
736 (desc.hasEnumerable() &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100737 desc.isEnumerable() != current.isEnumerable())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100738 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000739 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100740 } else {
741 return;
742 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100743 }
Steve Block1e0659c2011-05-24 12:43:12 +0100744 // Step 8
745 if (!IsGenericDescriptor(desc)) {
746 // Step 9a
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100747 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100748 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000749 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100750 } else {
751 return;
752 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100753 }
Steve Block1e0659c2011-05-24 12:43:12 +0100754 // Step 10a
755 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100756 if (!current.isWritable() && desc.isWritable()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100757 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000758 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100759 } else {
760 return;
761 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100762 }
Steve Block1e0659c2011-05-24 12:43:12 +0100763 if (!current.isWritable() && desc.hasValue() &&
764 !SameValue(desc.getValue(), current.getValue())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100765 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000766 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100767 } else {
768 return;
769 }
Steve Block1e0659c2011-05-24 12:43:12 +0100770 }
771 }
772 // Step 11
773 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100774 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100775 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000776 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100777 } else {
778 return;
779 }
Steve Block1e0659c2011-05-24 12:43:12 +0100780 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100781 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100782 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000783 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100784 } else {
785 return;
786 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100787 }
Steve Block1e0659c2011-05-24 12:43:12 +0100788 }
Andrei Popescu31002712010-02-23 13:46:05 +0000789 }
790 }
Andrei Popescu31002712010-02-23 13:46:05 +0000791 }
792
Steve Block6ded16b2010-05-10 14:33:55 +0100793 // Send flags - enumerable and configurable are common - writable is
Andrei Popescu31002712010-02-23 13:46:05 +0000794 // only send to the data descriptor.
795 // Take special care if enumerable and configurable is not defined on
796 // desc (we need to preserve the existing values from current).
797 var flag = NONE;
798 if (desc.hasEnumerable()) {
799 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
800 } else if (!IS_UNDEFINED(current)) {
801 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
Leon Clarkee46be812010-01-19 14:06:41 +0000802 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000803 flag |= DONT_ENUM;
804 }
805
806 if (desc.hasConfigurable()) {
807 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
808 } else if (!IS_UNDEFINED(current)) {
809 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
810 } else
811 flag |= DONT_DELETE;
812
Steve Block1e0659c2011-05-24 12:43:12 +0100813 if (IsDataDescriptor(desc) ||
814 (IsGenericDescriptor(desc) &&
815 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
816 // There are 3 cases that lead here:
817 // Step 4a - defining a new data property.
818 // Steps 9b & 12 - replacing an existing accessor property with a data
819 // property.
820 // Step 12 - updating an existing data property with a data or generic
821 // descriptor.
822
Leon Clarkef7060e22010-06-03 12:02:55 +0100823 if (desc.hasWritable()) {
824 flag |= desc.isWritable() ? 0 : READ_ONLY;
825 } else if (!IS_UNDEFINED(current)) {
826 flag |= current.isWritable() ? 0 : READ_ONLY;
827 } else {
828 flag |= READ_ONLY;
829 }
Steve Block1e0659c2011-05-24 12:43:12 +0100830
Ben Murdochb0fe1622011-05-05 13:52:32 +0100831 var value = void 0; // Default value is undefined.
832 if (desc.hasValue()) {
833 value = desc.getValue();
Steve Block1e0659c2011-05-24 12:43:12 +0100834 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100835 value = current.getValue();
836 }
Steve Block1e0659c2011-05-24 12:43:12 +0100837
Ben Murdochb0fe1622011-05-05 13:52:32 +0100838 %DefineOrRedefineDataProperty(obj, p, value, flag);
Steve Block1e0659c2011-05-24 12:43:12 +0100839 } else if (IsGenericDescriptor(desc)) {
840 // Step 12 - updating an existing accessor property with generic
841 // descriptor. Changing flags only.
842 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
Andrei Popescu31002712010-02-23 13:46:05 +0000843 } else {
Steve Block1e0659c2011-05-24 12:43:12 +0100844 // There are 3 cases that lead here:
845 // Step 4b - defining a new accessor property.
846 // Steps 9c & 12 - replacing an existing data property with an accessor
847 // property.
848 // Step 12 - updating an existing accessor property with an accessor
849 // descriptor.
850 if (desc.hasGetter()) {
851 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
Andrei Popescu31002712010-02-23 13:46:05 +0000852 }
Steve Block1e0659c2011-05-24 12:43:12 +0100853 if (desc.hasSetter()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000854 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
855 }
Leon Clarkee46be812010-01-19 14:06:41 +0000856 }
857 return true;
858}
859
860
861// ES5 section 15.2.3.2.
862function ObjectGetPrototypeOf(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100863 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000864 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000865 return %GetPrototype(obj);
Leon Clarkee46be812010-01-19 14:06:41 +0000866}
867
868
Steve Block6ded16b2010-05-10 14:33:55 +0100869// ES5 section 15.2.3.3
Leon Clarkee46be812010-01-19 14:06:41 +0000870function ObjectGetOwnPropertyDescriptor(obj, p) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100871 if (!IS_SPEC_OBJECT(obj))
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000872 throw MakeTypeError("obj_ctor_property_non_object",
873 ["getOwnPropertyDescriptor"]);
Leon Clarkee46be812010-01-19 14:06:41 +0000874 var desc = GetOwnProperty(obj, p);
875 return FromPropertyDescriptor(desc);
876}
877
878
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000879// For Harmony proxies
880function ToStringArray(obj, trap) {
881 if (!IS_SPEC_OBJECT(obj)) {
882 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
883 }
884 var n = ToUint32(obj.length);
885 var array = new $Array(n);
886 var names = {}
887 for (var index = 0; index < n; index++) {
888 var s = ToString(obj[index]);
889 if (s in names) {
890 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
891 }
892 array[index] = s;
893 names.s = 0;
894 }
895 return array;
896}
897
898
Leon Clarkee46be812010-01-19 14:06:41 +0000899// ES5 section 15.2.3.4.
900function ObjectGetOwnPropertyNames(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100901 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000902 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
903
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000904 // Special handling for proxies.
905 if (%IsJSProxy(obj)) {
906 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000907 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000908 return ToStringArray(names, "getOwnPropertyNames");
909 }
910
Leon Clarkee46be812010-01-19 14:06:41 +0000911 // Find all the indexed properties.
912
913 // Get the local element names.
914 var propertyNames = %GetLocalElementNames(obj);
915
916 // Get names for indexed interceptor properties.
917 if (%GetInterceptorInfo(obj) & 1) {
918 var indexedInterceptorNames =
919 %GetIndexedInterceptorElementNames(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000920 if (indexedInterceptorNames)
Leon Clarkee46be812010-01-19 14:06:41 +0000921 propertyNames = propertyNames.concat(indexedInterceptorNames);
Leon Clarkee46be812010-01-19 14:06:41 +0000922 }
923
924 // Find all the named properties.
925
926 // Get the local property names.
927 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
928
929 // Get names for named interceptor properties if any.
930
931 if (%GetInterceptorInfo(obj) & 2) {
932 var namedInterceptorNames =
933 %GetNamedInterceptorPropertyNames(obj);
934 if (namedInterceptorNames) {
935 propertyNames = propertyNames.concat(namedInterceptorNames);
936 }
937 }
938
Steve Block8defd9f2010-07-08 12:39:36 +0100939 // Property names are expected to be unique strings.
940 var propertySet = {};
941 var j = 0;
942 for (var i = 0; i < propertyNames.length; ++i) {
943 var name = ToString(propertyNames[i]);
944 // We need to check for the exact property value since for intrinsic
945 // properties like toString if(propertySet["toString"]) will always
946 // succeed.
947 if (propertySet[name] === true)
948 continue;
949 propertySet[name] = true;
950 propertyNames[j++] = name;
951 }
952 propertyNames.length = j;
Andrei Popescu402d9372010-02-26 13:31:12 +0000953
Leon Clarkee46be812010-01-19 14:06:41 +0000954 return propertyNames;
955}
956
957
958// ES5 section 15.2.3.5.
959function ObjectCreate(proto, properties) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100960 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
Leon Clarkee46be812010-01-19 14:06:41 +0000961 throw MakeTypeError("proto_object_or_null", [proto]);
962 }
963 var obj = new $Object();
964 obj.__proto__ = proto;
965 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
966 return obj;
967}
968
969
Andrei Popescu31002712010-02-23 13:46:05 +0000970// ES5 section 15.2.3.6.
971function ObjectDefineProperty(obj, p, attributes) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100972 if (!IS_SPEC_OBJECT(obj)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000973 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
Leon Clarkef7060e22010-06-03 12:02:55 +0100974 }
Andrei Popescu31002712010-02-23 13:46:05 +0000975 var name = ToString(p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000976 if (%IsJSProxy(obj)) {
977 // Clone the attributes object for protection.
978 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
979 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
Ben Murdoch589d6972011-11-30 16:04:58 +0000980 var attributesClone = {};
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000981 for (var a in attributes) {
982 attributesClone[a] = attributes[a];
983 }
984 DefineProxyProperty(obj, name, attributesClone, true);
985 // The following would implement the spec as in the current proposal,
986 // but after recent comments on es-discuss, is most likely obsolete.
987 /*
988 var defineObj = FromGenericPropertyDescriptor(desc);
989 var names = ObjectGetOwnPropertyNames(attributes);
990 var standardNames =
991 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
992 for (var i = 0; i < names.length; i++) {
993 var N = names[i];
994 if (!(%HasLocalProperty(standardNames, N))) {
995 var attr = GetOwnProperty(attributes, N);
996 DefineOwnProperty(descObj, N, attr, true);
997 }
998 }
999 // This is really confusing the types, but it is what the proxies spec
1000 // currently requires:
1001 desc = descObj;
1002 */
1003 } else {
1004 var desc = ToPropertyDescriptor(attributes);
1005 DefineOwnProperty(obj, name, desc, true);
1006 }
Andrei Popescu31002712010-02-23 13:46:05 +00001007 return obj;
1008}
1009
1010
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001011function GetOwnEnumerablePropertyNames(properties) {
1012 var names = new InternalArray();
1013 for (var key in properties) {
1014 if (%HasLocalProperty(properties, key)) {
1015 names.push(key);
1016 }
1017 }
1018 return names;
1019}
1020
1021
Andrei Popescu31002712010-02-23 13:46:05 +00001022// ES5 section 15.2.3.7.
Leon Clarkee46be812010-01-19 14:06:41 +00001023function ObjectDefineProperties(obj, properties) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001024 if (!IS_SPEC_OBJECT(obj))
Andrei Popescu31002712010-02-23 13:46:05 +00001025 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
Leon Clarkee46be812010-01-19 14:06:41 +00001026 var props = ToObject(properties);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001027 var names = GetOwnEnumerablePropertyNames(props);
1028 for (var i = 0; i < names.length; i++) {
1029 var name = names[i];
1030 var desc = ToPropertyDescriptor(props[name]);
1031 DefineOwnProperty(obj, name, desc, true);
Leon Clarkee46be812010-01-19 14:06:41 +00001032 }
Andrei Popescu31002712010-02-23 13:46:05 +00001033 return obj;
Leon Clarkee46be812010-01-19 14:06:41 +00001034}
1035
1036
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001037// Harmony proxies.
1038function ProxyFix(obj) {
1039 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001040 var props = CallTrap0(handler, "fix", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001041 if (IS_UNDEFINED(props)) {
1042 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1043 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001044
1045 if (IS_SPEC_FUNCTION(obj)) {
1046 var callTrap = %GetCallTrap(obj);
1047 var constructTrap = %GetConstructTrap(obj);
1048 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1049 %Fix(obj); // becomes a regular function
1050 %SetCode(obj, code);
1051 } else {
1052 %Fix(obj);
1053 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001054 ObjectDefineProperties(obj, props);
1055}
1056
1057
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001058// ES5 section 15.2.3.8.
1059function ObjectSeal(obj) {
1060 if (!IS_SPEC_OBJECT(obj)) {
1061 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
1062 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001063 if (%IsJSProxy(obj)) {
1064 ProxyFix(obj);
1065 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001066 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001067 for (var i = 0; i < names.length; i++) {
1068 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001069 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001070 if (desc.isConfigurable()) {
1071 desc.setConfigurable(false);
1072 DefineOwnProperty(obj, name, desc, true);
1073 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001074 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001075 %PreventExtensions(obj);
1076 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001077}
1078
1079
1080// ES5 section 15.2.3.9.
1081function ObjectFreeze(obj) {
1082 if (!IS_SPEC_OBJECT(obj)) {
1083 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
1084 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001085 if (%IsJSProxy(obj)) {
1086 ProxyFix(obj);
1087 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001088 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001089 for (var i = 0; i < names.length; i++) {
1090 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001091 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092 if (desc.isWritable() || desc.isConfigurable()) {
1093 if (IsDataDescriptor(desc)) desc.setWritable(false);
1094 desc.setConfigurable(false);
1095 DefineOwnProperty(obj, name, desc, true);
1096 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001097 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001098 %PreventExtensions(obj);
1099 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001100}
1101
1102
Steve Block8defd9f2010-07-08 12:39:36 +01001103// ES5 section 15.2.3.10
1104function ObjectPreventExtension(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001105 if (!IS_SPEC_OBJECT(obj)) {
Steve Block8defd9f2010-07-08 12:39:36 +01001106 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
1107 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001108 if (%IsJSProxy(obj)) {
1109 ProxyFix(obj);
1110 }
Steve Block8defd9f2010-07-08 12:39:36 +01001111 %PreventExtensions(obj);
1112 return obj;
1113}
1114
1115
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001116// ES5 section 15.2.3.11
1117function ObjectIsSealed(obj) {
1118 if (!IS_SPEC_OBJECT(obj)) {
1119 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
1120 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001121 if (%IsJSProxy(obj)) {
1122 return false;
1123 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001124 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001125 for (var i = 0; i < names.length; i++) {
1126 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001127 var desc = GetOwnProperty(obj, name);
1128 if (desc.isConfigurable()) return false;
1129 }
1130 if (!ObjectIsExtensible(obj)) {
1131 return true;
1132 }
1133 return false;
1134}
1135
1136
1137// ES5 section 15.2.3.12
1138function ObjectIsFrozen(obj) {
1139 if (!IS_SPEC_OBJECT(obj)) {
1140 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
1141 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001142 if (%IsJSProxy(obj)) {
1143 return false;
1144 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001145 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001146 for (var i = 0; i < names.length; i++) {
1147 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001148 var desc = GetOwnProperty(obj, name);
1149 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1150 if (desc.isConfigurable()) return false;
1151 }
1152 if (!ObjectIsExtensible(obj)) {
1153 return true;
1154 }
1155 return false;
1156}
1157
1158
Steve Block8defd9f2010-07-08 12:39:36 +01001159// ES5 section 15.2.3.13
1160function ObjectIsExtensible(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001161 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001162 throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
1163 }
1164 if (%IsJSProxy(obj)) {
1165 return true;
Steve Block8defd9f2010-07-08 12:39:36 +01001166 }
1167 return %IsExtensible(obj);
1168}
1169
1170
Steve Blocka7e24c12009-10-30 11:49:00 +00001171%SetCode($Object, function(x) {
1172 if (%_IsConstructCall()) {
1173 if (x == null) return this;
1174 return ToObject(x);
1175 } else {
1176 if (x == null) return { };
1177 return ToObject(x);
1178 }
1179});
1180
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001181%SetExpectedNumberOfProperties($Object, 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001182
1183// ----------------------------------------------------------------------------
Ben Murdoch589d6972011-11-30 16:04:58 +00001184// Object
Steve Blocka7e24c12009-10-30 11:49:00 +00001185
Ben Murdoch589d6972011-11-30 16:04:58 +00001186function SetUpObject() {
1187 %CheckIsBootstrapping();
1188 // Set Up non-enumerable functions on the Object.prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001189 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1190 "toString", ObjectToString,
1191 "toLocaleString", ObjectToLocaleString,
1192 "valueOf", ObjectValueOf,
1193 "hasOwnProperty", ObjectHasOwnProperty,
1194 "isPrototypeOf", ObjectIsPrototypeOf,
1195 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1196 "__defineGetter__", ObjectDefineGetter,
1197 "__lookupGetter__", ObjectLookupGetter,
1198 "__defineSetter__", ObjectDefineSetter,
1199 "__lookupSetter__", ObjectLookupSetter
1200 ));
1201 InstallFunctions($Object, DONT_ENUM, $Array(
Leon Clarkee46be812010-01-19 14:06:41 +00001202 "keys", ObjectKeys,
1203 "create", ObjectCreate,
Andrei Popescu31002712010-02-23 13:46:05 +00001204 "defineProperty", ObjectDefineProperty,
1205 "defineProperties", ObjectDefineProperties,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001206 "freeze", ObjectFreeze,
Leon Clarkee46be812010-01-19 14:06:41 +00001207 "getPrototypeOf", ObjectGetPrototypeOf,
1208 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
Steve Block8defd9f2010-07-08 12:39:36 +01001209 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1210 "isExtensible", ObjectIsExtensible,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001211 "isFrozen", ObjectIsFrozen,
1212 "isSealed", ObjectIsSealed,
1213 "preventExtensions", ObjectPreventExtension,
1214 "seal", ObjectSeal
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 ));
1216}
1217
Ben Murdoch589d6972011-11-30 16:04:58 +00001218SetUpObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00001219
1220// ----------------------------------------------------------------------------
1221// Boolean
1222
1223function BooleanToString() {
1224 // NOTE: Both Boolean objects and values can enter here as
1225 // 'this'. This is not as dictated by ECMA-262.
Ben Murdoch086aeea2011-05-13 15:57:08 +01001226 var b = this;
1227 if (!IS_BOOLEAN(b)) {
1228 if (!IS_BOOLEAN_WRAPPER(b)) {
1229 throw new $TypeError('Boolean.prototype.toString is not generic');
1230 }
1231 b = %_ValueOf(b);
1232 }
1233 return b ? 'true' : 'false';
Steve Blocka7e24c12009-10-30 11:49:00 +00001234}
1235
1236
1237function BooleanValueOf() {
1238 // NOTE: Both Boolean objects and values can enter here as
1239 // 'this'. This is not as dictated by ECMA-262.
1240 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
1241 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1242 return %_ValueOf(this);
1243}
1244
1245
Steve Blocka7e24c12009-10-30 11:49:00 +00001246// ----------------------------------------------------------------------------
1247
1248
Ben Murdoch589d6972011-11-30 16:04:58 +00001249function SetUpBoolean () {
1250 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1252 "toString", BooleanToString,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001253 "valueOf", BooleanValueOf
Steve Blocka7e24c12009-10-30 11:49:00 +00001254 ));
1255}
1256
Ben Murdoch589d6972011-11-30 16:04:58 +00001257SetUpBoolean();
1258
Steve Blocka7e24c12009-10-30 11:49:00 +00001259
1260// ----------------------------------------------------------------------------
1261// Number
1262
1263// Set the Number function and constructor.
1264%SetCode($Number, function(x) {
1265 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1266 if (%_IsConstructCall()) {
1267 %_SetValueOf(this, value);
1268 } else {
1269 return value;
1270 }
1271});
1272
1273%FunctionSetPrototype($Number, new $Number(0));
1274
1275// ECMA-262 section 15.7.4.2.
1276function NumberToString(radix) {
1277 // NOTE: Both Number objects and values can enter here as
1278 // 'this'. This is not as dictated by ECMA-262.
1279 var number = this;
1280 if (!IS_NUMBER(this)) {
1281 if (!IS_NUMBER_WRAPPER(this))
1282 throw new $TypeError('Number.prototype.toString is not generic');
1283 // Get the value of this number in case it's an object.
1284 number = %_ValueOf(this);
1285 }
1286 // Fast case: Convert number in radix 10.
1287 if (IS_UNDEFINED(radix) || radix === 10) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001288 return %_NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 }
1290
1291 // Convert the radix to an integer and check the range.
1292 radix = TO_INTEGER(radix);
1293 if (radix < 2 || radix > 36) {
1294 throw new $RangeError('toString() radix argument must be between 2 and 36');
1295 }
1296 // Convert the number to a string in the given radix.
1297 return %NumberToRadixString(number, radix);
1298}
1299
1300
1301// ECMA-262 section 15.7.4.3
1302function NumberToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001303 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1304 throw MakeTypeError("called_on_null_or_undefined",
1305 ["Number.prototype.toLocaleString"]);
1306 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 return this.toString();
1308}
1309
1310
1311// ECMA-262 section 15.7.4.4
1312function NumberValueOf() {
1313 // NOTE: Both Number objects and values can enter here as
1314 // 'this'. This is not as dictated by ECMA-262.
1315 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
1316 throw new $TypeError('Number.prototype.valueOf is not generic');
1317 return %_ValueOf(this);
1318}
1319
1320
1321// ECMA-262 section 15.7.4.5
1322function NumberToFixed(fractionDigits) {
1323 var f = TO_INTEGER(fractionDigits);
1324 if (f < 0 || f > 20) {
1325 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1326 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001327 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1328 throw MakeTypeError("called_on_null_or_undefined",
1329 ["Number.prototype.toFixed"]);
1330 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 var x = ToNumber(this);
1332 return %NumberToFixed(x, f);
1333}
1334
1335
1336// ECMA-262 section 15.7.4.6
1337function NumberToExponential(fractionDigits) {
1338 var f = -1;
1339 if (!IS_UNDEFINED(fractionDigits)) {
1340 f = TO_INTEGER(fractionDigits);
1341 if (f < 0 || f > 20) {
1342 throw new $RangeError("toExponential() argument must be between 0 and 20");
1343 }
1344 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001345 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1346 throw MakeTypeError("called_on_null_or_undefined",
1347 ["Number.prototype.toExponential"]);
1348 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001349 var x = ToNumber(this);
1350 return %NumberToExponential(x, f);
1351}
1352
1353
1354// ECMA-262 section 15.7.4.7
1355function NumberToPrecision(precision) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001356 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1357 throw MakeTypeError("called_on_null_or_undefined",
1358 ["Number.prototype.toPrecision"]);
1359 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1361 var p = TO_INTEGER(precision);
1362 if (p < 1 || p > 21) {
1363 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1364 }
1365 var x = ToNumber(this);
1366 return %NumberToPrecision(x, p);
1367}
1368
1369
Steve Blocka7e24c12009-10-30 11:49:00 +00001370// ----------------------------------------------------------------------------
1371
Ben Murdoch589d6972011-11-30 16:04:58 +00001372function SetUpNumber() {
1373 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001374 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
Ben Murdoch589d6972011-11-30 16:04:58 +00001375 // Set up the constructor property on the Number prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1377
1378 %OptimizeObjectForAddingMultipleProperties($Number, 5);
1379 // ECMA-262 section 15.7.3.1.
1380 %SetProperty($Number,
1381 "MAX_VALUE",
1382 1.7976931348623157e+308,
1383 DONT_ENUM | DONT_DELETE | READ_ONLY);
1384
1385 // ECMA-262 section 15.7.3.2.
1386 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
1387
1388 // ECMA-262 section 15.7.3.3.
1389 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1390
1391 // ECMA-262 section 15.7.3.4.
1392 %SetProperty($Number,
1393 "NEGATIVE_INFINITY",
1394 -1/0,
1395 DONT_ENUM | DONT_DELETE | READ_ONLY);
1396
1397 // ECMA-262 section 15.7.3.5.
1398 %SetProperty($Number,
1399 "POSITIVE_INFINITY",
1400 1/0,
1401 DONT_ENUM | DONT_DELETE | READ_ONLY);
Andrei Popescu402d9372010-02-26 13:31:12 +00001402 %ToFastProperties($Number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001403
Ben Murdoch589d6972011-11-30 16:04:58 +00001404 // Set up non-enumerable functions on the Number prototype object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001405 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1406 "toString", NumberToString,
1407 "toLocaleString", NumberToLocaleString,
1408 "valueOf", NumberValueOf,
1409 "toFixed", NumberToFixed,
1410 "toExponential", NumberToExponential,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001411 "toPrecision", NumberToPrecision
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 ));
1413}
1414
Ben Murdoch589d6972011-11-30 16:04:58 +00001415SetUpNumber();
Steve Blocka7e24c12009-10-30 11:49:00 +00001416
1417
Steve Blocka7e24c12009-10-30 11:49:00 +00001418// ----------------------------------------------------------------------------
1419// Function
1420
1421$Function.prototype.constructor = $Function;
1422
1423function FunctionSourceString(func) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001424 while (%IsJSFunctionProxy(func)) {
1425 func = %GetCallTrap(func);
1426 }
1427
Steve Blocka7e24c12009-10-30 11:49:00 +00001428 if (!IS_FUNCTION(func)) {
1429 throw new $TypeError('Function.prototype.toString is not generic');
1430 }
1431
1432 var source = %FunctionGetSourceCode(func);
1433 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1434 var name = %FunctionGetName(func);
1435 if (name) {
1436 // Mimic what KJS does.
1437 return 'function ' + name + '() { [native code] }';
1438 } else {
1439 return 'function () { [native code] }';
1440 }
1441 }
1442
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001443 var name = %FunctionNameShouldPrintAsAnonymous(func)
1444 ? 'anonymous'
1445 : %FunctionGetName(func);
Steve Blocka7e24c12009-10-30 11:49:00 +00001446 return 'function ' + name + source;
1447}
1448
1449
1450function FunctionToString() {
1451 return FunctionSourceString(this);
1452}
1453
1454
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001455// ES5 15.3.4.5
1456function FunctionBind(this_arg) { // Length is 1.
Ben Murdoch589d6972011-11-30 16:04:58 +00001457 if (!IS_SPEC_FUNCTION(this)) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001458 throw new $TypeError('Bind must be called on a function');
1459 }
1460 // this_arg is not an argument that should be bound.
Ben Murdochbb769b22010-08-11 14:56:33 +01001461 var argc_bound = (%_ArgumentsLength() || 1) - 1;
Steve Block1e0659c2011-05-24 12:43:12 +01001462 var fn = this;
Ben Murdoch589d6972011-11-30 16:04:58 +00001463
Steve Block1e0659c2011-05-24 12:43:12 +01001464 if (argc_bound == 0) {
1465 var result = function() {
1466 if (%_IsConstructCall()) {
1467 // %NewObjectFromBound implicitly uses arguments passed to this
1468 // function. We do not pass the arguments object explicitly to avoid
1469 // materializing it and guarantee that this function will be optimized.
1470 return %NewObjectFromBound(fn, null);
1471 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001472 return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength());
Steve Block1e0659c2011-05-24 12:43:12 +01001473 };
1474 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001475 var bound_args = new InternalArray(argc_bound);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001476 for(var i = 0; i < argc_bound; i++) {
1477 bound_args[i] = %_Arguments(i+1);
Ben Murdochf87a2032010-10-22 12:50:53 +01001478 }
Steve Block1e0659c2011-05-24 12:43:12 +01001479
1480 var result = function() {
1481 // If this is a construct call we use a special runtime method
1482 // to generate the actual object using the bound function.
1483 if (%_IsConstructCall()) {
1484 // %NewObjectFromBound implicitly uses arguments passed to this
1485 // function. We do not pass the arguments object explicitly to avoid
1486 // materializing it and guarantee that this function will be optimized.
1487 return %NewObjectFromBound(fn, bound_args);
1488 }
1489
1490 // Combine the args we got from the bind call with the args
1491 // given as argument to the invocation.
1492 var argc = %_ArgumentsLength();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001493 var args = new InternalArray(argc + argc_bound);
Steve Block1e0659c2011-05-24 12:43:12 +01001494 // Add bound arguments.
1495 for (var i = 0; i < argc_bound; i++) {
1496 args[i] = bound_args[i];
1497 }
1498 // Add arguments from call.
1499 for (var i = 0; i < argc; i++) {
1500 args[argc_bound + i] = %_Arguments(i);
1501 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001502 return %Apply(fn, this_arg, args, 0, argc + argc_bound);
Steve Block1e0659c2011-05-24 12:43:12 +01001503 };
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001504 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001505
1506 // We already have caller and arguments properties on functions,
1507 // which are non-configurable. It therefore makes no sence to
1508 // try to redefine these as defined by the spec. The spec says
1509 // that bind should make these throw a TypeError if get or set
1510 // is called and make them non-enumerable and non-configurable.
Ben Murdochf87a2032010-10-22 12:50:53 +01001511 // To be consistent with our normal functions we leave this as it is.
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001512
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001513 %FunctionRemovePrototype(result);
1514 %FunctionSetBound(result);
Ben Murdoch589d6972011-11-30 16:04:58 +00001515 // Set the correct length. If this is a function proxy, this.length might
1516 // throw, or return a bogus result. Leave length alone in that case.
1517 // TODO(rossberg): This is underspecified in the current proxy proposal.
1518 try {
1519 var old_length = ToInteger(this.length);
1520 var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0;
1521 %BoundFunctionSetLength(result, length);
1522 } catch(x) {}
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001523 return result;
1524}
1525
1526
Steve Blocka7e24c12009-10-30 11:49:00 +00001527function NewFunction(arg1) { // length == 1
1528 var n = %_ArgumentsLength();
1529 var p = '';
1530 if (n > 1) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001531 p = new InternalArray(n - 1);
Ben Murdoch086aeea2011-05-13 15:57:08 +01001532 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1533 p = Join(p, n - 1, ',', NonStringToString);
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 // If the formal parameters string include ) - an illegal
1535 // character - it may make the combined function expression
1536 // compile. We avoid this problem by checking for this early on.
1537 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1538 }
1539 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
1540 var source = '(function(' + p + ') {\n' + body + '\n})';
1541
1542 // The call to SetNewFunctionAttributes will ensure the prototype
1543 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001544 var f = %CompileString(source)();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001545 %FunctionMarkNameShouldPrintAsAnonymous(f);
Steve Blocka7e24c12009-10-30 11:49:00 +00001546 return %SetNewFunctionAttributes(f);
1547}
1548
1549%SetCode($Function, NewFunction);
1550
1551// ----------------------------------------------------------------------------
1552
Ben Murdoch589d6972011-11-30 16:04:58 +00001553function SetUpFunction() {
1554 %CheckIsBootstrapping();
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001556 "bind", FunctionBind,
Steve Blocka7e24c12009-10-30 11:49:00 +00001557 "toString", FunctionToString
1558 ));
1559}
1560
Ben Murdoch589d6972011-11-30 16:04:58 +00001561SetUpFunction();