blob: 88525f6b44f01de4e114175bb6253d0685deec44 [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;
465PropertyDescriptor.prototype.toString = function() {
466 return "[object PropertyDescriptor]";
467};
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000468
469PropertyDescriptor.prototype.setValue = function(value) {
470 this.value_ = value;
471 this.hasValue_ = true;
472}
473
474
475PropertyDescriptor.prototype.getValue = function() {
476 return this.value_;
477}
478
479
ager@chromium.org5c838252010-02-19 08:53:10 +0000480PropertyDescriptor.prototype.hasValue = function() {
481 return this.hasValue_;
482}
483
484
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
486 this.enumerable_ = enumerable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000487 this.hasEnumerable_ = true;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488}
489
490
491PropertyDescriptor.prototype.isEnumerable = function () {
492 return this.enumerable_;
493}
494
495
ager@chromium.org5c838252010-02-19 08:53:10 +0000496PropertyDescriptor.prototype.hasEnumerable = function() {
497 return this.hasEnumerable_;
498}
499
500
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501PropertyDescriptor.prototype.setWritable = function(writable) {
502 this.writable_ = writable;
503 this.hasWritable_ = true;
504}
505
506
507PropertyDescriptor.prototype.isWritable = function() {
508 return this.writable_;
509}
510
511
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000512PropertyDescriptor.prototype.hasWritable = function() {
513 return this.hasWritable_;
514}
515
516
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517PropertyDescriptor.prototype.setConfigurable = function(configurable) {
518 this.configurable_ = configurable;
ager@chromium.org5c838252010-02-19 08:53:10 +0000519 this.hasConfigurable_ = true;
520}
521
522
523PropertyDescriptor.prototype.hasConfigurable = function() {
524 return this.hasConfigurable_;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525}
526
527
528PropertyDescriptor.prototype.isConfigurable = function() {
529 return this.configurable_;
530}
531
532
533PropertyDescriptor.prototype.setGet = function(get) {
534 this.get_ = get;
535 this.hasGetter_ = true;
536}
537
538
539PropertyDescriptor.prototype.getGet = function() {
540 return this.get_;
541}
542
543
ager@chromium.org5c838252010-02-19 08:53:10 +0000544PropertyDescriptor.prototype.hasGetter = function() {
545 return this.hasGetter_;
546}
547
548
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000549PropertyDescriptor.prototype.setSet = function(set) {
550 this.set_ = set;
551 this.hasSetter_ = true;
552}
553
554
555PropertyDescriptor.prototype.getSet = function() {
556 return this.set_;
557}
558
559
ager@chromium.org5c838252010-02-19 08:53:10 +0000560PropertyDescriptor.prototype.hasSetter = function() {
561 return this.hasSetter_;
562}
563
564
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000565// Converts an array returned from Runtime_GetOwnProperty to an actual
566// property descriptor. For a description of the array layout please
567// see the runtime.cc file.
568function ConvertDescriptorArrayToDescriptor(desc_array) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000569 if (desc_array === false) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000570 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000571 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000572
573 if (IS_UNDEFINED(desc_array)) {
574 return void 0;
575 }
576
577 var desc = new PropertyDescriptor();
578 // This is an accessor.
579 if (desc_array[IS_ACCESSOR_INDEX]) {
580 desc.setGet(desc_array[GETTER_INDEX]);
581 desc.setSet(desc_array[SETTER_INDEX]);
582 } else {
583 desc.setValue(desc_array[VALUE_INDEX]);
584 desc.setWritable(desc_array[WRITABLE_INDEX]);
585 }
586 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
587 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000588
589 return desc;
590}
591
592
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000593// For Harmony proxies.
594function GetTrap(handler, name, defaultTrap) {
595 var trap = handler[name];
596 if (IS_UNDEFINED(trap)) {
597 if (IS_UNDEFINED(defaultTrap)) {
598 throw MakeTypeError("handler_trap_missing", [handler, name]);
599 }
600 trap = defaultTrap;
601 } else if (!IS_FUNCTION(trap)) {
602 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
603 }
604 return trap;
605}
606
607
608function CallTrap0(handler, name, defaultTrap) {
609 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
610}
611
612
613function CallTrap1(handler, name, defaultTrap, x) {
614 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
615}
616
617
618function CallTrap2(handler, name, defaultTrap, x, y) {
619 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
620}
621
622
ager@chromium.org5c838252010-02-19 08:53:10 +0000623// ES5 section 8.12.2.
624function GetProperty(obj, p) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000625 if (%IsJSProxy(obj)) {
626 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000627 var descriptor = CallTrap1(obj, "getPropertyDescriptor", void 0, p);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000628 if (IS_UNDEFINED(descriptor)) return descriptor;
629 var desc = ToCompletePropertyDescriptor(descriptor);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000630 if (!desc.isConfigurable()) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000631 throw MakeTypeError("proxy_prop_not_configurable",
632 [handler, "getPropertyDescriptor", p, descriptor]);
633 }
634 return desc;
635 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000636 var prop = GetOwnProperty(obj);
637 if (!IS_UNDEFINED(prop)) return prop;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000638 var proto = %GetPrototype(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000639 if (IS_NULL(proto)) return void 0;
640 return GetProperty(proto, p);
641}
642
643
644// ES5 section 8.12.6
645function HasProperty(obj, p) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000646 if (%IsJSProxy(obj)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000647 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000648 return ToBoolean(CallTrap1(handler, "has", DerivedHasTrap, p));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000649 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 var desc = GetProperty(obj, p);
651 return IS_UNDEFINED(desc) ? false : true;
652}
653
654
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000655// ES5 section 8.12.1.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000656function GetOwnProperty(obj, v) {
657 var p = ToString(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000658 if (%IsJSProxy(obj)) {
659 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000660 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000661 if (IS_UNDEFINED(descriptor)) return descriptor;
662 var desc = ToCompletePropertyDescriptor(descriptor);
663 if (!desc.isConfigurable()) {
664 throw MakeTypeError("proxy_prop_not_configurable",
665 [handler, "getOwnPropertyDescriptor", p, descriptor]);
666 }
667 return desc;
668 }
669
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000670 // GetOwnProperty returns an array indexed by the constants
671 // defined in macros.py.
672 // If p is not a property on obj undefined is returned.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000673 var props = %GetOwnProperty(ToObject(obj), ToString(v));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000674
675 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000676 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000677
678 return ConvertDescriptorArrayToDescriptor(props);
679}
680
681
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000682// Harmony proxies.
683function DefineProxyProperty(obj, p, attributes, should_throw) {
684 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000685 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000686 if (!ToBoolean(result)) {
687 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000688 throw MakeTypeError("handler_returned_false",
689 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000690 } else {
691 return false;
692 }
693 }
694 return true;
695}
696
697
lrn@chromium.org25156de2010-04-06 13:10:27 +0000698// ES5 8.12.9.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000699function DefineOwnProperty(obj, p, desc, should_throw) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000700 if (%IsJSProxy(obj)) {
701 var attributes = FromGenericPropertyDescriptor(desc);
702 return DefineProxyProperty(obj, p, attributes, should_throw);
703 }
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
706 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000707 if (current_or_access === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000708
709 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000710 var extensible = %IsExtensible(ToObject(obj));
711
712 // Error handling according to spec.
713 // Step 3
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000714 if (IS_UNDEFINED(current) && !extensible) {
715 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000716 throw MakeTypeError("define_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000717 } else {
718 return;
719 }
720 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000721
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000722 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000723 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000724 if ((IsGenericDescriptor(desc) ||
725 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
726 (!desc.hasEnumerable() ||
727 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000728 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000729 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000730 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000731 SameValue(desc.isWritable(), current.isWritable())) &&
732 (!desc.hasValue() ||
733 SameValue(desc.getValue(), current.getValue())) &&
734 (!desc.hasGetter() ||
735 SameValue(desc.getGet(), current.getGet())) &&
736 (!desc.hasSetter() ||
737 SameValue(desc.getSet(), current.getSet()))) {
738 return true;
739 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000740 if (!current.isConfigurable()) {
741 // Step 7
742 if (desc.isConfigurable() ||
743 (desc.hasEnumerable() &&
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000744 desc.isEnumerable() != current.isEnumerable())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000745 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000746 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000747 } else {
748 return;
749 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000750 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000751 // Step 8
752 if (!IsGenericDescriptor(desc)) {
753 // Step 9a
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000754 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000755 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000756 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000757 } else {
758 return;
759 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000760 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000761 // Step 10a
762 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000763 if (!current.isWritable() && desc.isWritable()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000764 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000765 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000766 } else {
767 return;
768 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000769 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000770 if (!current.isWritable() && desc.hasValue() &&
771 !SameValue(desc.getValue(), current.getValue())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000772 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000773 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000774 } else {
775 return;
776 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777 }
778 }
779 // Step 11
780 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000781 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000782 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000783 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000784 } else {
785 return;
786 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000788 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000789 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000790 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000791 } else {
792 return;
793 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000794 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000795 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000796 }
797 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000798 }
799
lrn@chromium.org25156de2010-04-06 13:10:27 +0000800 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000801 // only send to the data descriptor.
802 // Take special care if enumerable and configurable is not defined on
803 // desc (we need to preserve the existing values from current).
804 var flag = NONE;
805 if (desc.hasEnumerable()) {
806 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
807 } else if (!IS_UNDEFINED(current)) {
808 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000809 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000810 flag |= DONT_ENUM;
811 }
812
813 if (desc.hasConfigurable()) {
814 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
815 } else if (!IS_UNDEFINED(current)) {
816 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
817 } else
818 flag |= DONT_DELETE;
819
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000820 if (IsDataDescriptor(desc) ||
821 (IsGenericDescriptor(desc) &&
822 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
823 // There are 3 cases that lead here:
824 // Step 4a - defining a new data property.
825 // Steps 9b & 12 - replacing an existing accessor property with a data
826 // property.
827 // Step 12 - updating an existing data property with a data or generic
828 // descriptor.
829
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000830 if (desc.hasWritable()) {
831 flag |= desc.isWritable() ? 0 : READ_ONLY;
832 } else if (!IS_UNDEFINED(current)) {
833 flag |= current.isWritable() ? 0 : READ_ONLY;
834 } else {
835 flag |= READ_ONLY;
836 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000837
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000838 var value = void 0; // Default value is undefined.
839 if (desc.hasValue()) {
840 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000841 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000842 value = current.getValue();
843 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000844
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000845 %DefineOrRedefineDataProperty(obj, p, value, flag);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000846 } else if (IsGenericDescriptor(desc)) {
847 // Step 12 - updating an existing accessor property with generic
848 // descriptor. Changing flags only.
849 %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000850 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000851 // There are 3 cases that lead here:
852 // Step 4b - defining a new accessor property.
853 // Steps 9c & 12 - replacing an existing data property with an accessor
854 // property.
855 // Step 12 - updating an existing accessor property with an accessor
856 // descriptor.
857 if (desc.hasGetter()) {
858 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000859 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 if (desc.hasSetter()) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000861 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
862 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000863 }
864 return true;
865}
866
867
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000868// ES5 section 15.2.3.2.
869function ObjectGetPrototypeOf(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000870 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000871 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000872 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000873}
874
875
lrn@chromium.org25156de2010-04-06 13:10:27 +0000876// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877function ObjectGetOwnPropertyDescriptor(obj, p) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000878 if (!IS_SPEC_OBJECT(obj))
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000879 throw MakeTypeError("obj_ctor_property_non_object",
880 ["getOwnPropertyDescriptor"]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000881 var desc = GetOwnProperty(obj, p);
882 return FromPropertyDescriptor(desc);
883}
884
885
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000886// For Harmony proxies
887function ToStringArray(obj, trap) {
888 if (!IS_SPEC_OBJECT(obj)) {
889 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
890 }
891 var n = ToUint32(obj.length);
892 var array = new $Array(n);
893 var names = {}
894 for (var index = 0; index < n; index++) {
895 var s = ToString(obj[index]);
896 if (s in names) {
897 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
898 }
899 array[index] = s;
900 names.s = 0;
901 }
902 return array;
903}
904
905
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000906// ES5 section 15.2.3.4.
907function ObjectGetOwnPropertyNames(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000908 if (!IS_SPEC_OBJECT(obj))
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000909 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
910
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000911 // Special handling for proxies.
912 if (%IsJSProxy(obj)) {
913 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000914 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000915 return ToStringArray(names, "getOwnPropertyNames");
916 }
917
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000918 // Find all the indexed properties.
919
920 // Get the local element names.
921 var propertyNames = %GetLocalElementNames(obj);
922
923 // Get names for indexed interceptor properties.
924 if (%GetInterceptorInfo(obj) & 1) {
925 var indexedInterceptorNames =
926 %GetIndexedInterceptorElementNames(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000927 if (indexedInterceptorNames)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000928 propertyNames = propertyNames.concat(indexedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000929 }
930
931 // Find all the named properties.
932
933 // Get the local property names.
934 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
935
936 // Get names for named interceptor properties if any.
937
938 if (%GetInterceptorInfo(obj) & 2) {
939 var namedInterceptorNames =
940 %GetNamedInterceptorPropertyNames(obj);
941 if (namedInterceptorNames) {
942 propertyNames = propertyNames.concat(namedInterceptorNames);
943 }
944 }
945
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000946 // Property names are expected to be unique strings.
947 var propertySet = {};
948 var j = 0;
949 for (var i = 0; i < propertyNames.length; ++i) {
950 var name = ToString(propertyNames[i]);
951 // We need to check for the exact property value since for intrinsic
952 // properties like toString if(propertySet["toString"]) will always
953 // succeed.
954 if (propertySet[name] === true)
955 continue;
956 propertySet[name] = true;
957 propertyNames[j++] = name;
958 }
959 propertyNames.length = j;
ager@chromium.org5c838252010-02-19 08:53:10 +0000960
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000961 return propertyNames;
962}
963
964
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000965// ES5 section 15.2.3.5.
966function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000967 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000968 throw MakeTypeError("proto_object_or_null", [proto]);
969 }
970 var obj = new $Object();
971 obj.__proto__ = proto;
972 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
973 return obj;
974}
975
976
ager@chromium.org5c838252010-02-19 08:53:10 +0000977// ES5 section 15.2.3.6.
978function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000979 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000980 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000981 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000982 var name = ToString(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000983 if (%IsJSProxy(obj)) {
984 // Clone the attributes object for protection.
985 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
986 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
987 var attributesClone = {}
988 for (var a in attributes) {
989 attributesClone[a] = attributes[a];
990 }
991 DefineProxyProperty(obj, name, attributesClone, true);
992 // The following would implement the spec as in the current proposal,
993 // but after recent comments on es-discuss, is most likely obsolete.
994 /*
995 var defineObj = FromGenericPropertyDescriptor(desc);
996 var names = ObjectGetOwnPropertyNames(attributes);
997 var standardNames =
998 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
999 for (var i = 0; i < names.length; i++) {
1000 var N = names[i];
1001 if (!(%HasLocalProperty(standardNames, N))) {
1002 var attr = GetOwnProperty(attributes, N);
1003 DefineOwnProperty(descObj, N, attr, true);
1004 }
1005 }
1006 // This is really confusing the types, but it is what the proxies spec
1007 // currently requires:
1008 desc = descObj;
1009 */
1010 } else {
1011 var desc = ToPropertyDescriptor(attributes);
1012 DefineOwnProperty(obj, name, desc, true);
1013 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001014 return obj;
1015}
1016
1017
1018// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001019function ObjectDefineProperties(obj, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001020 if (!IS_SPEC_OBJECT(obj))
ager@chromium.org5c838252010-02-19 08:53:10 +00001021 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001022 var props = ToObject(properties);
1023 var key_values = [];
1024 for (var key in props) {
1025 if (%HasLocalProperty(props, key)) {
1026 key_values.push(key);
1027 var value = props[key];
1028 var desc = ToPropertyDescriptor(value);
1029 key_values.push(desc);
1030 }
1031 }
1032 for (var i = 0; i < key_values.length; i += 2) {
1033 var key = key_values[i];
1034 var desc = key_values[i + 1];
1035 DefineOwnProperty(obj, key, desc, true);
1036 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001037 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001038}
1039
1040
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001041// Harmony proxies.
1042function ProxyFix(obj) {
1043 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001044 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001045 if (IS_UNDEFINED(props)) {
1046 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1047 }
1048 %Fix(obj);
1049 ObjectDefineProperties(obj, props);
1050}
1051
1052
ager@chromium.orgb5737492010-07-15 09:29:43 +00001053// ES5 section 15.2.3.8.
1054function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001055 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00001056 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
1057 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001058 if (%IsJSProxy(obj)) {
1059 ProxyFix(obj);
1060 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001061 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001062 for (var i = 0; i < names.length; i++) {
1063 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001064 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001065 if (desc.isConfigurable()) {
1066 desc.setConfigurable(false);
1067 DefineOwnProperty(obj, name, desc, true);
1068 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001069 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001070 %PreventExtensions(obj);
1071 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001072}
1073
1074
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001075// ES5 section 15.2.3.9.
1076function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001077 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001078 throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
1079 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001080 if (%IsJSProxy(obj)) {
1081 ProxyFix(obj);
1082 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001083 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001084 for (var i = 0; i < names.length; i++) {
1085 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001086 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001087 if (desc.isWritable() || desc.isConfigurable()) {
1088 if (IsDataDescriptor(desc)) desc.setWritable(false);
1089 desc.setConfigurable(false);
1090 DefineOwnProperty(obj, name, desc, true);
1091 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001092 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001093 %PreventExtensions(obj);
1094 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001095}
1096
1097
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001098// ES5 section 15.2.3.10
1099function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001100 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001101 throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
1102 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001103 if (%IsJSProxy(obj)) {
1104 ProxyFix(obj);
1105 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001106 %PreventExtensions(obj);
1107 return obj;
1108}
1109
1110
ager@chromium.orgb5737492010-07-15 09:29:43 +00001111// ES5 section 15.2.3.11
1112function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001113 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00001114 throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
1115 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001116 if (%IsJSProxy(obj)) {
1117 return false;
1118 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001119 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001120 for (var i = 0; i < names.length; i++) {
1121 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001122 var desc = GetOwnProperty(obj, name);
1123 if (desc.isConfigurable()) return false;
1124 }
1125 if (!ObjectIsExtensible(obj)) {
1126 return true;
1127 }
1128 return false;
1129}
1130
1131
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001132// ES5 section 15.2.3.12
1133function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001134 if (!IS_SPEC_OBJECT(obj)) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001135 throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
1136 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001137 if (%IsJSProxy(obj)) {
1138 return false;
1139 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001140 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001141 for (var i = 0; i < names.length; i++) {
1142 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001143 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001144 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1145 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001146 }
1147 if (!ObjectIsExtensible(obj)) {
1148 return true;
1149 }
1150 return false;
1151}
1152
1153
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001154// ES5 section 15.2.3.13
1155function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001156 if (!IS_SPEC_OBJECT(obj)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001157 throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001158 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001159 if (%IsJSProxy(obj)) {
1160 return true;
1161 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001162 return %IsExtensible(obj);
1163}
1164
1165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001167 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 if (x == null) return this;
1169 return ToObject(x);
1170 } else {
1171 if (x == null) return { };
1172 return ToObject(x);
1173 }
1174});
1175
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001176%SetExpectedNumberOfProperties($Object, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177
1178// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179
1180
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001181function SetupObject() {
1182 // Setup non-enumerable functions on the Object.prototype object.
1183 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1184 "toString", ObjectToString,
1185 "toLocaleString", ObjectToLocaleString,
1186 "valueOf", ObjectValueOf,
1187 "hasOwnProperty", ObjectHasOwnProperty,
1188 "isPrototypeOf", ObjectIsPrototypeOf,
1189 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1190 "__defineGetter__", ObjectDefineGetter,
1191 "__lookupGetter__", ObjectLookupGetter,
1192 "__defineSetter__", ObjectDefineSetter,
1193 "__lookupSetter__", ObjectLookupSetter
1194 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001195 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001196 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001197 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001198 "defineProperty", ObjectDefineProperty,
1199 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001200 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001201 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001202 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001203 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
1204 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001205 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001206 "isSealed", ObjectIsSealed,
1207 "preventExtensions", ObjectPreventExtension,
1208 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001209 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001210}
1211
1212SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213
1214
1215// ----------------------------------------------------------------------------
1216// Boolean
1217
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001218function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219 // NOTE: Both Boolean objects and values can enter here as
1220 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001221 var b = this;
1222 if (!IS_BOOLEAN(b)) {
1223 if (!IS_BOOLEAN_WRAPPER(b)) {
1224 throw new $TypeError('Boolean.prototype.toString is not generic');
1225 }
1226 b = %_ValueOf(b);
1227 }
1228 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001229}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230
1231
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001232function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233 // NOTE: Both Boolean objects and values can enter here as
1234 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001235 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 throw new $TypeError('Boolean.prototype.valueOf is not generic');
1237 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001238}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239
1240
1241// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001242
1243
1244function SetupBoolean() {
1245 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1246 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001247 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001248 ));
1249}
1250
1251SetupBoolean();
1252
1253// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254// Number
1255
1256// Set the Number function and constructor.
1257%SetCode($Number, function(x) {
1258 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001259 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 %_SetValueOf(this, value);
1261 } else {
1262 return value;
1263 }
1264});
1265
1266%FunctionSetPrototype($Number, new $Number(0));
1267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001269function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 // NOTE: Both Number objects and values can enter here as
1271 // 'this'. This is not as dictated by ECMA-262.
1272 var number = this;
1273 if (!IS_NUMBER(this)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001274 if (!IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 throw new $TypeError('Number.prototype.toString is not generic');
1276 // Get the value of this number in case it's an object.
1277 number = %_ValueOf(this);
1278 }
1279 // Fast case: Convert number in radix 10.
1280 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001281 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 }
1283
1284 // Convert the radix to an integer and check the range.
1285 radix = TO_INTEGER(radix);
1286 if (radix < 2 || radix > 36) {
1287 throw new $RangeError('toString() radix argument must be between 2 and 36');
1288 }
1289 // Convert the number to a string in the given radix.
1290 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001291}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292
1293
1294// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001295function NumberToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001296 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1297 throw MakeTypeError("called_on_null_or_undefined",
1298 ["Number.prototype.toLocaleString"]);
1299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001301}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
1303
1304// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001305function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 // NOTE: Both Number objects and values can enter here as
1307 // 'this'. This is not as dictated by ECMA-262.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001308 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 throw new $TypeError('Number.prototype.valueOf is not generic');
1310 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001311}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313
1314// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001315function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 var f = TO_INTEGER(fractionDigits);
1317 if (f < 0 || f > 20) {
1318 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1319 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00001320 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1321 throw MakeTypeError("called_on_null_or_undefined",
1322 ["Number.prototype.toFixed"]);
1323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 var x = ToNumber(this);
1325 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001326}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327
1328
1329// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001330function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 var f = -1;
1332 if (!IS_UNDEFINED(fractionDigits)) {
1333 f = TO_INTEGER(fractionDigits);
1334 if (f < 0 || f > 20) {
1335 throw new $RangeError("toExponential() argument must be between 0 and 20");
1336 }
1337 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00001338 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1339 throw MakeTypeError("called_on_null_or_undefined",
1340 ["Number.prototype.toExponential"]);
1341 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 var x = ToNumber(this);
1343 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001344}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346
1347// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001348function NumberToPrecision(precision) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001349 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1350 throw MakeTypeError("called_on_null_or_undefined",
1351 ["Number.prototype.toPrecision"]);
1352 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1354 var p = TO_INTEGER(precision);
1355 if (p < 1 || p > 21) {
1356 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1357 }
1358 var x = ToNumber(this);
1359 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001360}
1361
1362
1363// ----------------------------------------------------------------------------
1364
1365function SetupNumber() {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001366 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001367 // Setup the constructor property on the Number prototype object.
1368 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1369
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001370 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001371 // ECMA-262 section 15.7.3.1.
1372 %SetProperty($Number,
1373 "MAX_VALUE",
1374 1.7976931348623157e+308,
1375 DONT_ENUM | DONT_DELETE | READ_ONLY);
1376
1377 // ECMA-262 section 15.7.3.2.
1378 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
1379
1380 // ECMA-262 section 15.7.3.3.
1381 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1382
1383 // ECMA-262 section 15.7.3.4.
1384 %SetProperty($Number,
1385 "NEGATIVE_INFINITY",
1386 -1/0,
1387 DONT_ENUM | DONT_DELETE | READ_ONLY);
1388
1389 // ECMA-262 section 15.7.3.5.
1390 %SetProperty($Number,
1391 "POSITIVE_INFINITY",
1392 1/0,
1393 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001394 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001395
1396 // Setup non-enumerable functions on the Number prototype object.
1397 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1398 "toString", NumberToString,
1399 "toLocaleString", NumberToLocaleString,
1400 "valueOf", NumberValueOf,
1401 "toFixed", NumberToFixed,
1402 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001403 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001404 ));
1405}
1406
1407SetupNumber();
1408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410// ----------------------------------------------------------------------------
1411// Function
1412
1413$Function.prototype.constructor = $Function;
1414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415function FunctionSourceString(func) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001416 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001421 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 var name = %FunctionGetName(func);
1423 if (name) {
1424 // Mimic what KJS does.
1425 return 'function ' + name + '() { [native code] }';
1426 } else {
1427 return 'function () { [native code] }';
1428 }
1429 }
1430
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001431 var name = %FunctionNameShouldPrintAsAnonymous(func)
1432 ? 'anonymous'
1433 : %FunctionGetName(func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001435}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436
1437
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001438function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001440}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
1442
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001443// ES5 15.3.4.5
1444function FunctionBind(this_arg) { // Length is 1.
1445 if (!IS_FUNCTION(this)) {
1446 throw new $TypeError('Bind must be called on a function');
1447 }
1448 // this_arg is not an argument that should be bound.
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001449 var argc_bound = (%_ArgumentsLength() || 1) - 1;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001450 var fn = this;
1451 if (argc_bound == 0) {
1452 var result = function() {
1453 if (%_IsConstructCall()) {
1454 // %NewObjectFromBound implicitly uses arguments passed to this
1455 // function. We do not pass the arguments object explicitly to avoid
1456 // materializing it and guarantee that this function will be optimized.
1457 return %NewObjectFromBound(fn, null);
1458 }
1459
1460 return fn.apply(this_arg, arguments);
1461 };
1462 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001463 var bound_args = new InternalArray(argc_bound);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001464 for(var i = 0; i < argc_bound; i++) {
1465 bound_args[i] = %_Arguments(i+1);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001466 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001467
1468 var result = function() {
1469 // If this is a construct call we use a special runtime method
1470 // to generate the actual object using the bound function.
1471 if (%_IsConstructCall()) {
1472 // %NewObjectFromBound implicitly uses arguments passed to this
1473 // function. We do not pass the arguments object explicitly to avoid
1474 // materializing it and guarantee that this function will be optimized.
1475 return %NewObjectFromBound(fn, bound_args);
1476 }
1477
1478 // Combine the args we got from the bind call with the args
1479 // given as argument to the invocation.
1480 var argc = %_ArgumentsLength();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001481 var args = new InternalArray(argc + argc_bound);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001482 // Add bound arguments.
1483 for (var i = 0; i < argc_bound; i++) {
1484 args[i] = bound_args[i];
1485 }
1486 // Add arguments from call.
1487 for (var i = 0; i < argc; i++) {
1488 args[argc_bound + i] = %_Arguments(i);
1489 }
1490 return fn.apply(this_arg, args);
1491 };
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001492 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001493
1494 // We already have caller and arguments properties on functions,
1495 // which are non-configurable. It therefore makes no sence to
1496 // try to redefine these as defined by the spec. The spec says
1497 // that bind should make these throw a TypeError if get or set
1498 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001499 // To be consistent with our normal functions we leave this as it is.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001500
1501 // Set the correct length.
1502 var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001503 %FunctionRemovePrototype(result);
1504 %FunctionSetBound(result);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001505 %BoundFunctionSetLength(result, length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001506 return result;
1507}
1508
1509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510function NewFunction(arg1) { // length == 1
1511 var n = %_ArgumentsLength();
1512 var p = '';
1513 if (n > 1) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001514 p = new InternalArray(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001515 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1516 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 // If the formal parameters string include ) - an illegal
1518 // character - it may make the combined function expression
1519 // compile. We avoid this problem by checking for this early on.
1520 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1521 }
1522 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001523 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 // The call to SetNewFunctionAttributes will ensure the prototype
1526 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001527 var f = %CompileString(source)();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001528 %FunctionMarkNameShouldPrintAsAnonymous(f);
ager@chromium.org236ad962008-09-25 09:45:57 +00001529 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001530}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531
1532%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001533
1534// ----------------------------------------------------------------------------
1535
1536function SetupFunction() {
1537 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001538 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001539 "toString", FunctionToString
1540 ));
1541}
1542
1543SetupFunction();