blob: 6a32d7bdd7c704c3a6a50dbd208129eff8ecf99b [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000028// This file relies on the fact that the following declarations have been made
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000029//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030// 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;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036// const $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000037//
38// in math.js:
39// const $floor = MathFloor
40
41const $isNaN = GlobalIsNaN;
42const $isFinite = GlobalIsFinite;
43
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000044
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000045// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000048// Helper function used to install functions on objects.
49function InstallFunctions(object, attributes, functions) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000050 if (functions.length >= 8) {
51 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
52 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000053 for (var i = 0; i < functions.length; i += 2) {
54 var key = functions[i];
55 var f = functions[i + 1];
56 %FunctionSetName(f, key);
57 %SetProperty(object, key, f, attributes);
58 }
ager@chromium.org5c838252010-02-19 08:53:10 +000059 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000060}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
ager@chromium.org9085a012009-05-11 19:22:57 +000062// Emulates JSC by installing functions on a hidden prototype that
63// lies above the current object/prototype. This lets you override
64// functions on String.prototype etc. and then restore the old function
65// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
66function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
67 var hidden_prototype = new $Object();
68 %SetHiddenPrototype(object, hidden_prototype);
69 InstallFunctions(hidden_prototype, attributes, functions);
70}
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000073// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
75
76// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000077function GlobalIsNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000078 var n = ToNumber(number);
79 return NUMBER_IS_NAN(n);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000080}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081
82
83// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000084function GlobalIsFinite(number) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000085 return %NumberIsFinite(ToNumber(number));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000086}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087
88
89// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000090function GlobalParseInt(string, radix) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000091 if (IS_UNDEFINED(radix)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 // Some people use parseInt instead of Math.floor. This
93 // optimization makes parseInt on a Smi 12 times faster (60ns
94 // vs 800ns). The following optimization makes parseInt on a
95 // non-Smi number 9 times faster (230ns vs 2070ns). Together
96 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
97 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +000098 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +000099 ((0.01 < string && string < 1e9) ||
100 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000101 // Truncate number.
102 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000104 radix = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 } else {
106 radix = TO_INT32(radix);
107 if (!(radix == 0 || (2 <= radix && radix <= 36)))
108 return $NaN;
109 }
110 return %StringParseInt(ToString(string), radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000111}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
113
114// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000115function GlobalParseFloat(string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 return %StringParseFloat(ToString(string));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000117}
118
119
120function GlobalEval(x) {
121 if (!IS_STRING(x)) return x;
122
ager@chromium.orge2902be2009-06-08 12:21:35 +0000123 var global_receiver = %GlobalReceiver(global);
124 var this_is_global_receiver = (this === global_receiver);
125 var global_is_detached = (global === global_receiver);
126
127 if (!this_is_global_receiver || global_is_detached) {
128 throw new $EvalError('The "this" object passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000129 'be the global object from which eval originated');
130 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000131
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000132 var f = %CompileString(x, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000133 if (!IS_FUNCTION(f)) return f;
134
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000135 return f.call(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000136}
137
138
139// execScript for IE compatibility.
140function GlobalExecScript(expr, lang) {
141 // NOTE: We don't care about the character casing.
142 if (!lang || /javascript/i.test(lang)) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000143 var f = %CompileString(ToString(expr), false);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000144 f.call(%GlobalReceiver(global));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000145 }
146 return null;
147}
148
149
150// ----------------------------------------------------------------------------
151
152
153function SetupGlobal() {
154 // ECMA 262 - 15.1.1.1.
155 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
156
157 // ECMA-262 - 15.1.1.2.
158 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
159
160 // ECMA-262 - 15.1.1.3.
161 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000162
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000163 // Setup non-enumerable function on the global object.
164 InstallFunctions(global, DONT_ENUM, $Array(
165 "isNaN", GlobalIsNaN,
166 "isFinite", GlobalIsFinite,
167 "parseInt", GlobalParseInt,
168 "parseFloat", GlobalParseFloat,
169 "eval", GlobalEval,
170 "execScript", GlobalExecScript
171 ));
172}
173
174SetupGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175
176
177// ----------------------------------------------------------------------------
178// Boolean (first part of definition)
179
180
181%SetCode($Boolean, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000182 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 %_SetValueOf(this, ToBoolean(x));
184 } else {
185 return ToBoolean(x);
186 }
187});
188
189%FunctionSetPrototype($Boolean, new $Boolean(false));
190
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000191%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192
193// ----------------------------------------------------------------------------
194// Object
195
196$Object.prototype.constructor = $Object;
197
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000198// ECMA-262 - 15.2.4.2
199function ObjectToString() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000200 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000201}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202
203
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000204// ECMA-262 - 15.2.4.3
205function ObjectToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000207}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208
209
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000210// ECMA-262 - 15.2.4.4
211function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000213}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214
215
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000216// ECMA-262 - 15.2.4.5
217function ObjectHasOwnProperty(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 return %HasLocalProperty(ToObject(this), ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000219}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220
221
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000222// ECMA-262 - 15.2.4.6
223function ObjectIsPrototypeOf(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
225 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000226}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227
228
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000229// ECMA-262 - 15.2.4.6
230function ObjectPropertyIsEnumerable(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231 if (this == null) return false;
232 if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
233 return %IsPropertyEnumerable(this, ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000234}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235
236
237// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000238function ObjectDefineGetter(name, fun) {
239 if (this == null) {
240 throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
241 }
242 if (!IS_FUNCTION(fun)) {
243 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
244 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000246}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247
248
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000249function ObjectLookupGetter(name) {
250 if (this == null) {
251 throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253 return %LookupAccessor(ToObject(this), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000254}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255
256
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000257function ObjectDefineSetter(name, fun) {
258 if (this == null) {
259 throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
260 }
261 if (!IS_FUNCTION(fun)) {
262 throw new $TypeError(
263 'Object.prototype.__defineSetter__: Expecting function');
264 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000266}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267
268
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000269function ObjectLookupSetter(name) {
270 if (this == null) {
271 throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 return %LookupAccessor(ToObject(this), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000274}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275
276
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000277function ObjectKeys(obj) {
278 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000279 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000280 return %LocalKeys(obj);
281}
282
283
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000284// ES5 8.10.1.
285function IsAccessorDescriptor(desc) {
286 if (IS_UNDEFINED(desc)) return false;
287 return desc.hasGetter_ || desc.hasSetter_;
288}
289
290
291// ES5 8.10.2.
292function IsDataDescriptor(desc) {
293 if (IS_UNDEFINED(desc)) return false;
294 return desc.hasValue_ || desc.hasWritable_;
295}
296
297
298// ES5 8.10.3.
299function IsGenericDescriptor(desc) {
300 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
301}
302
303
304function IsInconsistentDescriptor(desc) {
305 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
306}
307
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000308// ES5 8.10.4
309function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000310 if (IS_UNDEFINED(desc)) return desc;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000311 var obj = new $Object();
312 if (IsDataDescriptor(desc)) {
313 obj.value = desc.getValue();
314 obj.writable = desc.isWritable();
315 }
316 if (IsAccessorDescriptor(desc)) {
317 obj.get = desc.getGet();
318 obj.set = desc.getSet();
319 }
320 obj.enumerable = desc.isEnumerable();
321 obj.configurable = desc.isConfigurable();
322 return obj;
323}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000324
325// ES5 8.10.5.
326function ToPropertyDescriptor(obj) {
327 if (!IS_OBJECT(obj)) {
328 throw MakeTypeError("property_desc_object", [obj]);
329 }
330 var desc = new PropertyDescriptor();
331
332 if ("enumerable" in obj) {
333 desc.setEnumerable(ToBoolean(obj.enumerable));
334 }
335
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000336 if ("configurable" in obj) {
337 desc.setConfigurable(ToBoolean(obj.configurable));
338 }
339
340 if ("value" in obj) {
341 desc.setValue(obj.value);
342 }
343
344 if ("writable" in obj) {
345 desc.setWritable(ToBoolean(obj.writable));
346 }
347
348 if ("get" in obj) {
349 var get = obj.get;
350 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
351 throw MakeTypeError("getter_must_be_callable", [get]);
352 }
353 desc.setGet(get);
354 }
355
356 if ("set" in obj) {
357 var set = obj.set;
358 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
359 throw MakeTypeError("setter_must_be_callable", [set]);
360 }
361 desc.setSet(set);
362 }
363
364 if (IsInconsistentDescriptor(desc)) {
365 throw MakeTypeError("value_and_accessor", [obj]);
366 }
367 return desc;
368}
369
370
371function PropertyDescriptor() {
372 // Initialize here so they are all in-object and have the same map.
373 // Default values from ES5 8.6.1.
374 this.value_ = void 0;
375 this.hasValue_ = false;
376 this.writable_ = false;
377 this.hasWritable_ = false;
378 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000379 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000380 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000381 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000382 this.get_ = void 0;
383 this.hasGetter_ = false;
384 this.set_ = void 0;
385 this.hasSetter_ = false;
386}
387
388
389PropertyDescriptor.prototype.setValue = function(value) {
390 this.value_ = value;
391 this.hasValue_ = true;
392}
393
394
395PropertyDescriptor.prototype.getValue = function() {
396 return this.value_;
397}
398
399
ager@chromium.org5c838252010-02-19 08:53:10 +0000400PropertyDescriptor.prototype.hasValue = function() {
401 return this.hasValue_;
402}
403
404
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000405PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
406 this.enumerable_ = enumerable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000407 this.hasEnumerable_ = true;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000408}
409
410
411PropertyDescriptor.prototype.isEnumerable = function () {
412 return this.enumerable_;
413}
414
415
ager@chromium.org5c838252010-02-19 08:53:10 +0000416PropertyDescriptor.prototype.hasEnumerable = function() {
417 return this.hasEnumerable_;
418}
419
420
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000421PropertyDescriptor.prototype.setWritable = function(writable) {
422 this.writable_ = writable;
423 this.hasWritable_ = true;
424}
425
426
427PropertyDescriptor.prototype.isWritable = function() {
428 return this.writable_;
429}
430
431
432PropertyDescriptor.prototype.setConfigurable = function(configurable) {
433 this.configurable_ = configurable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000434 this.hasConfigurable_ = true;
435}
436
437
438PropertyDescriptor.prototype.hasConfigurable = function() {
439 return this.hasConfigurable_;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000440}
441
442
443PropertyDescriptor.prototype.isConfigurable = function() {
444 return this.configurable_;
445}
446
447
448PropertyDescriptor.prototype.setGet = function(get) {
449 this.get_ = get;
450 this.hasGetter_ = true;
451}
452
453
454PropertyDescriptor.prototype.getGet = function() {
455 return this.get_;
456}
457
458
ager@chromium.org5c838252010-02-19 08:53:10 +0000459PropertyDescriptor.prototype.hasGetter = function() {
460 return this.hasGetter_;
461}
462
463
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000464PropertyDescriptor.prototype.setSet = function(set) {
465 this.set_ = set;
466 this.hasSetter_ = true;
467}
468
469
470PropertyDescriptor.prototype.getSet = function() {
471 return this.set_;
472}
473
474
ager@chromium.org5c838252010-02-19 08:53:10 +0000475PropertyDescriptor.prototype.hasSetter = function() {
476 return this.hasSetter_;
477}
478
479
480
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000481// ES5 section 8.12.1.
482function GetOwnProperty(obj, p) {
483 var desc = new PropertyDescriptor();
484
485 // An array with:
486 // obj is a data property [false, value, Writeable, Enumerable, Configurable]
487 // obj is an accessor [true, Get, Set, Enumerable, Configurable]
488 var props = %GetOwnProperty(ToObject(obj), ToString(p));
489
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 if (IS_UNDEFINED(props)) return void 0;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000491
492 // This is an accessor
493 if (props[0]) {
494 desc.setGet(props[1]);
495 desc.setSet(props[2]);
496 } else {
497 desc.setValue(props[1]);
498 desc.setWritable(props[2]);
499 }
500 desc.setEnumerable(props[3]);
501 desc.setConfigurable(props[4]);
502
503 return desc;
504}
505
506
ager@chromium.org5c838252010-02-19 08:53:10 +0000507// ES5 section 8.12.2.
508function GetProperty(obj, p) {
509 var prop = GetOwnProperty(obj);
510 if (!IS_UNDEFINED(prop)) return prop;
511 var proto = obj.__proto__;
512 if (IS_NULL(proto)) return void 0;
513 return GetProperty(proto, p);
514}
515
516
517// ES5 section 8.12.6
518function HasProperty(obj, p) {
519 var desc = GetProperty(obj, p);
520 return IS_UNDEFINED(desc) ? false : true;
521}
522
523
524// ES5 8.12.9.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525function DefineOwnProperty(obj, p, desc, should_throw) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000526 var current = GetOwnProperty(obj, p);
527 var extensible = %IsExtensible(ToObject(obj));
528
529 // Error handling according to spec.
530 // Step 3
531 if (IS_UNDEFINED(current) && !extensible)
532 throw MakeTypeError("define_disallowed", ["defineProperty"]);
533
534 if (!IS_UNDEFINED(current) && !current.isConfigurable()) {
535 // Step 7
536 if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable())
537 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
538 // Step 9
539 if (IsDataDescriptor(current) != IsDataDescriptor(desc))
540 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
541 // Step 10
542 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
543 if (!current.isWritable() && desc.isWritable())
544 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
545 if (!current.isWritable() && desc.hasValue() &&
546 !SameValue(desc.getValue(), current.getValue())) {
547 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
548 }
549 }
550 // Step 11
551 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
552 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){
553 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
554 }
555 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet()))
556 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
557 }
558 }
559
560 // Send flags - enumerable and configurable are common - writable is
561 // only send to the data descriptor.
562 // Take special care if enumerable and configurable is not defined on
563 // desc (we need to preserve the existing values from current).
564 var flag = NONE;
565 if (desc.hasEnumerable()) {
566 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
567 } else if (!IS_UNDEFINED(current)) {
568 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 flag |= DONT_ENUM;
571 }
572
573 if (desc.hasConfigurable()) {
574 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
575 } else if (!IS_UNDEFINED(current)) {
576 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
577 } else
578 flag |= DONT_DELETE;
579
580 if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) {
581 flag |= desc.isWritable() ? 0 : READ_ONLY;
582 %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag);
583 } else {
584 if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) {
585 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
586 }
587 if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) {
588 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
589 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590 }
591 return true;
592}
593
594
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000595// ES5 section 15.2.3.2.
596function ObjectGetPrototypeOf(obj) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000597 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
598 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
599 return obj.__proto__;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000600}
601
602
603// ES5 section 15.2.3.3
604function ObjectGetOwnPropertyDescriptor(obj, p) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000605 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
606 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000607 var desc = GetOwnProperty(obj, p);
608 return FromPropertyDescriptor(desc);
609}
610
611
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000612// ES5 section 15.2.3.4.
613function ObjectGetOwnPropertyNames(obj) {
614 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
615 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
616
617 // Find all the indexed properties.
618
619 // Get the local element names.
620 var propertyNames = %GetLocalElementNames(obj);
621
622 // Get names for indexed interceptor properties.
623 if (%GetInterceptorInfo(obj) & 1) {
624 var indexedInterceptorNames =
625 %GetIndexedInterceptorElementNames(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000626 if (indexedInterceptorNames)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000627 propertyNames = propertyNames.concat(indexedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000628 }
629
630 // Find all the named properties.
631
632 // Get the local property names.
633 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
634
635 // Get names for named interceptor properties if any.
636
637 if (%GetInterceptorInfo(obj) & 2) {
638 var namedInterceptorNames =
639 %GetNamedInterceptorPropertyNames(obj);
640 if (namedInterceptorNames) {
641 propertyNames = propertyNames.concat(namedInterceptorNames);
642 }
643 }
644
ager@chromium.org5c838252010-02-19 08:53:10 +0000645 // Property names are expected to be strings.
646 for (var i = 0; i < propertyNames.length; ++i)
647 propertyNames[i] = ToString(propertyNames[i]);
648
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000649 return propertyNames;
650}
651
652
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000653// ES5 section 15.2.3.5.
654function ObjectCreate(proto, properties) {
655 if (!IS_OBJECT(proto) && !IS_NULL(proto)) {
656 throw MakeTypeError("proto_object_or_null", [proto]);
657 }
658 var obj = new $Object();
659 obj.__proto__ = proto;
660 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
661 return obj;
662}
663
664
ager@chromium.org5c838252010-02-19 08:53:10 +0000665// ES5 section 15.2.3.6.
666function ObjectDefineProperty(obj, p, attributes) {
667 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
668 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
669 var name = ToString(p);
670 var desc = ToPropertyDescriptor(attributes);
671 DefineOwnProperty(obj, name, desc, true);
672 return obj;
673}
674
675
676// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000677function ObjectDefineProperties(obj, properties) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000678 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
679 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000680 var props = ToObject(properties);
681 var key_values = [];
682 for (var key in props) {
683 if (%HasLocalProperty(props, key)) {
684 key_values.push(key);
685 var value = props[key];
686 var desc = ToPropertyDescriptor(value);
687 key_values.push(desc);
688 }
689 }
690 for (var i = 0; i < key_values.length; i += 2) {
691 var key = key_values[i];
692 var desc = key_values[i + 1];
693 DefineOwnProperty(obj, key, desc, true);
694 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000695 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000696}
697
698
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000700 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701 if (x == null) return this;
702 return ToObject(x);
703 } else {
704 if (x == null) return { };
705 return ToObject(x);
706 }
707});
708
709
710// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711
712
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000713function SetupObject() {
714 // Setup non-enumerable functions on the Object.prototype object.
715 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
716 "toString", ObjectToString,
717 "toLocaleString", ObjectToLocaleString,
718 "valueOf", ObjectValueOf,
719 "hasOwnProperty", ObjectHasOwnProperty,
720 "isPrototypeOf", ObjectIsPrototypeOf,
721 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
722 "__defineGetter__", ObjectDefineGetter,
723 "__lookupGetter__", ObjectLookupGetter,
724 "__defineSetter__", ObjectDefineSetter,
725 "__lookupSetter__", ObjectLookupSetter
726 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000727 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000728 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000729 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +0000730 "defineProperty", ObjectDefineProperty,
731 "defineProperties", ObjectDefineProperties,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000732 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000733 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
734 "getOwnPropertyNames", ObjectGetOwnPropertyNames
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000735 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000736}
737
738SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739
740
741// ----------------------------------------------------------------------------
742// Boolean
743
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000744function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745 // NOTE: Both Boolean objects and values can enter here as
746 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000747 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748 throw new $TypeError('Boolean.prototype.toString is not generic');
749 return ToString(%_ValueOf(this));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000750}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751
752
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000753function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 // NOTE: Both Boolean objects and values can enter here as
755 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000756 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000757 throw new $TypeError('Boolean.prototype.valueOf is not generic');
758 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000759}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760
761
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000762function BooleanToJSON(key) {
763 return CheckJSONPrimitive(this.valueOf());
764}
765
766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000767// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000768
769
770function SetupBoolean() {
771 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
772 "toString", BooleanToString,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000773 "valueOf", BooleanValueOf,
774 "toJSON", BooleanToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000775 ));
776}
777
778SetupBoolean();
779
780// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781// Number
782
783// Set the Number function and constructor.
784%SetCode($Number, function(x) {
785 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000786 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 %_SetValueOf(this, value);
788 } else {
789 return value;
790 }
791});
792
793%FunctionSetPrototype($Number, new $Number(0));
794
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000796function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 // NOTE: Both Number objects and values can enter here as
798 // 'this'. This is not as dictated by ECMA-262.
799 var number = this;
800 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000801 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000802 throw new $TypeError('Number.prototype.toString is not generic');
803 // Get the value of this number in case it's an object.
804 number = %_ValueOf(this);
805 }
806 // Fast case: Convert number in radix 10.
807 if (IS_UNDEFINED(radix) || radix === 10) {
808 return ToString(number);
809 }
810
811 // Convert the radix to an integer and check the range.
812 radix = TO_INTEGER(radix);
813 if (radix < 2 || radix > 36) {
814 throw new $RangeError('toString() radix argument must be between 2 and 36');
815 }
816 // Convert the number to a string in the given radix.
817 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000818}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819
820
821// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000822function NumberToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000824}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825
826
827// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000828function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 // NOTE: Both Number objects and values can enter here as
830 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000831 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 throw new $TypeError('Number.prototype.valueOf is not generic');
833 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000834}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835
836
837// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000838function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 var f = TO_INTEGER(fractionDigits);
840 if (f < 0 || f > 20) {
841 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
842 }
843 var x = ToNumber(this);
844 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000845}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846
847
848// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000849function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 var f = -1;
851 if (!IS_UNDEFINED(fractionDigits)) {
852 f = TO_INTEGER(fractionDigits);
853 if (f < 0 || f > 20) {
854 throw new $RangeError("toExponential() argument must be between 0 and 20");
855 }
856 }
857 var x = ToNumber(this);
858 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000859}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860
861
862// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000863function NumberToPrecision(precision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
865 var p = TO_INTEGER(precision);
866 if (p < 1 || p > 21) {
867 throw new $RangeError("toPrecision() argument must be between 1 and 21");
868 }
869 var x = ToNumber(this);
870 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000871}
872
873
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000874function CheckJSONPrimitive(val) {
875 if (!IsPrimitive(val))
876 throw MakeTypeError('result_not_primitive', ['toJSON', val]);
877 return val;
878}
879
880
881function NumberToJSON(key) {
882 return CheckJSONPrimitive(this.valueOf());
883}
884
885
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000886// ----------------------------------------------------------------------------
887
888function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000889 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000890 // Setup the constructor property on the Number prototype object.
891 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
892
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000893 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000894 // ECMA-262 section 15.7.3.1.
895 %SetProperty($Number,
896 "MAX_VALUE",
897 1.7976931348623157e+308,
898 DONT_ENUM | DONT_DELETE | READ_ONLY);
899
900 // ECMA-262 section 15.7.3.2.
901 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
902
903 // ECMA-262 section 15.7.3.3.
904 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
905
906 // ECMA-262 section 15.7.3.4.
907 %SetProperty($Number,
908 "NEGATIVE_INFINITY",
909 -1/0,
910 DONT_ENUM | DONT_DELETE | READ_ONLY);
911
912 // ECMA-262 section 15.7.3.5.
913 %SetProperty($Number,
914 "POSITIVE_INFINITY",
915 1/0,
916 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +0000917 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000918
919 // Setup non-enumerable functions on the Number prototype object.
920 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
921 "toString", NumberToString,
922 "toLocaleString", NumberToLocaleString,
923 "valueOf", NumberValueOf,
924 "toFixed", NumberToFixed,
925 "toExponential", NumberToExponential,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000926 "toPrecision", NumberToPrecision,
927 "toJSON", NumberToJSON
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000928 ));
929}
930
931SetupNumber();
932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933
934
935// ----------------------------------------------------------------------------
936// Function
937
938$Function.prototype.constructor = $Function;
939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000941 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944
945 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000946 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 var name = %FunctionGetName(func);
948 if (name) {
949 // Mimic what KJS does.
950 return 'function ' + name + '() { [native code] }';
951 } else {
952 return 'function () { [native code] }';
953 }
954 }
955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 var name = %FunctionGetName(func);
957 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000958}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
960
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000961function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000963}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964
965
966function NewFunction(arg1) { // length == 1
967 var n = %_ArgumentsLength();
968 var p = '';
969 if (n > 1) {
970 p = new $Array(n - 1);
971 // Explicitly convert all parameters to strings.
972 // Array.prototype.join replaces null with empty strings which is
973 // not appropriate.
974 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
975 p = p.join(',');
976 // If the formal parameters string include ) - an illegal
977 // character - it may make the combined function expression
978 // compile. We avoid this problem by checking for this early on.
979 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
980 }
981 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +0000982 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983
984 // The call to SetNewFunctionAttributes will ensure the prototype
985 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000986 var f = %CompileString(source, false)();
ager@chromium.org236ad962008-09-25 09:45:57 +0000987 %FunctionSetName(f, "anonymous");
988 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000989}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990
991%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000992
993// ----------------------------------------------------------------------------
994
995function SetupFunction() {
996 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
997 "toString", FunctionToString
998 ));
999}
1000
1001SetupFunction();