blob: 982e18e4d5564cc6874e215eaf86b6d94bf699ec [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
Leon Clarkee46be812010-01-19 14:06:41 +000044
Steve Blocka7e24c12009-10-30 11:49:00 +000045// ----------------------------------------------------------------------------
46
47
48// Helper function used to install functions on objects.
49function InstallFunctions(object, attributes, functions) {
50 if (functions.length >= 8) {
51 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
52 }
53 for (var i = 0; i < functions.length; i += 2) {
54 var key = functions[i];
55 var f = functions[i + 1];
56 %FunctionSetName(f, key);
Steve Block6ded16b2010-05-10 14:33:55 +010057 %FunctionRemovePrototype(f);
Steve Blocka7e24c12009-10-30 11:49:00 +000058 %SetProperty(object, key, f, attributes);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000059 %SetNativeFlag(f);
Steve Blocka7e24c12009-10-30 11:49:00 +000060 }
Andrei Popescu402d9372010-02-26 13:31:12 +000061 %ToFastProperties(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000062}
63
64// Emulates JSC by installing functions on a hidden prototype that
65// lies above the current object/prototype. This lets you override
66// functions on String.prototype etc. and then restore the old function
67// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
68function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
69 var hidden_prototype = new $Object();
70 %SetHiddenPrototype(object, hidden_prototype);
71 InstallFunctions(hidden_prototype, attributes, functions);
72}
73
74
75// ----------------------------------------------------------------------------
76
77
78// ECMA 262 - 15.1.4
79function GlobalIsNaN(number) {
80 var n = ToNumber(number);
81 return NUMBER_IS_NAN(n);
82}
83
84
85// ECMA 262 - 15.1.5
86function GlobalIsFinite(number) {
Ben Murdoch086aeea2011-05-13 15:57:08 +010087 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
Steve Block6ded16b2010-05-10 14:33:55 +010088
89 // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
90 return %_IsSmi(number) || number - number == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000091}
92
93
94// ECMA-262 - 15.1.2.2
95function GlobalParseInt(string, radix) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010096 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +000097 // Some people use parseInt instead of Math.floor. This
98 // optimization makes parseInt on a Smi 12 times faster (60ns
99 // vs 800ns). The following optimization makes parseInt on a
100 // non-Smi number 9 times faster (230ns vs 2070ns). Together
101 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
102 if (%_IsSmi(string)) return string;
103 if (IS_NUMBER(string) &&
Steve Blockd0582a62009-12-15 09:54:21 +0000104 ((0.01 < string && string < 1e9) ||
105 (-1e9 < string && string < -0.01))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000106 // Truncate number.
107 return string | 0;
108 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000109 string = TO_STRING_INLINE(string);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000110 radix = radix | 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000112 // The spec says ToString should be evaluated before ToInt32.
113 string = TO_STRING_INLINE(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 radix = TO_INT32(radix);
115 if (!(radix == 0 || (2 <= radix && radix <= 36)))
116 return $NaN;
117 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000118
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100119 if (%_HasCachedArrayIndex(string) &&
120 (radix == 0 || radix == 10)) {
121 return %_GetCachedArrayIndex(string);
122 }
123 return %StringParseInt(string, radix);
Steve Blocka7e24c12009-10-30 11:49:00 +0000124}
125
126
127// ECMA-262 - 15.1.2.3
128function GlobalParseFloat(string) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100129 string = TO_STRING_INLINE(string);
130 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
131 return %StringParseFloat(string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132}
133
134
135function GlobalEval(x) {
136 if (!IS_STRING(x)) return x;
137
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000138 var receiver = this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000139 var global_receiver = %GlobalReceiver(global);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000140
141 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
142 receiver = global_receiver;
143 }
144
145 var this_is_global_receiver = (receiver === global_receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000146 var global_is_detached = (global === global_receiver);
147
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000148 // For consistency with JSC we require the global object passed to
149 // eval to be the global object from which 'eval' originated. This
150 // is not mandated by the spec.
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 if (!this_is_global_receiver || global_is_detached) {
152 throw new $EvalError('The "this" object passed to eval must ' +
153 'be the global object from which eval originated');
154 }
155
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800156 var f = %CompileString(x);
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 if (!IS_FUNCTION(f)) return f;
158
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000159 return %_CallFunction(receiver, f);
Steve Blocka7e24c12009-10-30 11:49:00 +0000160}
161
162
Steve Blocka7e24c12009-10-30 11:49:00 +0000163// ----------------------------------------------------------------------------
164
165
166function SetupGlobal() {
167 // ECMA 262 - 15.1.1.1.
168 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
169
170 // ECMA-262 - 15.1.1.2.
171 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
172
173 // ECMA-262 - 15.1.1.3.
174 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
175
176 // Setup non-enumerable function on the global object.
177 InstallFunctions(global, DONT_ENUM, $Array(
178 "isNaN", GlobalIsNaN,
179 "isFinite", GlobalIsFinite,
180 "parseInt", GlobalParseInt,
181 "parseFloat", GlobalParseFloat,
Steve Block053d10c2011-06-13 19:13:29 +0100182 "eval", GlobalEval
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 ));
184}
185
186SetupGlobal();
187
188
189// ----------------------------------------------------------------------------
190// Boolean (first part of definition)
191
192
193%SetCode($Boolean, function(x) {
194 if (%_IsConstructCall()) {
195 %_SetValueOf(this, ToBoolean(x));
196 } else {
197 return ToBoolean(x);
198 }
199});
200
201%FunctionSetPrototype($Boolean, new $Boolean(false));
202
203%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
204
205// ----------------------------------------------------------------------------
206// Object
207
208$Object.prototype.constructor = $Object;
209
210// ECMA-262 - 15.2.4.2
211function ObjectToString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000212 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
213 return '[object Undefined]';
214 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000215 if (IS_NULL(this)) return '[object Null]';
Leon Clarked91b9f72010-01-27 17:25:45 +0000216 return "[object " + %_ClassOf(ToObject(this)) + "]";
Steve Blocka7e24c12009-10-30 11:49:00 +0000217}
218
219
220// ECMA-262 - 15.2.4.3
221function ObjectToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +0000222 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
223 throw MakeTypeError("called_on_null_or_undefined",
224 ["Object.prototype.toLocaleString"]);
225 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000226 return this.toString();
227}
228
229
230// ECMA-262 - 15.2.4.4
231function ObjectValueOf() {
Leon Clarked91b9f72010-01-27 17:25:45 +0000232 return ToObject(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000233}
234
235
236// ECMA-262 - 15.2.4.5
237function ObjectHasOwnProperty(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000238 if (%IsJSProxy(this)) {
239 var handler = %GetHandler(this);
240 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
241 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000242 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
Steve Blocka7e24c12009-10-30 11:49:00 +0000243}
244
245
246// ECMA-262 - 15.2.4.6
247function ObjectIsPrototypeOf(V) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000248 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
249 throw MakeTypeError("called_on_null_or_undefined",
250 ["Object.prototype.isPrototypeOf"]);
251 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100252 if (!IS_SPEC_OBJECT(V)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000253 return %IsInPrototypeChain(this, V);
254}
255
256
257// ECMA-262 - 15.2.4.6
258function ObjectPropertyIsEnumerable(V) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000259 var P = ToString(V);
260 if (%IsJSProxy(this)) {
261 var desc = GetOwnProperty(this, P);
262 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
263 }
264 return %IsPropertyEnumerable(ToObject(this), P);
Steve Blocka7e24c12009-10-30 11:49:00 +0000265}
266
267
268// Extensions for providing property getters and setters.
269function ObjectDefineGetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000270 var receiver = this;
271 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
272 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000273 }
274 if (!IS_FUNCTION(fun)) {
275 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
276 }
Steve Block44f0eee2011-05-26 01:26:41 +0100277 var desc = new PropertyDescriptor();
278 desc.setGet(fun);
279 desc.setEnumerable(true);
280 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000281 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000282}
283
284
285function ObjectLookupGetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000286 var receiver = this;
287 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
288 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000290 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000291}
292
293
294function ObjectDefineSetter(name, fun) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000295 var receiver = this;
296 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
297 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 }
299 if (!IS_FUNCTION(fun)) {
300 throw new $TypeError(
301 'Object.prototype.__defineSetter__: Expecting function');
302 }
Steve Block44f0eee2011-05-26 01:26:41 +0100303 var desc = new PropertyDescriptor();
304 desc.setSet(fun);
305 desc.setEnumerable(true);
306 desc.setConfigurable(true);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000307 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000308}
309
310
311function ObjectLookupSetter(name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000312 var receiver = this;
313 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
314 receiver = %GlobalReceiver(global);
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000316 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
Steve Blocka7e24c12009-10-30 11:49:00 +0000317}
318
319
320function ObjectKeys(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100321 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000322 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000323 if (%IsJSProxy(obj)) {
324 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000325 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000326 return ToStringArray(names);
327 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000328 return %LocalKeys(obj);
329}
330
331
Leon Clarkee46be812010-01-19 14:06:41 +0000332// ES5 8.10.1.
333function IsAccessorDescriptor(desc) {
334 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000335 return desc.hasGetter() || desc.hasSetter();
Leon Clarkee46be812010-01-19 14:06:41 +0000336}
337
338
339// ES5 8.10.2.
340function IsDataDescriptor(desc) {
341 if (IS_UNDEFINED(desc)) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000342 return desc.hasValue() || desc.hasWritable();
Leon Clarkee46be812010-01-19 14:06:41 +0000343}
344
345
346// ES5 8.10.3.
347function IsGenericDescriptor(desc) {
348 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
349}
350
351
352function IsInconsistentDescriptor(desc) {
353 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
354}
355
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000356
Leon Clarkee46be812010-01-19 14:06:41 +0000357// ES5 8.10.4
358function FromPropertyDescriptor(desc) {
Andrei Popescu31002712010-02-23 13:46:05 +0000359 if (IS_UNDEFINED(desc)) return desc;
Ben Murdoch257744e2011-11-30 15:57:28 +0000360
Leon Clarkee46be812010-01-19 14:06:41 +0000361 if (IsDataDescriptor(desc)) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000362 return { value: desc.getValue(),
363 writable: desc.isWritable(),
364 enumerable: desc.isEnumerable(),
365 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000366 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000367 // Must be an AccessorDescriptor then. We never return a generic descriptor.
368 return { get: desc.getGet(),
369 set: desc.getSet(),
370 enumerable: desc.isEnumerable(),
371 configurable: desc.isConfigurable() };
Leon Clarkee46be812010-01-19 14:06:41 +0000372}
373
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000374
375// Harmony Proxies
376function FromGenericPropertyDescriptor(desc) {
377 if (IS_UNDEFINED(desc)) return desc;
378 var obj = new $Object();
379
380 if (desc.hasValue()) {
381 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
382 }
383 if (desc.hasWritable()) {
384 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
385 }
386 if (desc.hasGetter()) {
387 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
388 }
389 if (desc.hasSetter()) {
390 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
391 }
392 if (desc.hasEnumerable()) {
393 %IgnoreAttributesAndSetProperty(obj, "enumerable",
394 desc.isEnumerable(), NONE);
395 }
396 if (desc.hasConfigurable()) {
397 %IgnoreAttributesAndSetProperty(obj, "configurable",
398 desc.isConfigurable(), NONE);
399 }
400 return obj;
401}
402
403
Leon Clarkee46be812010-01-19 14:06:41 +0000404// ES5 8.10.5.
405function ToPropertyDescriptor(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100406 if (!IS_SPEC_OBJECT(obj)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000407 throw MakeTypeError("property_desc_object", [obj]);
408 }
409 var desc = new PropertyDescriptor();
410
411 if ("enumerable" in obj) {
412 desc.setEnumerable(ToBoolean(obj.enumerable));
413 }
414
Leon Clarkee46be812010-01-19 14:06:41 +0000415 if ("configurable" in obj) {
416 desc.setConfigurable(ToBoolean(obj.configurable));
417 }
418
419 if ("value" in obj) {
420 desc.setValue(obj.value);
421 }
422
423 if ("writable" in obj) {
424 desc.setWritable(ToBoolean(obj.writable));
425 }
426
427 if ("get" in obj) {
428 var get = obj.get;
429 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
430 throw MakeTypeError("getter_must_be_callable", [get]);
431 }
432 desc.setGet(get);
433 }
434
435 if ("set" in obj) {
436 var set = obj.set;
437 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
438 throw MakeTypeError("setter_must_be_callable", [set]);
439 }
440 desc.setSet(set);
441 }
442
443 if (IsInconsistentDescriptor(desc)) {
444 throw MakeTypeError("value_and_accessor", [obj]);
445 }
446 return desc;
447}
448
449
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000450// For Harmony proxies.
451function ToCompletePropertyDescriptor(obj) {
452 var desc = ToPropertyDescriptor(obj)
453 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
454 if (!desc.hasValue()) desc.setValue(void 0);
455 if (!desc.hasWritable()) desc.setWritable(false);
456 } else {
457 // Is accessor descriptor.
458 if (!desc.hasGetter()) desc.setGet(void 0);
459 if (!desc.hasSetter()) desc.setSet(void 0);
460 }
461 if (!desc.hasEnumerable()) desc.setEnumerable(false);
462 if (!desc.hasConfigurable()) desc.setConfigurable(false);
463 return desc;
464}
465
466
Leon Clarkee46be812010-01-19 14:06:41 +0000467function PropertyDescriptor() {
468 // Initialize here so they are all in-object and have the same map.
469 // Default values from ES5 8.6.1.
470 this.value_ = void 0;
471 this.hasValue_ = false;
472 this.writable_ = false;
473 this.hasWritable_ = false;
474 this.enumerable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000475 this.hasEnumerable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000476 this.configurable_ = false;
Andrei Popescu31002712010-02-23 13:46:05 +0000477 this.hasConfigurable_ = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000478 this.get_ = void 0;
479 this.hasGetter_ = false;
480 this.set_ = void 0;
481 this.hasSetter_ = false;
482}
483
Steve Block44f0eee2011-05-26 01:26:41 +0100484PropertyDescriptor.prototype.__proto__ = null;
Ben Murdoch257744e2011-11-30 15:57:28 +0000485
Steve Block44f0eee2011-05-26 01:26:41 +0100486PropertyDescriptor.prototype.toString = function() {
487 return "[object PropertyDescriptor]";
488};
Leon Clarkee46be812010-01-19 14:06:41 +0000489
490PropertyDescriptor.prototype.setValue = function(value) {
491 this.value_ = value;
492 this.hasValue_ = true;
493}
494
495
496PropertyDescriptor.prototype.getValue = function() {
497 return this.value_;
498}
499
500
Andrei Popescu31002712010-02-23 13:46:05 +0000501PropertyDescriptor.prototype.hasValue = function() {
502 return this.hasValue_;
503}
504
505
Leon Clarkee46be812010-01-19 14:06:41 +0000506PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
507 this.enumerable_ = enumerable;
Andrei Popescu31002712010-02-23 13:46:05 +0000508 this.hasEnumerable_ = true;
Leon Clarkee46be812010-01-19 14:06:41 +0000509}
510
511
512PropertyDescriptor.prototype.isEnumerable = function () {
513 return this.enumerable_;
514}
515
516
Andrei Popescu31002712010-02-23 13:46:05 +0000517PropertyDescriptor.prototype.hasEnumerable = function() {
518 return this.hasEnumerable_;
519}
520
521
Leon Clarkee46be812010-01-19 14:06:41 +0000522PropertyDescriptor.prototype.setWritable = function(writable) {
523 this.writable_ = writable;
524 this.hasWritable_ = true;
525}
526
527
528PropertyDescriptor.prototype.isWritable = function() {
529 return this.writable_;
530}
531
532
Leon Clarkef7060e22010-06-03 12:02:55 +0100533PropertyDescriptor.prototype.hasWritable = function() {
534 return this.hasWritable_;
535}
536
537
Leon Clarkee46be812010-01-19 14:06:41 +0000538PropertyDescriptor.prototype.setConfigurable = function(configurable) {
539 this.configurable_ = configurable;
Andrei Popescu31002712010-02-23 13:46:05 +0000540 this.hasConfigurable_ = true;
541}
542
543
544PropertyDescriptor.prototype.hasConfigurable = function() {
545 return this.hasConfigurable_;
Leon Clarkee46be812010-01-19 14:06:41 +0000546}
547
548
549PropertyDescriptor.prototype.isConfigurable = function() {
550 return this.configurable_;
551}
552
553
554PropertyDescriptor.prototype.setGet = function(get) {
555 this.get_ = get;
556 this.hasGetter_ = true;
557}
558
559
560PropertyDescriptor.prototype.getGet = function() {
561 return this.get_;
562}
563
564
Andrei Popescu31002712010-02-23 13:46:05 +0000565PropertyDescriptor.prototype.hasGetter = function() {
566 return this.hasGetter_;
567}
568
569
Leon Clarkee46be812010-01-19 14:06:41 +0000570PropertyDescriptor.prototype.setSet = function(set) {
571 this.set_ = set;
572 this.hasSetter_ = true;
573}
574
575
576PropertyDescriptor.prototype.getSet = function() {
577 return this.set_;
578}
579
580
Andrei Popescu31002712010-02-23 13:46:05 +0000581PropertyDescriptor.prototype.hasSetter = function() {
582 return this.hasSetter_;
583}
584
585
Steve Block1e0659c2011-05-24 12:43:12 +0100586// Converts an array returned from Runtime_GetOwnProperty to an actual
587// property descriptor. For a description of the array layout please
588// see the runtime.cc file.
589function ConvertDescriptorArrayToDescriptor(desc_array) {
Steve Block44f0eee2011-05-26 01:26:41 +0100590 if (desc_array === false) {
Steve Block1e0659c2011-05-24 12:43:12 +0100591 throw 'Internal error: invalid desc_array';
Steve Block103cc402011-02-16 13:27:44 +0000592 }
Steve Block1e0659c2011-05-24 12:43:12 +0100593
594 if (IS_UNDEFINED(desc_array)) {
595 return void 0;
596 }
597
598 var desc = new PropertyDescriptor();
599 // This is an accessor.
600 if (desc_array[IS_ACCESSOR_INDEX]) {
601 desc.setGet(desc_array[GETTER_INDEX]);
602 desc.setSet(desc_array[SETTER_INDEX]);
603 } else {
604 desc.setValue(desc_array[VALUE_INDEX]);
605 desc.setWritable(desc_array[WRITABLE_INDEX]);
606 }
607 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
608 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
Leon Clarkee46be812010-01-19 14:06:41 +0000609
610 return desc;
611}
612
613
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000614// For Harmony proxies.
615function GetTrap(handler, name, defaultTrap) {
616 var trap = handler[name];
617 if (IS_UNDEFINED(trap)) {
618 if (IS_UNDEFINED(defaultTrap)) {
619 throw MakeTypeError("handler_trap_missing", [handler, name]);
620 }
621 trap = defaultTrap;
622 } else if (!IS_FUNCTION(trap)) {
623 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
624 }
625 return trap;
626}
627
628
629function CallTrap0(handler, name, defaultTrap) {
630 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
631}
632
633
634function CallTrap1(handler, name, defaultTrap, x) {
635 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
636}
637
638
639function CallTrap2(handler, name, defaultTrap, x, y) {
640 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
641}
642
643
Steve Block1e0659c2011-05-24 12:43:12 +0100644// ES5 section 8.12.1.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000645function GetOwnProperty(obj, v) {
646 var p = ToString(v);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000647 if (%IsJSProxy(obj)) {
648 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000649 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000650 if (IS_UNDEFINED(descriptor)) return descriptor;
651 var desc = ToCompletePropertyDescriptor(descriptor);
652 if (!desc.isConfigurable()) {
653 throw MakeTypeError("proxy_prop_not_configurable",
654 [handler, "getOwnPropertyDescriptor", p, descriptor]);
655 }
656 return desc;
657 }
658
Steve Block1e0659c2011-05-24 12:43:12 +0100659 // GetOwnProperty returns an array indexed by the constants
660 // defined in macros.py.
661 // If p is not a property on obj undefined is returned.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000662 var props = %GetOwnProperty(ToObject(obj), ToString(v));
Steve Block1e0659c2011-05-24 12:43:12 +0100663
664 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100665 if (props === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100666
667 return ConvertDescriptorArrayToDescriptor(props);
668}
669
670
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000671// Harmony proxies.
672function DefineProxyProperty(obj, p, attributes, should_throw) {
673 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000674 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000675 if (!ToBoolean(result)) {
676 if (should_throw) {
677 throw MakeTypeError("handler_returned_false",
678 [handler, "defineProperty"]);
679 } else {
680 return false;
681 }
682 }
683 return true;
684}
685
686
Steve Block6ded16b2010-05-10 14:33:55 +0100687// ES5 8.12.9.
Leon Clarkee46be812010-01-19 14:06:41 +0000688function DefineOwnProperty(obj, p, desc, should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000689 if (%IsJSProxy(obj)) {
690 var attributes = FromGenericPropertyDescriptor(desc);
691 return DefineProxyProperty(obj, p, attributes, should_throw);
692 }
693
Steve Block1e0659c2011-05-24 12:43:12 +0100694 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
695 // A false value here means that access checks failed.
Steve Block44f0eee2011-05-26 01:26:41 +0100696 if (current_or_access === false) return void 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100697
698 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
Andrei Popescu31002712010-02-23 13:46:05 +0000699 var extensible = %IsExtensible(ToObject(obj));
700
701 // Error handling according to spec.
702 // Step 3
Steve Block44f0eee2011-05-26 01:26:41 +0100703 if (IS_UNDEFINED(current) && !extensible) {
704 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000705 throw MakeTypeError("define_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100706 } else {
707 return;
708 }
709 }
Andrei Popescu31002712010-02-23 13:46:05 +0000710
Steve Block1e0659c2011-05-24 12:43:12 +0100711 if (!IS_UNDEFINED(current)) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100712 // Step 5 and 6
Steve Block1e0659c2011-05-24 12:43:12 +0100713 if ((IsGenericDescriptor(desc) ||
714 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
715 (!desc.hasEnumerable() ||
716 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100717 (!desc.hasConfigurable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100718 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
Ben Murdochf87a2032010-10-22 12:50:53 +0100719 (!desc.hasWritable() ||
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100720 SameValue(desc.isWritable(), current.isWritable())) &&
721 (!desc.hasValue() ||
722 SameValue(desc.getValue(), current.getValue())) &&
723 (!desc.hasGetter() ||
724 SameValue(desc.getGet(), current.getGet())) &&
725 (!desc.hasSetter() ||
726 SameValue(desc.getSet(), current.getSet()))) {
727 return true;
728 }
Steve Block1e0659c2011-05-24 12:43:12 +0100729 if (!current.isConfigurable()) {
730 // Step 7
731 if (desc.isConfigurable() ||
732 (desc.hasEnumerable() &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100733 desc.isEnumerable() != current.isEnumerable())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100734 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000735 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100736 } else {
737 return;
738 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100739 }
Steve Block1e0659c2011-05-24 12:43:12 +0100740 // Step 8
741 if (!IsGenericDescriptor(desc)) {
742 // Step 9a
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100743 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100744 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000745 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100746 } else {
747 return;
748 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100749 }
Steve Block1e0659c2011-05-24 12:43:12 +0100750 // Step 10a
751 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100752 if (!current.isWritable() && desc.isWritable()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100753 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000754 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100755 } else {
756 return;
757 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100758 }
Steve Block1e0659c2011-05-24 12:43:12 +0100759 if (!current.isWritable() && desc.hasValue() &&
760 !SameValue(desc.getValue(), current.getValue())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100761 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000762 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100763 } else {
764 return;
765 }
Steve Block1e0659c2011-05-24 12:43:12 +0100766 }
767 }
768 // Step 11
769 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100770 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100771 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000772 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100773 } else {
774 return;
775 }
Steve Block1e0659c2011-05-24 12:43:12 +0100776 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100777 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
Steve Block44f0eee2011-05-26 01:26:41 +0100778 if (should_throw) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000779 throw MakeTypeError("redefine_disallowed", [p]);
Steve Block44f0eee2011-05-26 01:26:41 +0100780 } else {
781 return;
782 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100783 }
Steve Block1e0659c2011-05-24 12:43:12 +0100784 }
Andrei Popescu31002712010-02-23 13:46:05 +0000785 }
786 }
Andrei Popescu31002712010-02-23 13:46:05 +0000787 }
788
Steve Block6ded16b2010-05-10 14:33:55 +0100789 // Send flags - enumerable and configurable are common - writable is
Andrei Popescu31002712010-02-23 13:46:05 +0000790 // only send to the data descriptor.
791 // Take special care if enumerable and configurable is not defined on
792 // desc (we need to preserve the existing values from current).
793 var flag = NONE;
794 if (desc.hasEnumerable()) {
795 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
796 } else if (!IS_UNDEFINED(current)) {
797 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
Leon Clarkee46be812010-01-19 14:06:41 +0000798 } else {
Andrei Popescu31002712010-02-23 13:46:05 +0000799 flag |= DONT_ENUM;
800 }
801
802 if (desc.hasConfigurable()) {
803 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
804 } else if (!IS_UNDEFINED(current)) {
805 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
806 } else
807 flag |= DONT_DELETE;
808
Steve Block1e0659c2011-05-24 12:43:12 +0100809 if (IsDataDescriptor(desc) ||
810 (IsGenericDescriptor(desc) &&
811 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
812 // There are 3 cases that lead here:
813 // Step 4a - defining a new data property.
814 // Steps 9b & 12 - replacing an existing accessor property with a data
815 // property.
816 // Step 12 - updating an existing data property with a data or generic
817 // descriptor.
818
Leon Clarkef7060e22010-06-03 12:02:55 +0100819 if (desc.hasWritable()) {
820 flag |= desc.isWritable() ? 0 : READ_ONLY;
821 } else if (!IS_UNDEFINED(current)) {
822 flag |= current.isWritable() ? 0 : READ_ONLY;
823 } else {
824 flag |= READ_ONLY;
825 }
Steve Block1e0659c2011-05-24 12:43:12 +0100826
Ben Murdochb0fe1622011-05-05 13:52:32 +0100827 var value = void 0; // Default value is undefined.
828 if (desc.hasValue()) {
829 value = desc.getValue();
Steve Block1e0659c2011-05-24 12:43:12 +0100830 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100831 value = current.getValue();
832 }
Steve Block1e0659c2011-05-24 12:43:12 +0100833
Ben Murdochb0fe1622011-05-05 13:52:32 +0100834 %DefineOrRedefineDataProperty(obj, p, value, flag);
Steve Block1e0659c2011-05-24 12:43:12 +0100835 } else if (IsGenericDescriptor(desc)) {
836 // Step 12 - updating an existing accessor property with generic
837 // descriptor. Changing flags only.
838 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
Andrei Popescu31002712010-02-23 13:46:05 +0000839 } else {
Steve Block1e0659c2011-05-24 12:43:12 +0100840 // There are 3 cases that lead here:
841 // Step 4b - defining a new accessor property.
842 // Steps 9c & 12 - replacing an existing data property with an accessor
843 // property.
844 // Step 12 - updating an existing accessor property with an accessor
845 // descriptor.
846 if (desc.hasGetter()) {
847 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
Andrei Popescu31002712010-02-23 13:46:05 +0000848 }
Steve Block1e0659c2011-05-24 12:43:12 +0100849 if (desc.hasSetter()) {
Andrei Popescu31002712010-02-23 13:46:05 +0000850 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
851 }
Leon Clarkee46be812010-01-19 14:06:41 +0000852 }
853 return true;
854}
855
856
857// ES5 section 15.2.3.2.
858function ObjectGetPrototypeOf(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100859 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000860 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000861 return %GetPrototype(obj);
Leon Clarkee46be812010-01-19 14:06:41 +0000862}
863
864
Steve Block6ded16b2010-05-10 14:33:55 +0100865// ES5 section 15.2.3.3
Leon Clarkee46be812010-01-19 14:06:41 +0000866function ObjectGetOwnPropertyDescriptor(obj, p) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100867 if (!IS_SPEC_OBJECT(obj))
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000868 throw MakeTypeError("obj_ctor_property_non_object",
869 ["getOwnPropertyDescriptor"]);
Leon Clarkee46be812010-01-19 14:06:41 +0000870 var desc = GetOwnProperty(obj, p);
871 return FromPropertyDescriptor(desc);
872}
873
874
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000875// For Harmony proxies
876function ToStringArray(obj, trap) {
877 if (!IS_SPEC_OBJECT(obj)) {
878 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
879 }
880 var n = ToUint32(obj.length);
881 var array = new $Array(n);
882 var names = {}
883 for (var index = 0; index < n; index++) {
884 var s = ToString(obj[index]);
885 if (s in names) {
886 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
887 }
888 array[index] = s;
889 names.s = 0;
890 }
891 return array;
892}
893
894
Leon Clarkee46be812010-01-19 14:06:41 +0000895// ES5 section 15.2.3.4.
896function ObjectGetOwnPropertyNames(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100897 if (!IS_SPEC_OBJECT(obj))
Leon Clarkee46be812010-01-19 14:06:41 +0000898 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
899
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000900 // Special handling for proxies.
901 if (%IsJSProxy(obj)) {
902 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000903 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000904 return ToStringArray(names, "getOwnPropertyNames");
905 }
906
Leon Clarkee46be812010-01-19 14:06:41 +0000907 // Find all the indexed properties.
908
909 // Get the local element names.
910 var propertyNames = %GetLocalElementNames(obj);
911
912 // Get names for indexed interceptor properties.
913 if (%GetInterceptorInfo(obj) & 1) {
914 var indexedInterceptorNames =
915 %GetIndexedInterceptorElementNames(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000916 if (indexedInterceptorNames)
Leon Clarkee46be812010-01-19 14:06:41 +0000917 propertyNames = propertyNames.concat(indexedInterceptorNames);
Leon Clarkee46be812010-01-19 14:06:41 +0000918 }
919
920 // Find all the named properties.
921
922 // Get the local property names.
923 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
924
925 // Get names for named interceptor properties if any.
926
927 if (%GetInterceptorInfo(obj) & 2) {
928 var namedInterceptorNames =
929 %GetNamedInterceptorPropertyNames(obj);
930 if (namedInterceptorNames) {
931 propertyNames = propertyNames.concat(namedInterceptorNames);
932 }
933 }
934
Steve Block8defd9f2010-07-08 12:39:36 +0100935 // Property names are expected to be unique strings.
936 var propertySet = {};
937 var j = 0;
938 for (var i = 0; i < propertyNames.length; ++i) {
939 var name = ToString(propertyNames[i]);
940 // We need to check for the exact property value since for intrinsic
941 // properties like toString if(propertySet["toString"]) will always
942 // succeed.
943 if (propertySet[name] === true)
944 continue;
945 propertySet[name] = true;
946 propertyNames[j++] = name;
947 }
948 propertyNames.length = j;
Andrei Popescu402d9372010-02-26 13:31:12 +0000949
Leon Clarkee46be812010-01-19 14:06:41 +0000950 return propertyNames;
951}
952
953
954// ES5 section 15.2.3.5.
955function ObjectCreate(proto, properties) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100956 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
Leon Clarkee46be812010-01-19 14:06:41 +0000957 throw MakeTypeError("proto_object_or_null", [proto]);
958 }
959 var obj = new $Object();
960 obj.__proto__ = proto;
961 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
962 return obj;
963}
964
965
Andrei Popescu31002712010-02-23 13:46:05 +0000966// ES5 section 15.2.3.6.
967function ObjectDefineProperty(obj, p, attributes) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100968 if (!IS_SPEC_OBJECT(obj)) {
Andrei Popescu31002712010-02-23 13:46:05 +0000969 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
Leon Clarkef7060e22010-06-03 12:02:55 +0100970 }
Andrei Popescu31002712010-02-23 13:46:05 +0000971 var name = ToString(p);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000972 if (%IsJSProxy(obj)) {
973 // Clone the attributes object for protection.
974 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
975 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
976 var attributesClone = {}
977 for (var a in attributes) {
978 attributesClone[a] = attributes[a];
979 }
980 DefineProxyProperty(obj, name, attributesClone, true);
981 // The following would implement the spec as in the current proposal,
982 // but after recent comments on es-discuss, is most likely obsolete.
983 /*
984 var defineObj = FromGenericPropertyDescriptor(desc);
985 var names = ObjectGetOwnPropertyNames(attributes);
986 var standardNames =
987 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
988 for (var i = 0; i < names.length; i++) {
989 var N = names[i];
990 if (!(%HasLocalProperty(standardNames, N))) {
991 var attr = GetOwnProperty(attributes, N);
992 DefineOwnProperty(descObj, N, attr, true);
993 }
994 }
995 // This is really confusing the types, but it is what the proxies spec
996 // currently requires:
997 desc = descObj;
998 */
999 } else {
1000 var desc = ToPropertyDescriptor(attributes);
1001 DefineOwnProperty(obj, name, desc, true);
1002 }
Andrei Popescu31002712010-02-23 13:46:05 +00001003 return obj;
1004}
1005
1006
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001007function GetOwnEnumerablePropertyNames(properties) {
1008 var names = new InternalArray();
1009 for (var key in properties) {
1010 if (%HasLocalProperty(properties, key)) {
1011 names.push(key);
1012 }
1013 }
1014 return names;
1015}
1016
1017
Andrei Popescu31002712010-02-23 13:46:05 +00001018// ES5 section 15.2.3.7.
Leon Clarkee46be812010-01-19 14:06:41 +00001019function ObjectDefineProperties(obj, properties) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001020 if (!IS_SPEC_OBJECT(obj))
Andrei Popescu31002712010-02-23 13:46:05 +00001021 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
Leon Clarkee46be812010-01-19 14:06:41 +00001022 var props = ToObject(properties);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001023 var names = GetOwnEnumerablePropertyNames(props);
1024 for (var i = 0; i < names.length; i++) {
1025 var name = names[i];
1026 var desc = ToPropertyDescriptor(props[name]);
1027 DefineOwnProperty(obj, name, desc, true);
Leon Clarkee46be812010-01-19 14:06:41 +00001028 }
Andrei Popescu31002712010-02-23 13:46:05 +00001029 return obj;
Leon Clarkee46be812010-01-19 14:06:41 +00001030}
1031
1032
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001033// Harmony proxies.
1034function ProxyFix(obj) {
1035 var handler = %GetHandler(obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001036 var props = CallTrap0(handler, "fix", void 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001037 if (IS_UNDEFINED(props)) {
1038 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1039 }
1040 %Fix(obj);
1041 ObjectDefineProperties(obj, props);
1042}
1043
1044
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001045// ES5 section 15.2.3.8.
1046function ObjectSeal(obj) {
1047 if (!IS_SPEC_OBJECT(obj)) {
1048 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
1049 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001050 if (%IsJSProxy(obj)) {
1051 ProxyFix(obj);
1052 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001053 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001054 for (var i = 0; i < names.length; i++) {
1055 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001056 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001057 if (desc.isConfigurable()) {
1058 desc.setConfigurable(false);
1059 DefineOwnProperty(obj, name, desc, true);
1060 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001061 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001062 %PreventExtensions(obj);
1063 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001064}
1065
1066
1067// ES5 section 15.2.3.9.
1068function ObjectFreeze(obj) {
1069 if (!IS_SPEC_OBJECT(obj)) {
1070 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
1071 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001072 if (%IsJSProxy(obj)) {
1073 ProxyFix(obj);
1074 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001075 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001076 for (var i = 0; i < names.length; i++) {
1077 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001078 var desc = GetOwnProperty(obj, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001079 if (desc.isWritable() || desc.isConfigurable()) {
1080 if (IsDataDescriptor(desc)) desc.setWritable(false);
1081 desc.setConfigurable(false);
1082 DefineOwnProperty(obj, name, desc, true);
1083 }
Ben Murdochf87a2032010-10-22 12:50:53 +01001084 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001085 %PreventExtensions(obj);
1086 return obj;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001087}
1088
1089
Steve Block8defd9f2010-07-08 12:39:36 +01001090// ES5 section 15.2.3.10
1091function ObjectPreventExtension(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001092 if (!IS_SPEC_OBJECT(obj)) {
Steve Block8defd9f2010-07-08 12:39:36 +01001093 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
1094 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001095 if (%IsJSProxy(obj)) {
1096 ProxyFix(obj);
1097 }
Steve Block8defd9f2010-07-08 12:39:36 +01001098 %PreventExtensions(obj);
1099 return obj;
1100}
1101
1102
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001103// ES5 section 15.2.3.11
1104function ObjectIsSealed(obj) {
1105 if (!IS_SPEC_OBJECT(obj)) {
1106 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
1107 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001108 if (%IsJSProxy(obj)) {
1109 return false;
1110 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001111 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001112 for (var i = 0; i < names.length; i++) {
1113 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001114 var desc = GetOwnProperty(obj, name);
1115 if (desc.isConfigurable()) return false;
1116 }
1117 if (!ObjectIsExtensible(obj)) {
1118 return true;
1119 }
1120 return false;
1121}
1122
1123
1124// ES5 section 15.2.3.12
1125function ObjectIsFrozen(obj) {
1126 if (!IS_SPEC_OBJECT(obj)) {
1127 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
1128 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001129 if (%IsJSProxy(obj)) {
1130 return false;
1131 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001132 var names = ObjectGetOwnPropertyNames(obj);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001133 for (var i = 0; i < names.length; i++) {
1134 var name = names[i];
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001135 var desc = GetOwnProperty(obj, name);
1136 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1137 if (desc.isConfigurable()) return false;
1138 }
1139 if (!ObjectIsExtensible(obj)) {
1140 return true;
1141 }
1142 return false;
1143}
1144
1145
Steve Block8defd9f2010-07-08 12:39:36 +01001146// ES5 section 15.2.3.13
1147function ObjectIsExtensible(obj) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001148 if (!IS_SPEC_OBJECT(obj)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001149 throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
1150 }
1151 if (%IsJSProxy(obj)) {
1152 return true;
Steve Block8defd9f2010-07-08 12:39:36 +01001153 }
1154 return %IsExtensible(obj);
1155}
1156
1157
Steve Blocka7e24c12009-10-30 11:49:00 +00001158%SetCode($Object, function(x) {
1159 if (%_IsConstructCall()) {
1160 if (x == null) return this;
1161 return ToObject(x);
1162 } else {
1163 if (x == null) return { };
1164 return ToObject(x);
1165 }
1166});
1167
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001168%SetExpectedNumberOfProperties($Object, 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00001169
1170// ----------------------------------------------------------------------------
1171
1172
1173function SetupObject() {
1174 // Setup non-enumerable functions on the Object.prototype object.
1175 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1176 "toString", ObjectToString,
1177 "toLocaleString", ObjectToLocaleString,
1178 "valueOf", ObjectValueOf,
1179 "hasOwnProperty", ObjectHasOwnProperty,
1180 "isPrototypeOf", ObjectIsPrototypeOf,
1181 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1182 "__defineGetter__", ObjectDefineGetter,
1183 "__lookupGetter__", ObjectLookupGetter,
1184 "__defineSetter__", ObjectDefineSetter,
1185 "__lookupSetter__", ObjectLookupSetter
1186 ));
1187 InstallFunctions($Object, DONT_ENUM, $Array(
Leon Clarkee46be812010-01-19 14:06:41 +00001188 "keys", ObjectKeys,
1189 "create", ObjectCreate,
Andrei Popescu31002712010-02-23 13:46:05 +00001190 "defineProperty", ObjectDefineProperty,
1191 "defineProperties", ObjectDefineProperties,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001192 "freeze", ObjectFreeze,
Leon Clarkee46be812010-01-19 14:06:41 +00001193 "getPrototypeOf", ObjectGetPrototypeOf,
1194 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
Steve Block8defd9f2010-07-08 12:39:36 +01001195 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1196 "isExtensible", ObjectIsExtensible,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001197 "isFrozen", ObjectIsFrozen,
1198 "isSealed", ObjectIsSealed,
1199 "preventExtensions", ObjectPreventExtension,
1200 "seal", ObjectSeal
Steve Blocka7e24c12009-10-30 11:49:00 +00001201 ));
1202}
1203
1204SetupObject();
1205
1206
1207// ----------------------------------------------------------------------------
1208// Boolean
1209
1210function BooleanToString() {
1211 // NOTE: Both Boolean objects and values can enter here as
1212 // 'this'. This is not as dictated by ECMA-262.
Ben Murdoch086aeea2011-05-13 15:57:08 +01001213 var b = this;
1214 if (!IS_BOOLEAN(b)) {
1215 if (!IS_BOOLEAN_WRAPPER(b)) {
1216 throw new $TypeError('Boolean.prototype.toString is not generic');
1217 }
1218 b = %_ValueOf(b);
1219 }
1220 return b ? 'true' : 'false';
Steve Blocka7e24c12009-10-30 11:49:00 +00001221}
1222
1223
1224function BooleanValueOf() {
1225 // NOTE: Both Boolean objects and values can enter here as
1226 // 'this'. This is not as dictated by ECMA-262.
1227 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
1228 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1229 return %_ValueOf(this);
1230}
1231
1232
Steve Blocka7e24c12009-10-30 11:49:00 +00001233// ----------------------------------------------------------------------------
1234
1235
1236function SetupBoolean() {
1237 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1238 "toString", BooleanToString,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001239 "valueOf", BooleanValueOf
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 ));
1241}
1242
1243SetupBoolean();
1244
1245// ----------------------------------------------------------------------------
1246// Number
1247
1248// Set the Number function and constructor.
1249%SetCode($Number, function(x) {
1250 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
1251 if (%_IsConstructCall()) {
1252 %_SetValueOf(this, value);
1253 } else {
1254 return value;
1255 }
1256});
1257
1258%FunctionSetPrototype($Number, new $Number(0));
1259
1260// ECMA-262 section 15.7.4.2.
1261function NumberToString(radix) {
1262 // NOTE: Both Number objects and values can enter here as
1263 // 'this'. This is not as dictated by ECMA-262.
1264 var number = this;
1265 if (!IS_NUMBER(this)) {
1266 if (!IS_NUMBER_WRAPPER(this))
1267 throw new $TypeError('Number.prototype.toString is not generic');
1268 // Get the value of this number in case it's an object.
1269 number = %_ValueOf(this);
1270 }
1271 // Fast case: Convert number in radix 10.
1272 if (IS_UNDEFINED(radix) || radix === 10) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001273 return %_NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 }
1275
1276 // Convert the radix to an integer and check the range.
1277 radix = TO_INTEGER(radix);
1278 if (radix < 2 || radix > 36) {
1279 throw new $RangeError('toString() radix argument must be between 2 and 36');
1280 }
1281 // Convert the number to a string in the given radix.
1282 return %NumberToRadixString(number, radix);
1283}
1284
1285
1286// ECMA-262 section 15.7.4.3
1287function NumberToLocaleString() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001288 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1289 throw MakeTypeError("called_on_null_or_undefined",
1290 ["Number.prototype.toLocaleString"]);
1291 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001292 return this.toString();
1293}
1294
1295
1296// ECMA-262 section 15.7.4.4
1297function NumberValueOf() {
1298 // NOTE: Both Number objects and values can enter here as
1299 // 'this'. This is not as dictated by ECMA-262.
1300 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
1301 throw new $TypeError('Number.prototype.valueOf is not generic');
1302 return %_ValueOf(this);
1303}
1304
1305
1306// ECMA-262 section 15.7.4.5
1307function NumberToFixed(fractionDigits) {
1308 var f = TO_INTEGER(fractionDigits);
1309 if (f < 0 || f > 20) {
1310 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1311 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001312 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1313 throw MakeTypeError("called_on_null_or_undefined",
1314 ["Number.prototype.toFixed"]);
1315 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 var x = ToNumber(this);
1317 return %NumberToFixed(x, f);
1318}
1319
1320
1321// ECMA-262 section 15.7.4.6
1322function NumberToExponential(fractionDigits) {
1323 var f = -1;
1324 if (!IS_UNDEFINED(fractionDigits)) {
1325 f = TO_INTEGER(fractionDigits);
1326 if (f < 0 || f > 20) {
1327 throw new $RangeError("toExponential() argument must be between 0 and 20");
1328 }
1329 }
Ben Murdoch257744e2011-11-30 15:57:28 +00001330 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1331 throw MakeTypeError("called_on_null_or_undefined",
1332 ["Number.prototype.toExponential"]);
1333 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 var x = ToNumber(this);
1335 return %NumberToExponential(x, f);
1336}
1337
1338
1339// ECMA-262 section 15.7.4.7
1340function NumberToPrecision(precision) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001341 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1342 throw MakeTypeError("called_on_null_or_undefined",
1343 ["Number.prototype.toPrecision"]);
1344 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1346 var p = TO_INTEGER(precision);
1347 if (p < 1 || p > 21) {
1348 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1349 }
1350 var x = ToNumber(this);
1351 return %NumberToPrecision(x, p);
1352}
1353
1354
Steve Blocka7e24c12009-10-30 11:49:00 +00001355// ----------------------------------------------------------------------------
1356
1357function SetupNumber() {
1358 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
1359 // Setup the constructor property on the Number prototype object.
1360 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1361
1362 %OptimizeObjectForAddingMultipleProperties($Number, 5);
1363 // ECMA-262 section 15.7.3.1.
1364 %SetProperty($Number,
1365 "MAX_VALUE",
1366 1.7976931348623157e+308,
1367 DONT_ENUM | DONT_DELETE | READ_ONLY);
1368
1369 // ECMA-262 section 15.7.3.2.
1370 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
1371
1372 // ECMA-262 section 15.7.3.3.
1373 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1374
1375 // ECMA-262 section 15.7.3.4.
1376 %SetProperty($Number,
1377 "NEGATIVE_INFINITY",
1378 -1/0,
1379 DONT_ENUM | DONT_DELETE | READ_ONLY);
1380
1381 // ECMA-262 section 15.7.3.5.
1382 %SetProperty($Number,
1383 "POSITIVE_INFINITY",
1384 1/0,
1385 DONT_ENUM | DONT_DELETE | READ_ONLY);
Andrei Popescu402d9372010-02-26 13:31:12 +00001386 %ToFastProperties($Number);
Steve Blocka7e24c12009-10-30 11:49:00 +00001387
1388 // Setup non-enumerable functions on the Number prototype object.
1389 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1390 "toString", NumberToString,
1391 "toLocaleString", NumberToLocaleString,
1392 "valueOf", NumberValueOf,
1393 "toFixed", NumberToFixed,
1394 "toExponential", NumberToExponential,
Ben Murdochb0fe1622011-05-05 13:52:32 +01001395 "toPrecision", NumberToPrecision
Steve Blocka7e24c12009-10-30 11:49:00 +00001396 ));
1397}
1398
1399SetupNumber();
1400
1401
Steve Blocka7e24c12009-10-30 11:49:00 +00001402// ----------------------------------------------------------------------------
1403// Function
1404
1405$Function.prototype.constructor = $Function;
1406
1407function FunctionSourceString(func) {
1408 if (!IS_FUNCTION(func)) {
1409 throw new $TypeError('Function.prototype.toString is not generic');
1410 }
1411
1412 var source = %FunctionGetSourceCode(func);
1413 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
1414 var name = %FunctionGetName(func);
1415 if (name) {
1416 // Mimic what KJS does.
1417 return 'function ' + name + '() { [native code] }';
1418 } else {
1419 return 'function () { [native code] }';
1420 }
1421 }
1422
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001423 var name = %FunctionNameShouldPrintAsAnonymous(func)
1424 ? 'anonymous'
1425 : %FunctionGetName(func);
Steve Blocka7e24c12009-10-30 11:49:00 +00001426 return 'function ' + name + source;
1427}
1428
1429
1430function FunctionToString() {
1431 return FunctionSourceString(this);
1432}
1433
1434
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001435// ES5 15.3.4.5
1436function FunctionBind(this_arg) { // Length is 1.
1437 if (!IS_FUNCTION(this)) {
1438 throw new $TypeError('Bind must be called on a function');
1439 }
1440 // this_arg is not an argument that should be bound.
Ben Murdochbb769b22010-08-11 14:56:33 +01001441 var argc_bound = (%_ArgumentsLength() || 1) - 1;
Steve Block1e0659c2011-05-24 12:43:12 +01001442 var fn = this;
1443 if (argc_bound == 0) {
1444 var result = function() {
1445 if (%_IsConstructCall()) {
1446 // %NewObjectFromBound implicitly uses arguments passed to this
1447 // function. We do not pass the arguments object explicitly to avoid
1448 // materializing it and guarantee that this function will be optimized.
1449 return %NewObjectFromBound(fn, null);
1450 }
1451
1452 return fn.apply(this_arg, arguments);
1453 };
1454 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001455 var bound_args = new InternalArray(argc_bound);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001456 for(var i = 0; i < argc_bound; i++) {
1457 bound_args[i] = %_Arguments(i+1);
Ben Murdochf87a2032010-10-22 12:50:53 +01001458 }
Steve Block1e0659c2011-05-24 12:43:12 +01001459
1460 var result = function() {
1461 // If this is a construct call we use a special runtime method
1462 // to generate the actual object using the bound function.
1463 if (%_IsConstructCall()) {
1464 // %NewObjectFromBound implicitly uses arguments passed to this
1465 // function. We do not pass the arguments object explicitly to avoid
1466 // materializing it and guarantee that this function will be optimized.
1467 return %NewObjectFromBound(fn, bound_args);
1468 }
1469
1470 // Combine the args we got from the bind call with the args
1471 // given as argument to the invocation.
1472 var argc = %_ArgumentsLength();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001473 var args = new InternalArray(argc + argc_bound);
Steve Block1e0659c2011-05-24 12:43:12 +01001474 // Add bound arguments.
1475 for (var i = 0; i < argc_bound; i++) {
1476 args[i] = bound_args[i];
1477 }
1478 // Add arguments from call.
1479 for (var i = 0; i < argc; i++) {
1480 args[argc_bound + i] = %_Arguments(i);
1481 }
1482 return fn.apply(this_arg, args);
1483 };
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001484 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001485
1486 // We already have caller and arguments properties on functions,
1487 // which are non-configurable. It therefore makes no sence to
1488 // try to redefine these as defined by the spec. The spec says
1489 // that bind should make these throw a TypeError if get or set
1490 // is called and make them non-enumerable and non-configurable.
Ben Murdochf87a2032010-10-22 12:50:53 +01001491 // To be consistent with our normal functions we leave this as it is.
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001492
1493 // Set the correct length.
1494 var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001495 %FunctionRemovePrototype(result);
1496 %FunctionSetBound(result);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001497 %BoundFunctionSetLength(result, length);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001498 return result;
1499}
1500
1501
Steve Blocka7e24c12009-10-30 11:49:00 +00001502function NewFunction(arg1) { // length == 1
1503 var n = %_ArgumentsLength();
1504 var p = '';
1505 if (n > 1) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001506 p = new InternalArray(n - 1);
Ben Murdoch086aeea2011-05-13 15:57:08 +01001507 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1508 p = Join(p, n - 1, ',', NonStringToString);
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 // If the formal parameters string include ) - an illegal
1510 // character - it may make the combined function expression
1511 // compile. We avoid this problem by checking for this early on.
1512 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1513 }
1514 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
1515 var source = '(function(' + p + ') {\n' + body + '\n})';
1516
1517 // The call to SetNewFunctionAttributes will ensure the prototype
1518 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001519 var f = %CompileString(source)();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001520 %FunctionMarkNameShouldPrintAsAnonymous(f);
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 return %SetNewFunctionAttributes(f);
1522}
1523
1524%SetCode($Function, NewFunction);
1525
1526// ----------------------------------------------------------------------------
1527
1528function SetupFunction() {
1529 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
Kristian Monsen50ef84f2010-07-29 15:18:00 +01001530 "bind", FunctionBind,
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 "toString", FunctionToString
1532 ));
1533}
1534
1535SetupFunction();