blob: c16d73e82ed05dc75890a8ba4e82c965330ffc92 [file] [log] [blame]
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001// Copyright 2011 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);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000059 %SetNativeFlag(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000060 }
ager@chromium.org5c838252010-02-19 08:53:10 +000061 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000062}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
ager@chromium.org9085a012009-05-11 19:22:57 +000064// Emulates JSC by installing functions on a hidden prototype that
65// lies above the current object/prototype. This lets you override
66// functions on String.prototype etc. and then restore the old function
67// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
68function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
69 var hidden_prototype = new $Object();
70 %SetHiddenPrototype(object, hidden_prototype);
71 InstallFunctions(hidden_prototype, attributes, functions);
72}
73
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000075// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076
77
78// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000079function GlobalIsNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000080 var n = ToNumber(number);
81 return NUMBER_IS_NAN(n);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000082}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083
84
85// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000086function GlobalIsFinite(number) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000087 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
lrn@chromium.org25156de2010-04-06 13:10:27 +000088
89 // NaN - NaN == NaN, Infinity - Infinity == NaN, -Infinity - -Infinity == NaN.
90 return %_IsSmi(number) || number - number == 0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000091}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092
93
94// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000095function GlobalParseInt(string, radix) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000096 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 // Some people use parseInt instead of Math.floor. This
98 // optimization makes parseInt on a Smi 12 times faster (60ns
99 // vs 800ns). The following optimization makes parseInt on a
100 // non-Smi number 9 times faster (230ns vs 2070ns). Together
101 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
102 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000103 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000104 ((0.01 < string && string < 1e9) ||
105 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000106 // Truncate number.
107 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000109 radix = radix | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 } else {
111 radix = TO_INT32(radix);
112 if (!(radix == 0 || (2 <= radix && radix <= 36)))
113 return $NaN;
114 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000115 string = TO_STRING_INLINE(string);
116 if (%_HasCachedArrayIndex(string) &&
117 (radix == 0 || radix == 10)) {
118 return %_GetCachedArrayIndex(string);
119 }
120 return %StringParseInt(string, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000121}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122
123
124// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000125function GlobalParseFloat(string) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000126 string = TO_STRING_INLINE(string);
127 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
128 return %StringParseFloat(string);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000129}
130
131
132function GlobalEval(x) {
133 if (!IS_STRING(x)) return x;
134
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000135 var receiver = this;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000136 var global_receiver = %GlobalReceiver(global);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000137
138 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
139 receiver = global_receiver;
140 }
141
142 var this_is_global_receiver = (receiver === global_receiver);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000143 var global_is_detached = (global === global_receiver);
144
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000145 // For consistency with JSC we require the global object passed to
146 // eval to be the global object from which 'eval' originated. This
147 // is not mandated by the spec.
ager@chromium.orge2902be2009-06-08 12:21:35 +0000148 if (!this_is_global_receiver || global_is_detached) {
149 throw new $EvalError('The "this" object passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000150 'be the global object from which eval originated');
151 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000152
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000153 var f = %CompileString(x);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000154 if (!IS_FUNCTION(f)) return f;
155
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000156 return %_CallFunction(receiver, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000157}
158
159
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000160// ----------------------------------------------------------------------------
161
162
163function SetupGlobal() {
164 // ECMA 262 - 15.1.1.1.
165 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
166
167 // ECMA-262 - 15.1.1.2.
168 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
169
170 // ECMA-262 - 15.1.1.3.
171 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000172
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000173 // Setup non-enumerable function on the global object.
174 InstallFunctions(global, DONT_ENUM, $Array(
175 "isNaN", GlobalIsNaN,
176 "isFinite", GlobalIsFinite,
177 "parseInt", GlobalParseInt,
178 "parseFloat", GlobalParseFloat,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000179 "eval", GlobalEval
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000180 ));
181}
182
183SetupGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184
185
186// ----------------------------------------------------------------------------
187// Boolean (first part of definition)
188
189
190%SetCode($Boolean, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000191 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 %_SetValueOf(this, ToBoolean(x));
193 } else {
194 return ToBoolean(x);
195 }
196});
197
198%FunctionSetPrototype($Boolean, new $Boolean(false));
199
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201
202// ----------------------------------------------------------------------------
203// Object
204
205$Object.prototype.constructor = $Object;
206
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000207// ECMA-262 - 15.2.4.2
208function ObjectToString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000209 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
210 return '[object Undefined]';
211 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000212 if (IS_NULL(this)) return '[object Null]';
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000213 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000214}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215
216
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000217// ECMA-262 - 15.2.4.3
218function ObjectToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000219 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
220 throw MakeTypeError("called_on_null_or_undefined",
221 ["Object.prototype.toLocaleString"]);
222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223 return this.toString();
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.4
228function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000229 return ToObject(this);
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.5
234function ObjectHasOwnProperty(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000235 if (%IsJSProxy(this)) {
236 var handler = %GetHandler(this);
237 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
238 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000239 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000240}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241
242
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000243// ECMA-262 - 15.2.4.6
244function ObjectIsPrototypeOf(V) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000245 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
246 throw MakeTypeError("called_on_null_or_undefined",
247 ["Object.prototype.isPrototypeOf"]);
248 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000249 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000251}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252
253
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000254// ECMA-262 - 15.2.4.6
255function ObjectPropertyIsEnumerable(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000256 var P = ToString(V);
257 if (%IsJSProxy(this)) {
258 var desc = GetOwnProperty(this, P);
259 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
260 }
261 return %IsPropertyEnumerable(ToObject(this), P);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000262}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000263
264
265// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000266function ObjectDefineGetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000267 var receiver = this;
268 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
269 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000270 }
271 if (!IS_FUNCTION(fun)) {
272 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
273 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000274 var desc = new PropertyDescriptor();
275 desc.setGet(fun);
276 desc.setEnumerable(true);
277 desc.setConfigurable(true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000278 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000279}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280
281
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000282function ObjectLookupGetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000283 var receiver = this;
284 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
285 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000286 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000287 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000288}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289
290
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000291function ObjectDefineSetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000292 var receiver = this;
293 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
294 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000295 }
296 if (!IS_FUNCTION(fun)) {
297 throw new $TypeError(
298 'Object.prototype.__defineSetter__: Expecting function');
299 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000300 var desc = new PropertyDescriptor();
301 desc.setSet(fun);
302 desc.setEnumerable(true);
303 desc.setConfigurable(true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000304 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306
307
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000308function ObjectLookupSetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000309 var receiver = this;
310 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
311 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000313 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000314}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315
316
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000317function ObjectKeys(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000318 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000319 throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000320 if (%IsJSProxy(obj)) {
321 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000322 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000323 return ToStringArray(names);
324 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000325 return %LocalKeys(obj);
326}
327
328
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000329// ES5 8.10.1.
330function IsAccessorDescriptor(desc) {
331 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000332 return desc.hasGetter() || desc.hasSetter();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000333}
334
335
336// ES5 8.10.2.
337function IsDataDescriptor(desc) {
338 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000339 return desc.hasValue() || desc.hasWritable();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000340}
341
342
343// ES5 8.10.3.
344function IsGenericDescriptor(desc) {
345 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
346}
347
348
349function IsInconsistentDescriptor(desc) {
350 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
351}
352
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000353
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000354// ES5 8.10.4
355function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000356 if (IS_UNDEFINED(desc)) return desc;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000357 var obj = new $Object();
358 if (IsDataDescriptor(desc)) {
359 obj.value = desc.getValue();
360 obj.writable = desc.isWritable();
361 }
362 if (IsAccessorDescriptor(desc)) {
363 obj.get = desc.getGet();
364 obj.set = desc.getSet();
365 }
366 obj.enumerable = desc.isEnumerable();
367 obj.configurable = desc.isConfigurable();
368 return obj;
369}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000370
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000371// Harmony Proxies
372function FromGenericPropertyDescriptor(desc) {
373 if (IS_UNDEFINED(desc)) return desc;
374 var obj = new $Object();
375 if (desc.hasValue()) obj.value = desc.getValue();
376 if (desc.hasWritable()) obj.writable = desc.isWritable();
377 if (desc.hasGetter()) obj.get = desc.getGet();
378 if (desc.hasSetter()) obj.set = desc.getSet();
379 if (desc.hasEnumerable()) obj.enumerable = desc.isEnumerable();
380 if (desc.hasConfigurable()) obj.configurable = desc.isConfigurable();
381 return obj;
382}
383
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000384// ES5 8.10.5.
385function ToPropertyDescriptor(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000386 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000387 throw MakeTypeError("property_desc_object", [obj]);
388 }
389 var desc = new PropertyDescriptor();
390
391 if ("enumerable" in obj) {
392 desc.setEnumerable(ToBoolean(obj.enumerable));
393 }
394
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000395 if ("configurable" in obj) {
396 desc.setConfigurable(ToBoolean(obj.configurable));
397 }
398
399 if ("value" in obj) {
400 desc.setValue(obj.value);
401 }
402
403 if ("writable" in obj) {
404 desc.setWritable(ToBoolean(obj.writable));
405 }
406
407 if ("get" in obj) {
408 var get = obj.get;
409 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) {
410 throw MakeTypeError("getter_must_be_callable", [get]);
411 }
412 desc.setGet(get);
413 }
414
415 if ("set" in obj) {
416 var set = obj.set;
417 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) {
418 throw MakeTypeError("setter_must_be_callable", [set]);
419 }
420 desc.setSet(set);
421 }
422
423 if (IsInconsistentDescriptor(desc)) {
424 throw MakeTypeError("value_and_accessor", [obj]);
425 }
426 return desc;
427}
428
429
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000430// For Harmony proxies.
431function ToCompletePropertyDescriptor(obj) {
432 var desc = ToPropertyDescriptor(obj)
433 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000434 if (!desc.hasValue()) desc.setValue(void 0);
435 if (!desc.hasWritable()) desc.setWritable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000436 } else {
437 // Is accessor descriptor.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000438 if (!desc.hasGetter()) desc.setGet(void 0);
439 if (!desc.hasSetter()) desc.setSet(void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000440 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000441 if (!desc.hasEnumerable()) desc.setEnumerable(false);
442 if (!desc.hasConfigurable()) desc.setConfigurable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000443 return desc;
444}
445
446
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000447function PropertyDescriptor() {
448 // Initialize here so they are all in-object and have the same map.
449 // Default values from ES5 8.6.1.
450 this.value_ = void 0;
451 this.hasValue_ = false;
452 this.writable_ = false;
453 this.hasWritable_ = false;
454 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000455 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000456 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000457 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000458 this.get_ = void 0;
459 this.hasGetter_ = false;
460 this.set_ = void 0;
461 this.hasSetter_ = false;
462}
463
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000464PropertyDescriptor.prototype.__proto__ = null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000465
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000466PropertyDescriptor.prototype.toString = function() {
467 return "[object PropertyDescriptor]";
468};
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000469
470PropertyDescriptor.prototype.setValue = function(value) {
471 this.value_ = value;
472 this.hasValue_ = true;
473}
474
475
476PropertyDescriptor.prototype.getValue = function() {
477 return this.value_;
478}
479
480
ager@chromium.org5c838252010-02-19 08:53:10 +0000481PropertyDescriptor.prototype.hasValue = function() {
482 return this.hasValue_;
483}
484
485
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000486PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
487 this.enumerable_ = enumerable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000488 this.hasEnumerable_ = true;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000489}
490
491
492PropertyDescriptor.prototype.isEnumerable = function () {
493 return this.enumerable_;
494}
495
496
ager@chromium.org5c838252010-02-19 08:53:10 +0000497PropertyDescriptor.prototype.hasEnumerable = function() {
498 return this.hasEnumerable_;
499}
500
501
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502PropertyDescriptor.prototype.setWritable = function(writable) {
503 this.writable_ = writable;
504 this.hasWritable_ = true;
505}
506
507
508PropertyDescriptor.prototype.isWritable = function() {
509 return this.writable_;
510}
511
512
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000513PropertyDescriptor.prototype.hasWritable = function() {
514 return this.hasWritable_;
515}
516
517
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000518PropertyDescriptor.prototype.setConfigurable = function(configurable) {
519 this.configurable_ = configurable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000520 this.hasConfigurable_ = true;
521}
522
523
524PropertyDescriptor.prototype.hasConfigurable = function() {
525 return this.hasConfigurable_;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526}
527
528
529PropertyDescriptor.prototype.isConfigurable = function() {
530 return this.configurable_;
531}
532
533
534PropertyDescriptor.prototype.setGet = function(get) {
535 this.get_ = get;
536 this.hasGetter_ = true;
537}
538
539
540PropertyDescriptor.prototype.getGet = function() {
541 return this.get_;
542}
543
544
ager@chromium.org5c838252010-02-19 08:53:10 +0000545PropertyDescriptor.prototype.hasGetter = function() {
546 return this.hasGetter_;
547}
548
549
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550PropertyDescriptor.prototype.setSet = function(set) {
551 this.set_ = set;
552 this.hasSetter_ = true;
553}
554
555
556PropertyDescriptor.prototype.getSet = function() {
557 return this.set_;
558}
559
560
ager@chromium.org5c838252010-02-19 08:53:10 +0000561PropertyDescriptor.prototype.hasSetter = function() {
562 return this.hasSetter_;
563}
564
565
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000566// Converts an array returned from Runtime_GetOwnProperty to an actual
567// property descriptor. For a description of the array layout please
568// see the runtime.cc file.
569function ConvertDescriptorArrayToDescriptor(desc_array) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000570 if (desc_array === false) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000571 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000572 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000573
574 if (IS_UNDEFINED(desc_array)) {
575 return void 0;
576 }
577
578 var desc = new PropertyDescriptor();
579 // This is an accessor.
580 if (desc_array[IS_ACCESSOR_INDEX]) {
581 desc.setGet(desc_array[GETTER_INDEX]);
582 desc.setSet(desc_array[SETTER_INDEX]);
583 } else {
584 desc.setValue(desc_array[VALUE_INDEX]);
585 desc.setWritable(desc_array[WRITABLE_INDEX]);
586 }
587 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
588 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000589
590 return desc;
591}
592
593
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000594// For Harmony proxies.
595function GetTrap(handler, name, defaultTrap) {
596 var trap = handler[name];
597 if (IS_UNDEFINED(trap)) {
598 if (IS_UNDEFINED(defaultTrap)) {
599 throw MakeTypeError("handler_trap_missing", [handler, name]);
600 }
601 trap = defaultTrap;
602 } else if (!IS_FUNCTION(trap)) {
603 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
604 }
605 return trap;
606}
607
608
609function CallTrap0(handler, name, defaultTrap) {
610 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
611}
612
613
614function CallTrap1(handler, name, defaultTrap, x) {
615 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
616}
617
618
619function CallTrap2(handler, name, defaultTrap, x, y) {
620 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
621}
622
623
ager@chromium.org5c838252010-02-19 08:53:10 +0000624// ES5 section 8.12.2.
625function GetProperty(obj, p) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000626 if (%IsJSProxy(obj)) {
627 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000628 var descriptor = CallTrap1(obj, "getPropertyDescriptor", void 0, p);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000629 if (IS_UNDEFINED(descriptor)) return descriptor;
630 var desc = ToCompletePropertyDescriptor(descriptor);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000631 if (!desc.isConfigurable()) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000632 throw MakeTypeError("proxy_prop_not_configurable",
633 [handler, "getPropertyDescriptor", p, descriptor]);
634 }
635 return desc;
636 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000637 var prop = GetOwnProperty(obj);
638 if (!IS_UNDEFINED(prop)) return prop;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000639 var proto = %GetPrototype(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000640 if (IS_NULL(proto)) return void 0;
641 return GetProperty(proto, p);
642}
643
644
645// ES5 section 8.12.6
646function HasProperty(obj, p) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647 if (%IsJSProxy(obj)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000648 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000649 return ToBoolean(CallTrap1(handler, "has", DerivedHasTrap, p));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000650 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000651 var desc = GetProperty(obj, p);
652 return IS_UNDEFINED(desc) ? false : true;
653}
654
655
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000656// ES5 section 8.12.1.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000657function GetOwnProperty(obj, v) {
658 var p = ToString(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000659 if (%IsJSProxy(obj)) {
660 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000661 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000662 if (IS_UNDEFINED(descriptor)) return descriptor;
663 var desc = ToCompletePropertyDescriptor(descriptor);
664 if (!desc.isConfigurable()) {
665 throw MakeTypeError("proxy_prop_not_configurable",
666 [handler, "getOwnPropertyDescriptor", p, descriptor]);
667 }
668 return desc;
669 }
670
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000671 // GetOwnProperty returns an array indexed by the constants
672 // defined in macros.py.
673 // If p is not a property on obj undefined is returned.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000674 var props = %GetOwnProperty(ToObject(obj), ToString(v));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000675
676 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000677 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000678
679 return ConvertDescriptorArrayToDescriptor(props);
680}
681
682
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000683// Harmony proxies.
684function DefineProxyProperty(obj, p, attributes, should_throw) {
685 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000686 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000687 if (!ToBoolean(result)) {
688 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000689 throw MakeTypeError("handler_returned_false",
690 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 } else {
692 return false;
693 }
694 }
695 return true;
696}
697
698
lrn@chromium.org25156de2010-04-06 13:10:27 +0000699// ES5 8.12.9.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000700function DefineOwnProperty(obj, p, desc, should_throw) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000701 if (%IsJSProxy(obj)) {
702 var attributes = FromGenericPropertyDescriptor(desc);
703 return DefineProxyProperty(obj, p, attributes, should_throw);
704 }
705
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000706 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
707 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000708 if (current_or_access === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000709
710 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000711 var extensible = %IsExtensible(ToObject(obj));
712
713 // Error handling according to spec.
714 // Step 3
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000715 if (IS_UNDEFINED(current) && !extensible) {
716 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000717 throw MakeTypeError("define_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000718 } else {
719 return;
720 }
721 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000722
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000723 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000724 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000725 if ((IsGenericDescriptor(desc) ||
726 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
727 (!desc.hasEnumerable() ||
728 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000729 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000730 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000731 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000732 SameValue(desc.isWritable(), current.isWritable())) &&
733 (!desc.hasValue() ||
734 SameValue(desc.getValue(), current.getValue())) &&
735 (!desc.hasGetter() ||
736 SameValue(desc.getGet(), current.getGet())) &&
737 (!desc.hasSetter() ||
738 SameValue(desc.getSet(), current.getSet()))) {
739 return true;
740 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000741 if (!current.isConfigurable()) {
742 // Step 7
743 if (desc.isConfigurable() ||
744 (desc.hasEnumerable() &&
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000745 desc.isEnumerable() != current.isEnumerable())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000746 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000747 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000748 } else {
749 return;
750 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000751 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Step 8
753 if (!IsGenericDescriptor(desc)) {
754 // Step 9a
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000755 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000756 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000757 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000758 } else {
759 return;
760 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000761 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000762 // Step 10a
763 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000764 if (!current.isWritable() && desc.isWritable()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000765 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000766 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000767 } else {
768 return;
769 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000770 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000771 if (!current.isWritable() && desc.hasValue() &&
772 !SameValue(desc.getValue(), current.getValue())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000773 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000774 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000775 } else {
776 return;
777 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000778 }
779 }
780 // Step 11
781 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000782 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000783 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000784 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000785 } else {
786 return;
787 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000789 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000790 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000791 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000792 } else {
793 return;
794 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000795 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000796 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000797 }
798 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000799 }
800
lrn@chromium.org25156de2010-04-06 13:10:27 +0000801 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 // only send to the data descriptor.
803 // Take special care if enumerable and configurable is not defined on
804 // desc (we need to preserve the existing values from current).
805 var flag = NONE;
806 if (desc.hasEnumerable()) {
807 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
808 } else if (!IS_UNDEFINED(current)) {
809 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000810 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000811 flag |= DONT_ENUM;
812 }
813
814 if (desc.hasConfigurable()) {
815 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
816 } else if (!IS_UNDEFINED(current)) {
817 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
818 } else
819 flag |= DONT_DELETE;
820
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000821 if (IsDataDescriptor(desc) ||
822 (IsGenericDescriptor(desc) &&
823 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
824 // There are 3 cases that lead here:
825 // Step 4a - defining a new data property.
826 // Steps 9b & 12 - replacing an existing accessor property with a data
827 // property.
828 // Step 12 - updating an existing data property with a data or generic
829 // descriptor.
830
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000831 if (desc.hasWritable()) {
832 flag |= desc.isWritable() ? 0 : READ_ONLY;
833 } else if (!IS_UNDEFINED(current)) {
834 flag |= current.isWritable() ? 0 : READ_ONLY;
835 } else {
836 flag |= READ_ONLY;
837 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000838
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000839 var value = void 0; // Default value is undefined.
840 if (desc.hasValue()) {
841 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000842 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000843 value = current.getValue();
844 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000846 %DefineOrRedefineDataProperty(obj, p, value, flag);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 } else if (IsGenericDescriptor(desc)) {
848 // Step 12 - updating an existing accessor property with generic
849 // descriptor. Changing flags only.
850 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000851 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000852 // There are 3 cases that lead here:
853 // Step 4b - defining a new accessor property.
854 // Steps 9c & 12 - replacing an existing data property with an accessor
855 // property.
856 // Step 12 - updating an existing accessor property with an accessor
857 // descriptor.
858 if (desc.hasGetter()) {
859 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000860 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000861 if (desc.hasSetter()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000862 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
863 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000864 }
865 return true;
866}
867
868
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000869// ES5 section 15.2.3.2.
870function ObjectGetPrototypeOf(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000871 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000872 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000873 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000874}
875
876
lrn@chromium.org25156de2010-04-06 13:10:27 +0000877// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000878function ObjectGetOwnPropertyDescriptor(obj, p) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000879 if (!IS_SPEC_OBJECT(obj))
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000880 throw MakeTypeError("obj_ctor_property_non_object",
881 ["getOwnPropertyDescriptor"]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000882 var desc = GetOwnProperty(obj, p);
883 return FromPropertyDescriptor(desc);
884}
885
886
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000887// For Harmony proxies
888function ToStringArray(obj, trap) {
889 if (!IS_SPEC_OBJECT(obj)) {
890 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
891 }
892 var n = ToUint32(obj.length);
893 var array = new $Array(n);
894 var names = {}
895 for (var index = 0; index < n; index++) {
896 var s = ToString(obj[index]);
897 if (s in names) {
898 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
899 }
900 array[index] = s;
901 names.s = 0;
902 }
903 return array;
904}
905
906
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000907// ES5 section 15.2.3.4.
908function ObjectGetOwnPropertyNames(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000909 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000910 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
911
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000912 // Special handling for proxies.
913 if (%IsJSProxy(obj)) {
914 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000915 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000916 return ToStringArray(names, "getOwnPropertyNames");
917 }
918
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000919 // Find all the indexed properties.
920
921 // Get the local element names.
922 var propertyNames = %GetLocalElementNames(obj);
923
924 // Get names for indexed interceptor properties.
925 if (%GetInterceptorInfo(obj) & 1) {
926 var indexedInterceptorNames =
927 %GetIndexedInterceptorElementNames(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000928 if (indexedInterceptorNames)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000929 propertyNames = propertyNames.concat(indexedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000930 }
931
932 // Find all the named properties.
933
934 // Get the local property names.
935 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
936
937 // Get names for named interceptor properties if any.
938
939 if (%GetInterceptorInfo(obj) & 2) {
940 var namedInterceptorNames =
941 %GetNamedInterceptorPropertyNames(obj);
942 if (namedInterceptorNames) {
943 propertyNames = propertyNames.concat(namedInterceptorNames);
944 }
945 }
946
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000947 // Property names are expected to be unique strings.
948 var propertySet = {};
949 var j = 0;
950 for (var i = 0; i < propertyNames.length; ++i) {
951 var name = ToString(propertyNames[i]);
952 // We need to check for the exact property value since for intrinsic
953 // properties like toString if(propertySet["toString"]) will always
954 // succeed.
955 if (propertySet[name] === true)
956 continue;
957 propertySet[name] = true;
958 propertyNames[j++] = name;
959 }
960 propertyNames.length = j;
ager@chromium.org5c838252010-02-19 08:53:10 +0000961
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000962 return propertyNames;
963}
964
965
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000966// ES5 section 15.2.3.5.
967function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000968 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000969 throw MakeTypeError("proto_object_or_null", [proto]);
970 }
971 var obj = new $Object();
972 obj.__proto__ = proto;
973 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
974 return obj;
975}
976
977
ager@chromium.org5c838252010-02-19 08:53:10 +0000978// ES5 section 15.2.3.6.
979function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000980 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000981 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000982 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000983 var name = ToString(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000984 if (%IsJSProxy(obj)) {
985 // Clone the attributes object for protection.
986 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
987 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
988 var attributesClone = {}
989 for (var a in attributes) {
990 attributesClone[a] = attributes[a];
991 }
992 DefineProxyProperty(obj, name, attributesClone, true);
993 // The following would implement the spec as in the current proposal,
994 // but after recent comments on es-discuss, is most likely obsolete.
995 /*
996 var defineObj = FromGenericPropertyDescriptor(desc);
997 var names = ObjectGetOwnPropertyNames(attributes);
998 var standardNames =
999 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1000 for (var i = 0; i < names.length; i++) {
1001 var N = names[i];
1002 if (!(%HasLocalProperty(standardNames, N))) {
1003 var attr = GetOwnProperty(attributes, N);
1004 DefineOwnProperty(descObj, N, attr, true);
1005 }
1006 }
1007 // This is really confusing the types, but it is what the proxies spec
1008 // currently requires:
1009 desc = descObj;
1010 */
1011 } else {
1012 var desc = ToPropertyDescriptor(attributes);
1013 DefineOwnProperty(obj, name, desc, true);
1014 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001015 return obj;
1016}
1017
1018
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001019function GetOwnEnumerablePropertyNames(properties) {
1020 var names = new InternalArray();
1021 for (var key in properties) {
1022 if (%HasLocalProperty(properties, key)) {
1023 names.push(key);
1024 }
1025 }
1026 return names;
1027}
1028
1029
ager@chromium.org5c838252010-02-19 08:53:10 +00001030// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001031function ObjectDefineProperties(obj, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001032 if (!IS_SPEC_OBJECT(obj))
ager@chromium.org5c838252010-02-19 08:53:10 +00001033 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001034 var props = ToObject(properties);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001035 var names = GetOwnEnumerablePropertyNames(props);
1036 for (var i = 0; i < names.length; i++) {
1037 var name = names[i];
1038 var desc = ToPropertyDescriptor(props[name]);
1039 DefineOwnProperty(obj, name, desc, true);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001040 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001041 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001042}
1043
1044
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001045// Harmony proxies.
1046function ProxyFix(obj) {
1047 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001048 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001049 if (IS_UNDEFINED(props)) {
1050 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1051 }
1052 %Fix(obj);
1053 ObjectDefineProperties(obj, props);
1054}
1055
1056
ager@chromium.orgb5737492010-07-15 09:29:43 +00001057// ES5 section 15.2.3.8.
1058function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001059 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00001060 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
1061 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001062 if (%IsJSProxy(obj)) {
1063 ProxyFix(obj);
1064 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001065 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001066 for (var i = 0; i < names.length; i++) {
1067 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001068 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001069 if (desc.isConfigurable()) {
1070 desc.setConfigurable(false);
1071 DefineOwnProperty(obj, name, desc, true);
1072 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001073 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001074 %PreventExtensions(obj);
1075 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001076}
1077
1078
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001079// ES5 section 15.2.3.9.
1080function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001081 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001082 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
1083 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001084 if (%IsJSProxy(obj)) {
1085 ProxyFix(obj);
1086 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001087 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001088 for (var i = 0; i < names.length; i++) {
1089 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001090 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001091 if (desc.isWritable() || desc.isConfigurable()) {
1092 if (IsDataDescriptor(desc)) desc.setWritable(false);
1093 desc.setConfigurable(false);
1094 DefineOwnProperty(obj, name, desc, true);
1095 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001096 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001097 %PreventExtensions(obj);
1098 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001099}
1100
1101
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001102// ES5 section 15.2.3.10
1103function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001104 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001105 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
1106 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001107 if (%IsJSProxy(obj)) {
1108 ProxyFix(obj);
1109 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001110 %PreventExtensions(obj);
1111 return obj;
1112}
1113
1114
ager@chromium.orgb5737492010-07-15 09:29:43 +00001115// ES5 section 15.2.3.11
1116function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001117 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00001118 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
1119 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001120 if (%IsJSProxy(obj)) {
1121 return false;
1122 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001123 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001124 for (var i = 0; i < names.length; i++) {
1125 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001126 var desc = GetOwnProperty(obj, name);
1127 if (desc.isConfigurable()) return false;
1128 }
1129 if (!ObjectIsExtensible(obj)) {
1130 return true;
1131 }
1132 return false;
1133}
1134
1135
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001136// ES5 section 15.2.3.12
1137function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001138 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001139 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
1140 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001141 if (%IsJSProxy(obj)) {
1142 return false;
1143 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001144 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001145 for (var i = 0; i < names.length; i++) {
1146 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001147 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001148 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1149 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001150 }
1151 if (!ObjectIsExtensible(obj)) {
1152 return true;
1153 }
1154 return false;
1155}
1156
1157
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001158// ES5 section 15.2.3.13
1159function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001160 if (!IS_SPEC_OBJECT(obj)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001161 throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001162 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001163 if (%IsJSProxy(obj)) {
1164 return true;
1165 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001166 return %IsExtensible(obj);
1167}
1168
1169
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001171 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 if (x == null) return this;
1173 return ToObject(x);
1174 } else {
1175 if (x == null) return { };
1176 return ToObject(x);
1177 }
1178});
1179
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001180%SetExpectedNumberOfProperties($Object, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001181
1182// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183
1184
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001185function SetupObject() {
1186 // Setup non-enumerable functions on the Object.prototype object.
1187 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1188 "toString", ObjectToString,
1189 "toLocaleString", ObjectToLocaleString,
1190 "valueOf", ObjectValueOf,
1191 "hasOwnProperty", ObjectHasOwnProperty,
1192 "isPrototypeOf", ObjectIsPrototypeOf,
1193 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1194 "__defineGetter__", ObjectDefineGetter,
1195 "__lookupGetter__", ObjectLookupGetter,
1196 "__defineSetter__", ObjectDefineSetter,
1197 "__lookupSetter__", ObjectLookupSetter
1198 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001199 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001200 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001201 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001202 "defineProperty", ObjectDefineProperty,
1203 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001204 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001205 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001206 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001207 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1208 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001209 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001210 "isSealed", ObjectIsSealed,
1211 "preventExtensions", ObjectPreventExtension,
1212 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001213 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001214}
1215
1216SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217
1218
1219// ----------------------------------------------------------------------------
1220// Boolean
1221
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001222function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // NOTE: Both Boolean objects and values can enter here as
1224 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001225 var b = this;
1226 if (!IS_BOOLEAN(b)) {
1227 if (!IS_BOOLEAN_WRAPPER(b)) {
1228 throw new $TypeError('Boolean.prototype.toString is not generic');
1229 }
1230 b = %_ValueOf(b);
1231 }
1232 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234
1235
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001236function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 // NOTE: Both Boolean objects and values can enter here as
1238 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001239 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1241 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001242}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243
1244
1245// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001246
1247
1248function SetupBoolean() {
1249 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1250 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001251 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001252 ));
1253}
1254
1255SetupBoolean();
1256
1257// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258// Number
1259
1260// Set the Number function and constructor.
1261%SetCode($Number, function(x) {
1262 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001263 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 %_SetValueOf(this, value);
1265 } else {
1266 return value;
1267 }
1268});
1269
1270%FunctionSetPrototype($Number, new $Number(0));
1271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001273function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // NOTE: Both Number objects and values can enter here as
1275 // 'this'. This is not as dictated by ECMA-262.
1276 var number = this;
1277 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001278 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 throw new $TypeError('Number.prototype.toString is not generic');
1280 // Get the value of this number in case it's an object.
1281 number = %_ValueOf(this);
1282 }
1283 // Fast case: Convert number in radix 10.
1284 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001285 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 }
1287
1288 // Convert the radix to an integer and check the range.
1289 radix = TO_INTEGER(radix);
1290 if (radix < 2 || radix > 36) {
1291 throw new $RangeError('toString() radix argument must be between 2 and 36');
1292 }
1293 // Convert the number to a string in the given radix.
1294 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001295}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296
1297
1298// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001299function NumberToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001300 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1301 throw MakeTypeError("called_on_null_or_undefined",
1302 ["Number.prototype.toLocaleString"]);
1303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001305}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306
1307
1308// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001309function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 // NOTE: Both Number objects and values can enter here as
1311 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001312 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 throw new $TypeError('Number.prototype.valueOf is not generic');
1314 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001315}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316
1317
1318// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001319function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 var f = TO_INTEGER(fractionDigits);
1321 if (f < 0 || f > 20) {
1322 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1323 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00001324 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1325 throw MakeTypeError("called_on_null_or_undefined",
1326 ["Number.prototype.toFixed"]);
1327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 var x = ToNumber(this);
1329 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001330}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332
1333// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001334function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 var f = -1;
1336 if (!IS_UNDEFINED(fractionDigits)) {
1337 f = TO_INTEGER(fractionDigits);
1338 if (f < 0 || f > 20) {
1339 throw new $RangeError("toExponential() argument must be between 0 and 20");
1340 }
1341 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00001342 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1343 throw MakeTypeError("called_on_null_or_undefined",
1344 ["Number.prototype.toExponential"]);
1345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 var x = ToNumber(this);
1347 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001348}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349
1350
1351// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001352function NumberToPrecision(precision) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001353 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1354 throw MakeTypeError("called_on_null_or_undefined",
1355 ["Number.prototype.toPrecision"]);
1356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1358 var p = TO_INTEGER(precision);
1359 if (p < 1 || p > 21) {
1360 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1361 }
1362 var x = ToNumber(this);
1363 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001364}
1365
1366
1367// ----------------------------------------------------------------------------
1368
1369function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001370 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001371 // Setup the constructor property on the Number prototype object.
1372 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1373
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001374 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001375 // ECMA-262 section 15.7.3.1.
1376 %SetProperty($Number,
1377 "MAX_VALUE",
1378 1.7976931348623157e+308,
1379 DONT_ENUM | DONT_DELETE | READ_ONLY);
1380
1381 // ECMA-262 section 15.7.3.2.
1382 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
1383
1384 // ECMA-262 section 15.7.3.3.
1385 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1386
1387 // ECMA-262 section 15.7.3.4.
1388 %SetProperty($Number,
1389 "NEGATIVE_INFINITY",
1390 -1/0,
1391 DONT_ENUM | DONT_DELETE | READ_ONLY);
1392
1393 // ECMA-262 section 15.7.3.5.
1394 %SetProperty($Number,
1395 "POSITIVE_INFINITY",
1396 1/0,
1397 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001398 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001399
1400 // Setup non-enumerable functions on the Number prototype object.
1401 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1402 "toString", NumberToString,
1403 "toLocaleString", NumberToLocaleString,
1404 "valueOf", NumberValueOf,
1405 "toFixed", NumberToFixed,
1406 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001407 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001408 ));
1409}
1410
1411SetupNumber();
1412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414// ----------------------------------------------------------------------------
1415// Function
1416
1417$Function.prototype.constructor = $Function;
1418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001420 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423
1424 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001425 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 var name = %FunctionGetName(func);
1427 if (name) {
1428 // Mimic what KJS does.
1429 return 'function ' + name + '() { [native code] }';
1430 } else {
1431 return 'function () { [native code] }';
1432 }
1433 }
1434
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001435 var name = %FunctionNameShouldPrintAsAnonymous(func)
1436 ? 'anonymous'
1437 : %FunctionGetName(func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001439}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
1441
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001442function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001444}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445
1446
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001447// ES5 15.3.4.5
1448function FunctionBind(this_arg) { // Length is 1.
1449 if (!IS_FUNCTION(this)) {
1450 throw new $TypeError('Bind must be called on a function');
1451 }
1452 // this_arg is not an argument that should be bound.
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001453 var argc_bound = (%_ArgumentsLength() || 1) - 1;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001454 var fn = this;
1455 if (argc_bound == 0) {
1456 var result = function() {
1457 if (%_IsConstructCall()) {
1458 // %NewObjectFromBound implicitly uses arguments passed to this
1459 // function. We do not pass the arguments object explicitly to avoid
1460 // materializing it and guarantee that this function will be optimized.
1461 return %NewObjectFromBound(fn, null);
1462 }
1463
1464 return fn.apply(this_arg, arguments);
1465 };
1466 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001467 var bound_args = new InternalArray(argc_bound);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001468 for(var i = 0; i < argc_bound; i++) {
1469 bound_args[i] = %_Arguments(i+1);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001470 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001471
1472 var result = function() {
1473 // If this is a construct call we use a special runtime method
1474 // to generate the actual object using the bound function.
1475 if (%_IsConstructCall()) {
1476 // %NewObjectFromBound implicitly uses arguments passed to this
1477 // function. We do not pass the arguments object explicitly to avoid
1478 // materializing it and guarantee that this function will be optimized.
1479 return %NewObjectFromBound(fn, bound_args);
1480 }
1481
1482 // Combine the args we got from the bind call with the args
1483 // given as argument to the invocation.
1484 var argc = %_ArgumentsLength();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001485 var args = new InternalArray(argc + argc_bound);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001486 // Add bound arguments.
1487 for (var i = 0; i < argc_bound; i++) {
1488 args[i] = bound_args[i];
1489 }
1490 // Add arguments from call.
1491 for (var i = 0; i < argc; i++) {
1492 args[argc_bound + i] = %_Arguments(i);
1493 }
1494 return fn.apply(this_arg, args);
1495 };
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001496 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001497
1498 // We already have caller and arguments properties on functions,
1499 // which are non-configurable. It therefore makes no sence to
1500 // try to redefine these as defined by the spec. The spec says
1501 // that bind should make these throw a TypeError if get or set
1502 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001503 // To be consistent with our normal functions we leave this as it is.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001504
1505 // Set the correct length.
1506 var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001507 %FunctionRemovePrototype(result);
1508 %FunctionSetBound(result);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001509 %BoundFunctionSetLength(result, length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001510 return result;
1511}
1512
1513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514function NewFunction(arg1) { // length == 1
1515 var n = %_ArgumentsLength();
1516 var p = '';
1517 if (n > 1) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001518 p = new InternalArray(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001519 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1520 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 // If the formal parameters string include ) - an illegal
1522 // character - it may make the combined function expression
1523 // compile. We avoid this problem by checking for this early on.
1524 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1525 }
1526 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001527 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528
1529 // The call to SetNewFunctionAttributes will ensure the prototype
1530 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001531 var f = %CompileString(source)();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001532 %FunctionMarkNameShouldPrintAsAnonymous(f);
ager@chromium.org236ad962008-09-25 09:45:57 +00001533 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001534}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535
1536%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001537
1538// ----------------------------------------------------------------------------
1539
1540function SetupFunction() {
1541 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001542 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001543 "toString", FunctionToString
1544 ));
1545}
1546
1547SetupFunction();