blob: 83b00b0f139301efff199d9a72f0418227006911 [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);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000057 %FunctionRemovePrototype(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000058 %SetProperty(object, key, f, attributes);
59 }
ager@chromium.org5c838252010-02-19 08:53:10 +000060 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000061}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
ager@chromium.org9085a012009-05-11 19:22:57 +000063// Emulates JSC by installing functions on a hidden prototype that
64// lies above the current object/prototype. This lets you override
65// functions on String.prototype etc. and then restore the old function
66// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
67function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
68 var hidden_prototype = new $Object();
69 %SetHiddenPrototype(object, hidden_prototype);
70 InstallFunctions(hidden_prototype, attributes, functions);
71}
72
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000074// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075
76
77// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000078function GlobalIsNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000079 var n = ToNumber(number);
80 return NUMBER_IS_NAN(n);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000081}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082
83
84// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000085function GlobalIsFinite(number) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000086 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
lrn@chromium.org25156de2010-04-06 13:10:27 +000087
88 // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
89 return %_IsSmi(number) || number - number == 0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000090}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091
92
93// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000094function GlobalParseInt(string, radix) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000095 if (IS_UNDEFINED(radix)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 // Some people use parseInt instead of Math.floor. This
97 // optimization makes parseInt on a Smi 12 times faster (60ns
98 // vs 800ns). The following optimization makes parseInt on a
99 // non-Smi number 9 times faster (230ns vs 2070ns). Together
100 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
101 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000102 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000103 ((0.01 < string && string < 1e9) ||
104 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000105 // Truncate number.
106 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000108 radix = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109 } else {
110 radix = TO_INT32(radix);
111 if (!(radix == 0 || (2 <= radix && radix <= 36)))
112 return $NaN;
113 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000114 string = TO_STRING_INLINE(string);
115 if (%_HasCachedArrayIndex(string) &&
116 (radix == 0 || radix == 10)) {
117 return %_GetCachedArrayIndex(string);
118 }
119 return %StringParseInt(string, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000120}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121
122
123// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000124function GlobalParseFloat(string) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000125 string = TO_STRING_INLINE(string);
126 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
127 return %StringParseFloat(string);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000128}
129
130
131function GlobalEval(x) {
132 if (!IS_STRING(x)) return x;
133
ager@chromium.orge2902be2009-06-08 12:21:35 +0000134 var global_receiver = %GlobalReceiver(global);
135 var this_is_global_receiver = (this === global_receiver);
136 var global_is_detached = (global === global_receiver);
137
138 if (!this_is_global_receiver || global_is_detached) {
139 throw new $EvalError('The "this" object passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000140 'be the global object from which eval originated');
141 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000142
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000143 var f = %CompileString(x);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000144 if (!IS_FUNCTION(f)) return f;
145
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000146 return f.call(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000147}
148
149
150// execScript for IE compatibility.
151function GlobalExecScript(expr, lang) {
152 // NOTE: We don't care about the character casing.
153 if (!lang || /javascript/i.test(lang)) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000154 var f = %CompileString(ToString(expr));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000155 f.call(%GlobalReceiver(global));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000156 }
157 return null;
158}
159
160
161// ----------------------------------------------------------------------------
162
163
164function SetupGlobal() {
165 // ECMA 262 - 15.1.1.1.
166 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
167
168 // ECMA-262 - 15.1.1.2.
169 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
170
171 // ECMA-262 - 15.1.1.3.
172 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000173
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000174 // Setup non-enumerable function on the global object.
175 InstallFunctions(global, DONT_ENUM, $Array(
176 "isNaN", GlobalIsNaN,
177 "isFinite", GlobalIsFinite,
178 "parseInt", GlobalParseInt,
179 "parseFloat", GlobalParseFloat,
180 "eval", GlobalEval,
181 "execScript", GlobalExecScript
182 ));
183}
184
185SetupGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186
187
188// ----------------------------------------------------------------------------
189// Boolean (first part of definition)
190
191
192%SetCode($Boolean, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000193 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 %_SetValueOf(this, ToBoolean(x));
195 } else {
196 return ToBoolean(x);
197 }
198});
199
200%FunctionSetPrototype($Boolean, new $Boolean(false));
201
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000202%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203
204// ----------------------------------------------------------------------------
205// Object
206
207$Object.prototype.constructor = $Object;
208
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000209// ECMA-262 - 15.2.4.2
210function ObjectToString() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000212}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000213
214
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000215// ECMA-262 - 15.2.4.3
216function ObjectToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000218}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219
220
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000221// ECMA-262 - 15.2.4.4
222function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000223 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000224}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225
226
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000227// ECMA-262 - 15.2.4.5
228function ObjectHasOwnProperty(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229 return %HasLocalProperty(ToObject(this), ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000230}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231
232
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000233// ECMA-262 - 15.2.4.6
234function ObjectIsPrototypeOf(V) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000235 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000237}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
239
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000240// ECMA-262 - 15.2.4.6
241function ObjectPropertyIsEnumerable(V) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000242 return %IsPropertyEnumerable(ToObject(this), ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000243}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244
245
246// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000247function ObjectDefineGetter(name, fun) {
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000248 if (this == null && !IS_UNDETECTABLE(this)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000249 throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
250 }
251 if (!IS_FUNCTION(fun)) {
252 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
253 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000255}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000256
257
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000258function ObjectLookupGetter(name) {
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000259 if (this == null && !IS_UNDETECTABLE(this)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000260 throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262 return %LookupAccessor(ToObject(this), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000263}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000264
265
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000266function ObjectDefineSetter(name, fun) {
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000267 if (this == null && !IS_UNDETECTABLE(this)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000268 throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
269 }
270 if (!IS_FUNCTION(fun)) {
271 throw new $TypeError(
272 'Object.prototype.__defineSetter__: Expecting function');
273 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000275}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276
277
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000278function ObjectLookupSetter(name) {
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000279 if (this == null && !IS_UNDETECTABLE(this)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000280 throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282 return %LookupAccessor(ToObject(this), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000283}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284
285
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000286function ObjectKeys(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000287 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000288 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000289 return %LocalKeys(obj);
290}
291
292
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000293// ES5 8.10.1.
294function IsAccessorDescriptor(desc) {
295 if (IS_UNDEFINED(desc)) return false;
296 return desc.hasGetter_ || desc.hasSetter_;
297}
298
299
300// ES5 8.10.2.
301function IsDataDescriptor(desc) {
302 if (IS_UNDEFINED(desc)) return false;
303 return desc.hasValue_ || desc.hasWritable_;
304}
305
306
307// ES5 8.10.3.
308function IsGenericDescriptor(desc) {
309 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
310}
311
312
313function IsInconsistentDescriptor(desc) {
314 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
315}
316
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000317// ES5 8.10.4
318function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000319 if (IS_UNDEFINED(desc)) return desc;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000320 var obj = new $Object();
321 if (IsDataDescriptor(desc)) {
322 obj.value = desc.getValue();
323 obj.writable = desc.isWritable();
324 }
325 if (IsAccessorDescriptor(desc)) {
326 obj.get = desc.getGet();
327 obj.set = desc.getSet();
328 }
329 obj.enumerable = desc.isEnumerable();
330 obj.configurable = desc.isConfigurable();
331 return obj;
332}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000333
334// ES5 8.10.5.
335function ToPropertyDescriptor(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000336 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000337 throw MakeTypeError("property_desc_object", [obj]);
338 }
339 var desc = new PropertyDescriptor();
340
341 if ("enumerable" in obj) {
342 desc.setEnumerable(ToBoolean(obj.enumerable));
343 }
344
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000345 if ("configurable" in obj) {
346 desc.setConfigurable(ToBoolean(obj.configurable));
347 }
348
349 if ("value" in obj) {
350 desc.setValue(obj.value);
351 }
352
353 if ("writable" in obj) {
354 desc.setWritable(ToBoolean(obj.writable));
355 }
356
357 if ("get" in obj) {
358 var get = obj.get;
359 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
360 throw MakeTypeError("getter_must_be_callable", [get]);
361 }
362 desc.setGet(get);
363 }
364
365 if ("set" in obj) {
366 var set = obj.set;
367 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
368 throw MakeTypeError("setter_must_be_callable", [set]);
369 }
370 desc.setSet(set);
371 }
372
373 if (IsInconsistentDescriptor(desc)) {
374 throw MakeTypeError("value_and_accessor", [obj]);
375 }
376 return desc;
377}
378
379
380function PropertyDescriptor() {
381 // Initialize here so they are all in-object and have the same map.
382 // Default values from ES5 8.6.1.
383 this.value_ = void 0;
384 this.hasValue_ = false;
385 this.writable_ = false;
386 this.hasWritable_ = false;
387 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000388 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000389 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000390 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000391 this.get_ = void 0;
392 this.hasGetter_ = false;
393 this.set_ = void 0;
394 this.hasSetter_ = false;
395}
396
397
398PropertyDescriptor.prototype.setValue = function(value) {
399 this.value_ = value;
400 this.hasValue_ = true;
401}
402
403
404PropertyDescriptor.prototype.getValue = function() {
405 return this.value_;
406}
407
408
ager@chromium.org5c838252010-02-19 08:53:10 +0000409PropertyDescriptor.prototype.hasValue = function() {
410 return this.hasValue_;
411}
412
413
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000414PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
415 this.enumerable_ = enumerable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000416 this.hasEnumerable_ = true;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000417}
418
419
420PropertyDescriptor.prototype.isEnumerable = function () {
421 return this.enumerable_;
422}
423
424
ager@chromium.org5c838252010-02-19 08:53:10 +0000425PropertyDescriptor.prototype.hasEnumerable = function() {
426 return this.hasEnumerable_;
427}
428
429
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000430PropertyDescriptor.prototype.setWritable = function(writable) {
431 this.writable_ = writable;
432 this.hasWritable_ = true;
433}
434
435
436PropertyDescriptor.prototype.isWritable = function() {
437 return this.writable_;
438}
439
440
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000441PropertyDescriptor.prototype.hasWritable = function() {
442 return this.hasWritable_;
443}
444
445
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000446PropertyDescriptor.prototype.setConfigurable = function(configurable) {
447 this.configurable_ = configurable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000448 this.hasConfigurable_ = true;
449}
450
451
452PropertyDescriptor.prototype.hasConfigurable = function() {
453 return this.hasConfigurable_;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000454}
455
456
457PropertyDescriptor.prototype.isConfigurable = function() {
458 return this.configurable_;
459}
460
461
462PropertyDescriptor.prototype.setGet = function(get) {
463 this.get_ = get;
464 this.hasGetter_ = true;
465}
466
467
468PropertyDescriptor.prototype.getGet = function() {
469 return this.get_;
470}
471
472
ager@chromium.org5c838252010-02-19 08:53:10 +0000473PropertyDescriptor.prototype.hasGetter = function() {
474 return this.hasGetter_;
475}
476
477
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478PropertyDescriptor.prototype.setSet = function(set) {
479 this.set_ = set;
480 this.hasSetter_ = true;
481}
482
483
484PropertyDescriptor.prototype.getSet = function() {
485 return this.set_;
486}
487
488
ager@chromium.org5c838252010-02-19 08:53:10 +0000489PropertyDescriptor.prototype.hasSetter = function() {
490 return this.hasSetter_;
491}
492
493
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000494// Converts an array returned from Runtime_GetOwnProperty to an actual
495// property descriptor. For a description of the array layout please
496// see the runtime.cc file.
497function ConvertDescriptorArrayToDescriptor(desc_array) {
498 if (desc_array == false) {
499 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000500 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000501
502 if (IS_UNDEFINED(desc_array)) {
503 return void 0;
504 }
505
506 var desc = new PropertyDescriptor();
507 // This is an accessor.
508 if (desc_array[IS_ACCESSOR_INDEX]) {
509 desc.setGet(desc_array[GETTER_INDEX]);
510 desc.setSet(desc_array[SETTER_INDEX]);
511 } else {
512 desc.setValue(desc_array[VALUE_INDEX]);
513 desc.setWritable(desc_array[WRITABLE_INDEX]);
514 }
515 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
516 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000517
518 return desc;
519}
520
521
ager@chromium.org5c838252010-02-19 08:53:10 +0000522// ES5 section 8.12.2.
523function GetProperty(obj, p) {
524 var prop = GetOwnProperty(obj);
525 if (!IS_UNDEFINED(prop)) return prop;
526 var proto = obj.__proto__;
527 if (IS_NULL(proto)) return void 0;
528 return GetProperty(proto, p);
529}
530
531
532// ES5 section 8.12.6
533function HasProperty(obj, p) {
534 var desc = GetProperty(obj, p);
535 return IS_UNDEFINED(desc) ? false : true;
536}
537
538
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000539// ES5 section 8.12.1.
540function GetOwnProperty(obj, p) {
541 // GetOwnProperty returns an array indexed by the constants
542 // defined in macros.py.
543 // If p is not a property on obj undefined is returned.
544 var props = %GetOwnProperty(ToObject(obj), ToString(p));
545
546 // A false value here means that access checks failed.
547 if (props == false) return void 0;
548
549 return ConvertDescriptorArrayToDescriptor(props);
550}
551
552
lrn@chromium.org25156de2010-04-06 13:10:27 +0000553// ES5 8.12.9.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554function DefineOwnProperty(obj, p, desc, should_throw) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000555 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
556 // A false value here means that access checks failed.
557 if (current_or_access == false) return void 0;
558
559 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000560 var extensible = %IsExtensible(ToObject(obj));
561
562 // Error handling according to spec.
563 // Step 3
564 if (IS_UNDEFINED(current) && !extensible)
565 throw MakeTypeError("define_disallowed", ["defineProperty"]);
566
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000567 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000568 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000569 if ((IsGenericDescriptor(desc) ||
570 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
571 (!desc.hasEnumerable() ||
572 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000573 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000574 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000575 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000576 SameValue(desc.isWritable(), current.isWritable())) &&
577 (!desc.hasValue() ||
578 SameValue(desc.getValue(), current.getValue())) &&
579 (!desc.hasGetter() ||
580 SameValue(desc.getGet(), current.getGet())) &&
581 (!desc.hasSetter() ||
582 SameValue(desc.getSet(), current.getSet()))) {
583 return true;
584 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000585 if (!current.isConfigurable()) {
586 // Step 7
587 if (desc.isConfigurable() ||
588 (desc.hasEnumerable() &&
589 desc.isEnumerable() != current.isEnumerable()))
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000591 // Step 8
592 if (!IsGenericDescriptor(desc)) {
593 // Step 9a
594 if (IsDataDescriptor(current) != IsDataDescriptor(desc))
595 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
596 // Step 10a
597 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
598 if (!current.isWritable() && desc.isWritable())
599 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
600 if (!current.isWritable() && desc.hasValue() &&
601 !SameValue(desc.getValue(), current.getValue())) {
602 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
603 }
604 }
605 // Step 11
606 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
607 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){
608 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
609 }
610 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet()))
611 throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
612 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000613 }
614 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000615 }
616
lrn@chromium.org25156de2010-04-06 13:10:27 +0000617 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000618 // only send to the data descriptor.
619 // Take special care if enumerable and configurable is not defined on
620 // desc (we need to preserve the existing values from current).
621 var flag = NONE;
622 if (desc.hasEnumerable()) {
623 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
624 } else if (!IS_UNDEFINED(current)) {
625 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000626 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000627 flag |= DONT_ENUM;
628 }
629
630 if (desc.hasConfigurable()) {
631 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
632 } else if (!IS_UNDEFINED(current)) {
633 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
634 } else
635 flag |= DONT_DELETE;
636
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000637 if (IsDataDescriptor(desc) ||
638 (IsGenericDescriptor(desc) &&
639 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
640 // There are 3 cases that lead here:
641 // Step 4a - defining a new data property.
642 // Steps 9b & 12 - replacing an existing accessor property with a data
643 // property.
644 // Step 12 - updating an existing data property with a data or generic
645 // descriptor.
646
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000647 if (desc.hasWritable()) {
648 flag |= desc.isWritable() ? 0 : READ_ONLY;
649 } else if (!IS_UNDEFINED(current)) {
650 flag |= current.isWritable() ? 0 : READ_ONLY;
651 } else {
652 flag |= READ_ONLY;
653 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000654
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000655 var value = void 0; // Default value is undefined.
656 if (desc.hasValue()) {
657 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000658 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000659 value = current.getValue();
660 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000661
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000662 %DefineOrRedefineDataProperty(obj, p, value, flag);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000663 } else if (IsGenericDescriptor(desc)) {
664 // Step 12 - updating an existing accessor property with generic
665 // descriptor. Changing flags only.
666 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000667 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000668 // There are 3 cases that lead here:
669 // Step 4b - defining a new accessor property.
670 // Steps 9c & 12 - replacing an existing data property with an accessor
671 // property.
672 // Step 12 - updating an existing accessor property with an accessor
673 // descriptor.
674 if (desc.hasGetter()) {
675 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000676 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000677 if (desc.hasSetter()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000678 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
679 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000680 }
681 return true;
682}
683
684
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000685// ES5 section 15.2.3.2.
686function ObjectGetPrototypeOf(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000687 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000688 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
689 return obj.__proto__;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000690}
691
692
lrn@chromium.org25156de2010-04-06 13:10:27 +0000693// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000694function ObjectGetOwnPropertyDescriptor(obj, p) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000695 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000696 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyDescriptor"]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000697 var desc = GetOwnProperty(obj, p);
698 return FromPropertyDescriptor(desc);
699}
700
701
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000702// ES5 section 15.2.3.4.
703function ObjectGetOwnPropertyNames(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000704 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000705 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
706
707 // Find all the indexed properties.
708
709 // Get the local element names.
710 var propertyNames = %GetLocalElementNames(obj);
711
712 // Get names for indexed interceptor properties.
713 if (%GetInterceptorInfo(obj) & 1) {
714 var indexedInterceptorNames =
715 %GetIndexedInterceptorElementNames(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 if (indexedInterceptorNames)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000717 propertyNames = propertyNames.concat(indexedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000718 }
719
720 // Find all the named properties.
721
722 // Get the local property names.
723 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
724
725 // Get names for named interceptor properties if any.
726
727 if (%GetInterceptorInfo(obj) & 2) {
728 var namedInterceptorNames =
729 %GetNamedInterceptorPropertyNames(obj);
730 if (namedInterceptorNames) {
731 propertyNames = propertyNames.concat(namedInterceptorNames);
732 }
733 }
734
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000735 // Property names are expected to be unique strings.
736 var propertySet = {};
737 var j = 0;
738 for (var i = 0; i < propertyNames.length; ++i) {
739 var name = ToString(propertyNames[i]);
740 // We need to check for the exact property value since for intrinsic
741 // properties like toString if(propertySet["toString"]) will always
742 // succeed.
743 if (propertySet[name] === true)
744 continue;
745 propertySet[name] = true;
746 propertyNames[j++] = name;
747 }
748 propertyNames.length = j;
ager@chromium.org5c838252010-02-19 08:53:10 +0000749
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000750 return propertyNames;
751}
752
753
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000754// ES5 section 15.2.3.5.
755function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000756 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000757 throw MakeTypeError("proto_object_or_null", [proto]);
758 }
759 var obj = new $Object();
760 obj.__proto__ = proto;
761 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
762 return obj;
763}
764
765
ager@chromium.org5c838252010-02-19 08:53:10 +0000766// ES5 section 15.2.3.6.
767function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000768 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000769 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000770 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000771 var name = ToString(p);
772 var desc = ToPropertyDescriptor(attributes);
773 DefineOwnProperty(obj, name, desc, true);
774 return obj;
775}
776
777
778// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000779function ObjectDefineProperties(obj, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000780 if (!IS_SPEC_OBJECT(obj))
ager@chromium.org5c838252010-02-19 08:53:10 +0000781 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000782 var props = ToObject(properties);
783 var key_values = [];
784 for (var key in props) {
785 if (%HasLocalProperty(props, key)) {
786 key_values.push(key);
787 var value = props[key];
788 var desc = ToPropertyDescriptor(value);
789 key_values.push(desc);
790 }
791 }
792 for (var i = 0; i < key_values.length; i += 2) {
793 var key = key_values[i];
794 var desc = key_values[i + 1];
795 DefineOwnProperty(obj, key, desc, true);
796 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000797 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000798}
799
800
ager@chromium.orgb5737492010-07-15 09:29:43 +0000801// ES5 section 15.2.3.8.
802function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000803 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +0000804 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
805 }
806 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000807 for (var i = 0; i < names.length; i++) {
808 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +0000809 var desc = GetOwnProperty(obj, name);
810 if (desc.isConfigurable()) desc.setConfigurable(false);
811 DefineOwnProperty(obj, name, desc, true);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000812 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000813 return ObjectPreventExtension(obj);
ager@chromium.orgb5737492010-07-15 09:29:43 +0000814}
815
816
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000817// ES5 section 15.2.3.9.
818function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000819 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000820 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
821 }
822 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000823 for (var i = 0; i < names.length; i++) {
824 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000825 var desc = GetOwnProperty(obj, name);
826 if (IsDataDescriptor(desc)) desc.setWritable(false);
827 if (desc.isConfigurable()) desc.setConfigurable(false);
828 DefineOwnProperty(obj, name, desc, true);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000829 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000830 return ObjectPreventExtension(obj);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000831}
832
833
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000834// ES5 section 15.2.3.10
835function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000836 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000837 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
838 }
839 %PreventExtensions(obj);
840 return obj;
841}
842
843
ager@chromium.orgb5737492010-07-15 09:29:43 +0000844// ES5 section 15.2.3.11
845function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000846 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +0000847 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
848 }
849 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000850 for (var i = 0; i < names.length; i++) {
851 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +0000852 var desc = GetOwnProperty(obj, name);
853 if (desc.isConfigurable()) return false;
854 }
855 if (!ObjectIsExtensible(obj)) {
856 return true;
857 }
858 return false;
859}
860
861
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000862// ES5 section 15.2.3.12
863function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000864 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000865 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
866 }
867 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000868 for (var i = 0; i < names.length; i++) {
869 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000870 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +0000871 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
872 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000873 }
874 if (!ObjectIsExtensible(obj)) {
875 return true;
876 }
877 return false;
878}
879
880
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000881// ES5 section 15.2.3.13
882function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000883 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000884 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
885 }
886 return %IsExtensible(obj);
887}
888
889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000891 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 if (x == null) return this;
893 return ToObject(x);
894 } else {
895 if (x == null) return { };
896 return ToObject(x);
897 }
898});
899
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000900%SetExpectedNumberOfProperties($Object, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901
902// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903
904
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000905function SetupObject() {
906 // Setup non-enumerable functions on the Object.prototype object.
907 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
908 "toString", ObjectToString,
909 "toLocaleString", ObjectToLocaleString,
910 "valueOf", ObjectValueOf,
911 "hasOwnProperty", ObjectHasOwnProperty,
912 "isPrototypeOf", ObjectIsPrototypeOf,
913 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
914 "__defineGetter__", ObjectDefineGetter,
915 "__lookupGetter__", ObjectLookupGetter,
916 "__defineSetter__", ObjectDefineSetter,
917 "__lookupSetter__", ObjectLookupSetter
918 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000919 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000920 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000921 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +0000922 "defineProperty", ObjectDefineProperty,
923 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000924 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000926 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000927 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
928 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000929 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +0000930 "isSealed", ObjectIsSealed,
931 "preventExtensions", ObjectPreventExtension,
932 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000933 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000934}
935
936SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937
938
939// ----------------------------------------------------------------------------
940// Boolean
941
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000942function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 // NOTE: Both Boolean objects and values can enter here as
944 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000945 var b = this;
946 if (!IS_BOOLEAN(b)) {
947 if (!IS_BOOLEAN_WRAPPER(b)) {
948 throw new $TypeError('Boolean.prototype.toString is not generic');
949 }
950 b = %_ValueOf(b);
951 }
952 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000953}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954
955
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000956function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 // NOTE: Both Boolean objects and values can enter here as
958 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000959 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 throw new $TypeError('Boolean.prototype.valueOf is not generic');
961 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000962}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000963
964
965// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000966
967
968function SetupBoolean() {
969 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
970 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000971 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000972 ));
973}
974
975SetupBoolean();
976
977// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978// Number
979
980// Set the Number function and constructor.
981%SetCode($Number, function(x) {
982 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000983 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 %_SetValueOf(this, value);
985 } else {
986 return value;
987 }
988});
989
990%FunctionSetPrototype($Number, new $Number(0));
991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000993function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 // NOTE: Both Number objects and values can enter here as
995 // 'this'. This is not as dictated by ECMA-262.
996 var number = this;
997 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000998 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 throw new $TypeError('Number.prototype.toString is not generic');
1000 // Get the value of this number in case it's an object.
1001 number = %_ValueOf(this);
1002 }
1003 // Fast case: Convert number in radix 10.
1004 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001005 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 }
1007
1008 // Convert the radix to an integer and check the range.
1009 radix = TO_INTEGER(radix);
1010 if (radix < 2 || radix > 36) {
1011 throw new $RangeError('toString() radix argument must be between 2 and 36');
1012 }
1013 // Convert the number to a string in the given radix.
1014 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001015}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016
1017
1018// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001019function NumberToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001021}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022
1023
1024// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001025function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 // NOTE: Both Number objects and values can enter here as
1027 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001028 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 throw new $TypeError('Number.prototype.valueOf is not generic');
1030 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001031}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032
1033
1034// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001035function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 var f = TO_INTEGER(fractionDigits);
1037 if (f < 0 || f > 20) {
1038 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1039 }
1040 var x = ToNumber(this);
1041 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001042}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043
1044
1045// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001046function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 var f = -1;
1048 if (!IS_UNDEFINED(fractionDigits)) {
1049 f = TO_INTEGER(fractionDigits);
1050 if (f < 0 || f > 20) {
1051 throw new $RangeError("toExponential() argument must be between 0 and 20");
1052 }
1053 }
1054 var x = ToNumber(this);
1055 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001056}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
1058
1059// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001060function NumberToPrecision(precision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1062 var p = TO_INTEGER(precision);
1063 if (p < 1 || p > 21) {
1064 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1065 }
1066 var x = ToNumber(this);
1067 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001068}
1069
1070
1071// ----------------------------------------------------------------------------
1072
1073function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001074 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001075 // Setup the constructor property on the Number prototype object.
1076 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1077
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001078 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001079 // ECMA-262 section 15.7.3.1.
1080 %SetProperty($Number,
1081 "MAX_VALUE",
1082 1.7976931348623157e+308,
1083 DONT_ENUM | DONT_DELETE | READ_ONLY);
1084
1085 // ECMA-262 section 15.7.3.2.
1086 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
1087
1088 // ECMA-262 section 15.7.3.3.
1089 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1090
1091 // ECMA-262 section 15.7.3.4.
1092 %SetProperty($Number,
1093 "NEGATIVE_INFINITY",
1094 -1/0,
1095 DONT_ENUM | DONT_DELETE | READ_ONLY);
1096
1097 // ECMA-262 section 15.7.3.5.
1098 %SetProperty($Number,
1099 "POSITIVE_INFINITY",
1100 1/0,
1101 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001102 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001103
1104 // Setup non-enumerable functions on the Number prototype object.
1105 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1106 "toString", NumberToString,
1107 "toLocaleString", NumberToLocaleString,
1108 "valueOf", NumberValueOf,
1109 "toFixed", NumberToFixed,
1110 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001111 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001112 ));
1113}
1114
1115SetupNumber();
1116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118// ----------------------------------------------------------------------------
1119// Function
1120
1121$Function.prototype.constructor = $Function;
1122
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001124 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127
1128 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001129 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 var name = %FunctionGetName(func);
1131 if (name) {
1132 // Mimic what KJS does.
1133 return 'function ' + name + '() { [native code] }';
1134 } else {
1135 return 'function () { [native code] }';
1136 }
1137 }
1138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 var name = %FunctionGetName(func);
1140 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001141}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142
1143
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001144function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001146}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
1148
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001149// ES5 15.3.4.5
1150function FunctionBind(this_arg) { // Length is 1.
1151 if (!IS_FUNCTION(this)) {
1152 throw new $TypeError('Bind must be called on a function');
1153 }
1154 // this_arg is not an argument that should be bound.
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001155 var argc_bound = (%_ArgumentsLength() || 1) - 1;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001156 var fn = this;
1157 if (argc_bound == 0) {
1158 var result = function() {
1159 if (%_IsConstructCall()) {
1160 // %NewObjectFromBound implicitly uses arguments passed to this
1161 // function. We do not pass the arguments object explicitly to avoid
1162 // materializing it and guarantee that this function will be optimized.
1163 return %NewObjectFromBound(fn, null);
1164 }
1165
1166 return fn.apply(this_arg, arguments);
1167 };
1168 } else {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001169 var bound_args = new $Array(argc_bound);
1170 for(var i = 0; i < argc_bound; i++) {
1171 bound_args[i] = %_Arguments(i+1);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001172 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001173
1174 var result = function() {
1175 // If this is a construct call we use a special runtime method
1176 // to generate the actual object using the bound function.
1177 if (%_IsConstructCall()) {
1178 // %NewObjectFromBound implicitly uses arguments passed to this
1179 // function. We do not pass the arguments object explicitly to avoid
1180 // materializing it and guarantee that this function will be optimized.
1181 return %NewObjectFromBound(fn, bound_args);
1182 }
1183
1184 // Combine the args we got from the bind call with the args
1185 // given as argument to the invocation.
1186 var argc = %_ArgumentsLength();
1187 var args = new $Array(argc + argc_bound);
1188 // Add bound arguments.
1189 for (var i = 0; i < argc_bound; i++) {
1190 args[i] = bound_args[i];
1191 }
1192 // Add arguments from call.
1193 for (var i = 0; i < argc; i++) {
1194 args[argc_bound + i] = %_Arguments(i);
1195 }
1196 return fn.apply(this_arg, args);
1197 };
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001198 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001199
1200 // We already have caller and arguments properties on functions,
1201 // which are non-configurable. It therefore makes no sence to
1202 // try to redefine these as defined by the spec. The spec says
1203 // that bind should make these throw a TypeError if get or set
1204 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001205 // To be consistent with our normal functions we leave this as it is.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001206
1207 // Set the correct length.
1208 var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
1209 %FunctionSetLength(result, length);
1210
1211 return result;
1212}
1213
1214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215function NewFunction(arg1) { // length == 1
1216 var n = %_ArgumentsLength();
1217 var p = '';
1218 if (n > 1) {
1219 p = new $Array(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001220 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1221 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 // If the formal parameters string include ) - an illegal
1223 // character - it may make the combined function expression
1224 // compile. We avoid this problem by checking for this early on.
1225 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1226 }
1227 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001228 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229
1230 // The call to SetNewFunctionAttributes will ensure the prototype
1231 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001232 var f = %CompileString(source)();
ager@chromium.org236ad962008-09-25 09:45:57 +00001233 %FunctionSetName(f, "anonymous");
1234 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001235}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236
1237%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001238
1239// ----------------------------------------------------------------------------
1240
1241function SetupFunction() {
1242 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001243 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001244 "toString", FunctionToString
1245 ));
1246}
1247
1248SetupFunction();