blob: 356ce885e0632415124abc94260bc08edeae7d1b [file] [log] [blame]
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001// Copyright 2012 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:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000031// var $Object = global.Object;
32// var $Boolean = global.Boolean;
33// var $Number = global.Number;
34// var $Function = global.Function;
35// var $Array = global.Array;
36// var $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000037//
38// in math.js:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000039// var $floor = MathFloor
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000040
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000041var $isNaN = GlobalIsNaN;
42var $isFinite = GlobalIsFinite;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000043
44// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000047// Helper function used to install functions on objects.
48function InstallFunctions(object, attributes, functions) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000049 if (functions.length >= 8) {
50 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
51 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000052 for (var i = 0; i < functions.length; i += 2) {
53 var key = functions[i];
54 var f = functions[i + 1];
55 %FunctionSetName(f, key);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000056 %FunctionRemovePrototype(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000057 %SetProperty(object, key, f, attributes);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000058 %SetNativeFlag(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000059 }
ager@chromium.org5c838252010-02-19 08:53:10 +000060 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000061}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000063
64// Helper function to install a getter only property.
65function InstallGetter(object, name, getter) {
66 %FunctionSetName(getter, name);
67 %FunctionRemovePrototype(getter);
68 %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
69 %SetNativeFlag(getter);
70}
71
72
73// Prevents changes to the prototype of a built-in function.
fschneider@chromium.org1805e212011-09-05 10:49:12 +000074// The "prototype" property of the function object is made non-configurable,
75// and the prototype object is made non-extensible. The latter prevents
76// changing the __proto__ property.
77function SetUpLockedPrototype(constructor, fields, methods) {
78 %CheckIsBootstrapping();
79 var prototype = constructor.prototype;
80 // Install functions first, because this function is used to initialize
81 // PropertyDescriptor itself.
82 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
83 if (property_count >= 4) {
84 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
85 }
86 if (fields) {
87 for (var i = 0; i < fields.length; i++) {
88 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
89 }
90 }
91 for (var i = 0; i < methods.length; i += 2) {
92 var key = methods[i];
93 var f = methods[i + 1];
94 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
95 %SetNativeFlag(f);
96 }
97 prototype.__proto__ = null;
fschneider@chromium.org1805e212011-09-05 10:49:12 +000098 %ToFastProperties(prototype);
fschneider@chromium.org1805e212011-09-05 10:49:12 +000099}
100
101
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000102// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
105// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000106function GlobalIsNaN(number) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000107 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
108 return NUMBER_IS_NAN(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000109}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
111
112// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000113function GlobalIsFinite(number) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000114 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000115 return NUMBER_IS_FINITE(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000116}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117
118
119// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000120function GlobalParseInt(string, radix) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000121 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 // Some people use parseInt instead of Math.floor. This
123 // optimization makes parseInt on a Smi 12 times faster (60ns
124 // vs 800ns). The following optimization makes parseInt on a
125 // non-Smi number 9 times faster (230ns vs 2070ns). Together
126 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
127 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000128 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000129 ((0.01 < string && string < 1e9) ||
130 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000131 // Truncate number.
132 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000134 string = TO_STRING_INLINE(string);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000135 radix = radix | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000137 // The spec says ToString should be evaluated before ToInt32.
138 string = TO_STRING_INLINE(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 radix = TO_INT32(radix);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000140 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 return $NaN;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000144
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000145 if (%_HasCachedArrayIndex(string) &&
146 (radix == 0 || radix == 10)) {
147 return %_GetCachedArrayIndex(string);
148 }
149 return %StringParseInt(string, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000150}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151
152
153// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000154function GlobalParseFloat(string) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000155 string = TO_STRING_INLINE(string);
156 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
157 return %StringParseFloat(string);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000158}
159
160
161function GlobalEval(x) {
162 if (!IS_STRING(x)) return x;
163
ager@chromium.orge2902be2009-06-08 12:21:35 +0000164 var global_receiver = %GlobalReceiver(global);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000165 var global_is_detached = (global === global_receiver);
166
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000167 // For consistency with JSC we require the global object passed to
168 // eval to be the global object from which 'eval' originated. This
169 // is not mandated by the spec.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000170 // We only throw if the global has been detached, since we need the
171 // receiver as this-value for the call.
172 if (global_is_detached) {
173 throw new $EvalError('The "this" value passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000174 'be the global object from which eval originated');
175 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000176
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000177 var f = %CompileString(x);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000178 if (!IS_FUNCTION(f)) return f;
179
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000180 return %_CallFunction(global_receiver, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000181}
182
183
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000184// ----------------------------------------------------------------------------
185
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000186// Set up global object.
187function SetUpGlobal() {
188 %CheckIsBootstrapping();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000189 // ECMA 262 - 15.1.1.1.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000190 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000191
192 // ECMA-262 - 15.1.1.2.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000193 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000194
195 // ECMA-262 - 15.1.1.3.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000196 %SetProperty(global, "undefined", void 0,
197 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000198
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000199 // Set up non-enumerable function on the global object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200 InstallFunctions(global, DONT_ENUM, $Array(
201 "isNaN", GlobalIsNaN,
202 "isFinite", GlobalIsFinite,
203 "parseInt", GlobalParseInt,
204 "parseFloat", GlobalParseFloat,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000205 "eval", GlobalEval
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000206 ));
207}
208
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000209SetUpGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210
211// ----------------------------------------------------------------------------
212// Boolean (first part of definition)
213
214
215%SetCode($Boolean, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000216 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217 %_SetValueOf(this, ToBoolean(x));
218 } else {
219 return ToBoolean(x);
220 }
221});
222
223%FunctionSetPrototype($Boolean, new $Boolean(false));
224
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000225%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226
227// ----------------------------------------------------------------------------
228// Object
229
230$Object.prototype.constructor = $Object;
231
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000232// ECMA-262 - 15.2.4.2
233function ObjectToString() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000234 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
235 if (IS_NULL(this)) return "[object Null]";
236 if (IS_SYMBOL(this)) return "[object Symbol]";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000237 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000238}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
240
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000241// ECMA-262 - 15.2.4.3
242function ObjectToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000243 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
244 throw MakeTypeError("called_on_null_or_undefined",
245 ["Object.prototype.toLocaleString"]);
246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000247 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000248}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249
250
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000251// ECMA-262 - 15.2.4.4
252function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000253 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000254}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255
256
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000257// ECMA-262 - 15.2.4.5
258function ObjectHasOwnProperty(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000259 if (%IsJSProxy(this)) {
260 var handler = %GetHandler(this);
261 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
262 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000263 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000264}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265
266
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000267// ECMA-262 - 15.2.4.6
268function ObjectIsPrototypeOf(V) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000269 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
270 throw MakeTypeError("called_on_null_or_undefined",
271 ["Object.prototype.isPrototypeOf"]);
272 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000273 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000274 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000275}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276
277
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000278// ECMA-262 - 15.2.4.6
279function ObjectPropertyIsEnumerable(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000280 var P = ToString(V);
281 if (%IsJSProxy(this)) {
282 var desc = GetOwnProperty(this, P);
283 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
284 }
285 return %IsPropertyEnumerable(ToObject(this), P);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000286}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000287
288
289// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290function ObjectDefineGetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000291 var receiver = this;
292 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
293 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000294 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000295 if (!IS_SPEC_FUNCTION(fun)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000296 throw new $TypeError(
297 'Object.prototype.__defineGetter__: Expecting function');
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000299 var desc = new PropertyDescriptor();
300 desc.setGet(fun);
301 desc.setEnumerable(true);
302 desc.setConfigurable(true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000303 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000304}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000305
306
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307function ObjectLookupGetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000308 var receiver = this;
309 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
310 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000311 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000312 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314
315
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000316function ObjectDefineSetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000317 var receiver = this;
318 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
319 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000321 if (!IS_SPEC_FUNCTION(fun)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000322 throw new $TypeError(
323 'Object.prototype.__defineSetter__: Expecting function');
324 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000325 var desc = new PropertyDescriptor();
326 desc.setSet(fun);
327 desc.setEnumerable(true);
328 desc.setConfigurable(true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000329 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000330}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331
332
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333function ObjectLookupSetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000334 var receiver = this;
335 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
336 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000337 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000338 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000339}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
341
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000342function ObjectKeys(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000343 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000344 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000345 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000346 if (%IsJSProxy(obj)) {
347 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000348 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000349 return ToStringArray(names, "keys");
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000350 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000351 return %LocalKeys(obj);
352}
353
354
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000355// ES5 8.10.1.
356function IsAccessorDescriptor(desc) {
357 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000358 return desc.hasGetter() || desc.hasSetter();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000359}
360
361
362// ES5 8.10.2.
363function IsDataDescriptor(desc) {
364 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000365 return desc.hasValue() || desc.hasWritable();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000366}
367
368
369// ES5 8.10.3.
370function IsGenericDescriptor(desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000371 if (IS_UNDEFINED(desc)) return false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000372 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
373}
374
375
376function IsInconsistentDescriptor(desc) {
377 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
378}
379
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000380
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000381// ES5 8.10.4
382function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000383 if (IS_UNDEFINED(desc)) return desc;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000384
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000385 if (IsDataDescriptor(desc)) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000386 return { value: desc.getValue(),
387 writable: desc.isWritable(),
388 enumerable: desc.isEnumerable(),
389 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000390 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000391 // Must be an AccessorDescriptor then. We never return a generic descriptor.
392 return { get: desc.getGet(),
393 set: desc.getSet(),
394 enumerable: desc.isEnumerable(),
395 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000396}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000397
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000398
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000399// Harmony Proxies
400function FromGenericPropertyDescriptor(desc) {
401 if (IS_UNDEFINED(desc)) return desc;
402 var obj = new $Object();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000403
404 if (desc.hasValue()) {
405 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
406 }
407 if (desc.hasWritable()) {
408 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
409 }
410 if (desc.hasGetter()) {
411 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
412 }
413 if (desc.hasSetter()) {
414 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
415 }
416 if (desc.hasEnumerable()) {
417 %IgnoreAttributesAndSetProperty(obj, "enumerable",
418 desc.isEnumerable(), NONE);
419 }
420 if (desc.hasConfigurable()) {
421 %IgnoreAttributesAndSetProperty(obj, "configurable",
422 desc.isConfigurable(), NONE);
423 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000424 return obj;
425}
426
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000427
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000428// ES5 8.10.5.
429function ToPropertyDescriptor(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000430 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000431 throw MakeTypeError("property_desc_object", [obj]);
432 }
433 var desc = new PropertyDescriptor();
434
435 if ("enumerable" in obj) {
436 desc.setEnumerable(ToBoolean(obj.enumerable));
437 }
438
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000439 if ("configurable" in obj) {
440 desc.setConfigurable(ToBoolean(obj.configurable));
441 }
442
443 if ("value" in obj) {
444 desc.setValue(obj.value);
445 }
446
447 if ("writable" in obj) {
448 desc.setWritable(ToBoolean(obj.writable));
449 }
450
451 if ("get" in obj) {
452 var get = obj.get;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000453 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000454 throw MakeTypeError("getter_must_be_callable", [get]);
455 }
456 desc.setGet(get);
457 }
458
459 if ("set" in obj) {
460 var set = obj.set;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000461 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 throw MakeTypeError("setter_must_be_callable", [set]);
463 }
464 desc.setSet(set);
465 }
466
467 if (IsInconsistentDescriptor(desc)) {
468 throw MakeTypeError("value_and_accessor", [obj]);
469 }
470 return desc;
471}
472
473
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000474// For Harmony proxies.
475function ToCompletePropertyDescriptor(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000476 var desc = ToPropertyDescriptor(obj);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000477 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000478 if (!desc.hasValue()) desc.setValue(void 0);
479 if (!desc.hasWritable()) desc.setWritable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000480 } else {
481 // Is accessor descriptor.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000482 if (!desc.hasGetter()) desc.setGet(void 0);
483 if (!desc.hasSetter()) desc.setSet(void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000484 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000485 if (!desc.hasEnumerable()) desc.setEnumerable(false);
486 if (!desc.hasConfigurable()) desc.setConfigurable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000487 return desc;
488}
489
490
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000491function PropertyDescriptor() {
492 // Initialize here so they are all in-object and have the same map.
493 // Default values from ES5 8.6.1.
494 this.value_ = void 0;
495 this.hasValue_ = false;
496 this.writable_ = false;
497 this.hasWritable_ = false;
498 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000499 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000500 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000501 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502 this.get_ = void 0;
503 this.hasGetter_ = false;
504 this.set_ = void 0;
505 this.hasSetter_ = false;
506}
507
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000508SetUpLockedPrototype(PropertyDescriptor, $Array(
509 "value_",
510 "hasValue_",
511 "writable_",
512 "hasWritable_",
513 "enumerable_",
514 "hasEnumerable_",
515 "configurable_",
516 "hasConfigurable_",
517 "get_",
518 "hasGetter_",
519 "set_",
520 "hasSetter_"
521 ), $Array(
522 "toString", function() {
523 return "[object PropertyDescriptor]";
524 },
525 "setValue", function(value) {
526 this.value_ = value;
527 this.hasValue_ = true;
528 },
529 "getValue", function() {
530 return this.value_;
531 },
532 "hasValue", function() {
533 return this.hasValue_;
534 },
535 "setEnumerable", function(enumerable) {
536 this.enumerable_ = enumerable;
537 this.hasEnumerable_ = true;
538 },
539 "isEnumerable", function () {
540 return this.enumerable_;
541 },
542 "hasEnumerable", function() {
543 return this.hasEnumerable_;
544 },
545 "setWritable", function(writable) {
546 this.writable_ = writable;
547 this.hasWritable_ = true;
548 },
549 "isWritable", function() {
550 return this.writable_;
551 },
552 "hasWritable", function() {
553 return this.hasWritable_;
554 },
555 "setConfigurable", function(configurable) {
556 this.configurable_ = configurable;
557 this.hasConfigurable_ = true;
558 },
559 "hasConfigurable", function() {
560 return this.hasConfigurable_;
561 },
562 "isConfigurable", function() {
563 return this.configurable_;
564 },
565 "setGet", function(get) {
566 this.get_ = get;
567 this.hasGetter_ = true;
568 },
569 "getGet", function() {
570 return this.get_;
571 },
572 "hasGetter", function() {
573 return this.hasGetter_;
574 },
575 "setSet", function(set) {
576 this.set_ = set;
577 this.hasSetter_ = true;
578 },
579 "getSet", function() {
580 return this.set_;
581 },
582 "hasSetter", function() {
583 return this.hasSetter_;
584 }));
ager@chromium.org5c838252010-02-19 08:53:10 +0000585
586
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000587// Converts an array returned from Runtime_GetOwnProperty to an actual
588// property descriptor. For a description of the array layout please
589// see the runtime.cc file.
590function ConvertDescriptorArrayToDescriptor(desc_array) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000591 if (desc_array === false) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000592 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000593 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000594
595 if (IS_UNDEFINED(desc_array)) {
596 return void 0;
597 }
598
599 var desc = new PropertyDescriptor();
600 // This is an accessor.
601 if (desc_array[IS_ACCESSOR_INDEX]) {
602 desc.setGet(desc_array[GETTER_INDEX]);
603 desc.setSet(desc_array[SETTER_INDEX]);
604 } else {
605 desc.setValue(desc_array[VALUE_INDEX]);
606 desc.setWritable(desc_array[WRITABLE_INDEX]);
607 }
608 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
609 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000610
611 return desc;
612}
613
614
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000615// For Harmony proxies.
616function GetTrap(handler, name, defaultTrap) {
617 var trap = handler[name];
618 if (IS_UNDEFINED(trap)) {
619 if (IS_UNDEFINED(defaultTrap)) {
620 throw MakeTypeError("handler_trap_missing", [handler, name]);
621 }
622 trap = defaultTrap;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000623 } else if (!IS_SPEC_FUNCTION(trap)) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000624 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
625 }
626 return trap;
627}
628
629
630function CallTrap0(handler, name, defaultTrap) {
631 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
632}
633
634
635function CallTrap1(handler, name, defaultTrap, x) {
636 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
637}
638
639
640function CallTrap2(handler, name, defaultTrap, x, y) {
641 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
642}
643
644
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000645// ES5 section 8.12.1.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000646function GetOwnProperty(obj, v) {
647 var p = ToString(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000648 if (%IsJSProxy(obj)) {
649 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000650 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000651 if (IS_UNDEFINED(descriptor)) return descriptor;
652 var desc = ToCompletePropertyDescriptor(descriptor);
653 if (!desc.isConfigurable()) {
654 throw MakeTypeError("proxy_prop_not_configurable",
655 [handler, "getOwnPropertyDescriptor", p, descriptor]);
656 }
657 return desc;
658 }
659
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000660 // GetOwnProperty returns an array indexed by the constants
661 // defined in macros.py.
662 // If p is not a property on obj undefined is returned.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000663 var props = %GetOwnProperty(ToObject(obj), ToString(v));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000664
665 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000666 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000667
668 return ConvertDescriptorArrayToDescriptor(props);
669}
670
671
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000672// ES5 section 8.12.7.
673function Delete(obj, p, should_throw) {
674 var desc = GetOwnProperty(obj, p);
675 if (IS_UNDEFINED(desc)) return true;
676 if (desc.isConfigurable()) {
677 %DeleteProperty(obj, p, 0);
678 return true;
679 } else if (should_throw) {
680 throw MakeTypeError("define_disallowed", [p]);
681 } else {
682 return;
683 }
684}
685
686
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000687// Harmony proxies.
688function DefineProxyProperty(obj, p, attributes, should_throw) {
689 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000690 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 if (!ToBoolean(result)) {
692 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000693 throw MakeTypeError("handler_returned_false",
694 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000695 } else {
696 return false;
697 }
698 }
699 return true;
700}
701
702
lrn@chromium.org25156de2010-04-06 13:10:27 +0000703// ES5 8.12.9.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000704function DefineObjectProperty(obj, p, desc, should_throw) {
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000718 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000719 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000748 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000749 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000758 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000759 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000767 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000768 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000775 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000776 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000785 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000786 }
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 {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000792 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000793 }
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);
ager@chromium.org5c838252010-02-19 08:53:10 +0000846 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 // There are 3 cases that lead here:
848 // Step 4b - defining a new accessor property.
849 // Steps 9c & 12 - replacing an existing data property with an accessor
850 // property.
851 // Step 12 - updating an existing accessor property with an accessor
852 // descriptor.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000853 var getter = desc.hasGetter() ? desc.getGet() : null;
854 var setter = desc.hasSetter() ? desc.getSet() : null;
855 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000856 }
857 return true;
858}
859
860
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000861// ES5 section 15.4.5.1.
862function DefineArrayProperty(obj, p, desc, should_throw) {
863 // Note that the length of an array is not actually stored as part of the
864 // property, hence we use generated code throughout this function instead of
865 // DefineObjectProperty() to modify its value.
866
867 // Step 3 - Special handling for length property.
868 if (p == "length") {
869 var length = obj.length;
870 if (!desc.hasValue()) {
871 return DefineObjectProperty(obj, "length", desc, should_throw);
872 }
873 var new_length = ToUint32(desc.getValue());
874 if (new_length != ToNumber(desc.getValue())) {
875 throw new $RangeError('defineProperty() array length out of range');
876 }
877 var length_desc = GetOwnProperty(obj, "length");
878 if (new_length != length && !length_desc.isWritable()) {
879 if (should_throw) {
880 throw MakeTypeError("redefine_disallowed", [p]);
881 } else {
882 return false;
883 }
884 }
885 var threw = false;
886 while (new_length < length--) {
887 if (!Delete(obj, ToString(length), false)) {
888 new_length = length + 1;
889 threw = true;
890 break;
891 }
892 }
893 // Make sure the below call to DefineObjectProperty() doesn't overwrite
894 // any magic "length" property by removing the value.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000895 // TODO(mstarzinger): This hack should be removed once we have addressed the
896 // respective TODO in Runtime_DefineOrRedefineDataProperty.
897 // For the time being, we need a hack to prevent Object.observe from
898 // generating two change records.
899 var isObserved = %IsObserved(obj);
900 if (isObserved) %SetIsObserved(obj, false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000901 obj.length = new_length;
902 desc.value_ = void 0;
903 desc.hasValue_ = false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000904 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
905 if (isObserved) %SetIsObserved(obj, true);
906 if (threw) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000907 if (should_throw) {
908 throw MakeTypeError("redefine_disallowed", [p]);
909 } else {
910 return false;
911 }
912 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000913 if (isObserved) {
914 var new_desc = GetOwnProperty(obj, "length");
915 var updated = length_desc.value_ !== new_desc.value_;
916 var reconfigured = length_desc.writable_ !== new_desc.writable_ ||
917 length_desc.configurable_ !== new_desc.configurable_ ||
918 length_desc.enumerable_ !== new_desc.configurable_;
919 if (updated || reconfigured) {
920 NotifyChange(reconfigured ? "reconfigured" : "updated",
921 obj, "length", length_desc.value_);
922 }
923 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000924 return true;
925 }
926
927 // Step 4 - Special handling for array index.
928 var index = ToUint32(p);
929 if (index == ToNumber(p) && index != 4294967295) {
930 var length = obj.length;
931 var length_desc = GetOwnProperty(obj, "length");
932 if ((index >= length && !length_desc.isWritable()) ||
933 !DefineObjectProperty(obj, p, desc, true)) {
934 if (should_throw) {
935 throw MakeTypeError("define_disallowed", [p]);
936 } else {
937 return false;
938 }
939 }
940 if (index >= length) {
941 obj.length = index + 1;
942 }
943 return true;
944 }
945
946 // Step 5 - Fallback to default implementation.
947 return DefineObjectProperty(obj, p, desc, should_throw);
948}
949
950
951// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
952function DefineOwnProperty(obj, p, desc, should_throw) {
953 if (%IsJSProxy(obj)) {
954 var attributes = FromGenericPropertyDescriptor(desc);
955 return DefineProxyProperty(obj, p, attributes, should_throw);
956 } else if (IS_ARRAY(obj)) {
957 return DefineArrayProperty(obj, p, desc, should_throw);
958 } else {
959 return DefineObjectProperty(obj, p, desc, should_throw);
960 }
961}
962
963
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964// ES5 section 15.2.3.2.
965function ObjectGetPrototypeOf(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000966 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000967 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000968 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000969 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000970}
971
972
lrn@chromium.org25156de2010-04-06 13:10:27 +0000973// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000974function ObjectGetOwnPropertyDescriptor(obj, p) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000975 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000976 throw MakeTypeError("called_on_non_object",
977 ["Object.getOwnPropertyDescriptor"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000978 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000979 var desc = GetOwnProperty(obj, p);
980 return FromPropertyDescriptor(desc);
981}
982
983
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000984// For Harmony proxies
985function ToStringArray(obj, trap) {
986 if (!IS_SPEC_OBJECT(obj)) {
987 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
988 }
989 var n = ToUint32(obj.length);
990 var array = new $Array(n);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000991 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000992 for (var index = 0; index < n; index++) {
993 var s = ToString(obj[index]);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000994 if (%HasLocalProperty(names, s)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000995 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000996 }
997 array[index] = s;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 names[s] = 0;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000999 }
1000 return array;
1001}
1002
1003
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001004// ES5 section 15.2.3.4.
1005function ObjectGetOwnPropertyNames(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001006 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001007 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001008 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001009 // Special handling for proxies.
1010 if (%IsJSProxy(obj)) {
1011 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001012 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001013 return ToStringArray(names, "getOwnPropertyNames");
1014 }
1015
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001016 // Find all the indexed properties.
1017
1018 // Get the local element names.
1019 var propertyNames = %GetLocalElementNames(obj);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001020 for (var i = 0; i < propertyNames.length; ++i) {
1021 propertyNames[i] = %_NumberToString(propertyNames[i]);
1022 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001023
1024 // Get names for indexed interceptor properties.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001025 var interceptorInfo = %GetInterceptorInfo(obj);
1026 if ((interceptorInfo & 1) != 0) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001027 var indexedInterceptorNames =
1028 %GetIndexedInterceptorElementNames(obj);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001029 if (indexedInterceptorNames) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001030 propertyNames = propertyNames.concat(indexedInterceptorNames);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001031 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032 }
1033
1034 // Find all the named properties.
1035
1036 // Get the local property names.
1037 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
1038
1039 // Get names for named interceptor properties if any.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001040 if ((interceptorInfo & 2) != 0) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001041 var namedInterceptorNames =
1042 %GetNamedInterceptorPropertyNames(obj);
1043 if (namedInterceptorNames) {
1044 propertyNames = propertyNames.concat(namedInterceptorNames);
1045 }
1046 }
1047
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001048 // Property names are expected to be unique strings,
1049 // but interceptors can interfere with that assumption.
1050 if (interceptorInfo != 0) {
1051 var propertySet = { __proto__: null };
1052 var j = 0;
1053 for (var i = 0; i < propertyNames.length; ++i) {
1054 var name = ToString(propertyNames[i]);
1055 // We need to check for the exact property value since for intrinsic
1056 // properties like toString if(propertySet["toString"]) will always
1057 // succeed.
1058 if (propertySet[name] === true) {
1059 continue;
1060 }
1061 propertySet[name] = true;
1062 propertyNames[j++] = name;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001063 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001064 propertyNames.length = j;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001065 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001066
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001067 return propertyNames;
1068}
1069
1070
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001071// ES5 section 15.2.3.5.
1072function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001073 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001074 throw MakeTypeError("proto_object_or_null", [proto]);
1075 }
1076 var obj = new $Object();
1077 obj.__proto__ = proto;
1078 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1079 return obj;
1080}
1081
1082
ager@chromium.org5c838252010-02-19 08:53:10 +00001083// ES5 section 15.2.3.6.
1084function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001085 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001086 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001087 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001088 var name = ToString(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001089 if (%IsJSProxy(obj)) {
1090 // Clone the attributes object for protection.
1091 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1092 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001093 var attributesClone = { __proto__: null };
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001094 for (var a in attributes) {
1095 attributesClone[a] = attributes[a];
1096 }
1097 DefineProxyProperty(obj, name, attributesClone, true);
1098 // The following would implement the spec as in the current proposal,
1099 // but after recent comments on es-discuss, is most likely obsolete.
1100 /*
1101 var defineObj = FromGenericPropertyDescriptor(desc);
1102 var names = ObjectGetOwnPropertyNames(attributes);
1103 var standardNames =
1104 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1105 for (var i = 0; i < names.length; i++) {
1106 var N = names[i];
1107 if (!(%HasLocalProperty(standardNames, N))) {
1108 var attr = GetOwnProperty(attributes, N);
1109 DefineOwnProperty(descObj, N, attr, true);
1110 }
1111 }
1112 // This is really confusing the types, but it is what the proxies spec
1113 // currently requires:
1114 desc = descObj;
1115 */
1116 } else {
1117 var desc = ToPropertyDescriptor(attributes);
1118 DefineOwnProperty(obj, name, desc, true);
1119 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001120 return obj;
1121}
1122
1123
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001124function GetOwnEnumerablePropertyNames(properties) {
1125 var names = new InternalArray();
1126 for (var key in properties) {
1127 if (%HasLocalProperty(properties, key)) {
1128 names.push(key);
1129 }
1130 }
1131 return names;
1132}
1133
1134
ager@chromium.org5c838252010-02-19 08:53:10 +00001135// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001136function ObjectDefineProperties(obj, properties) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001137 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001138 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001139 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001140 var props = ToObject(properties);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001141 var names = GetOwnEnumerablePropertyNames(props);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001142 var descriptors = new InternalArray();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001143 for (var i = 0; i < names.length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001144 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1145 }
1146 for (var i = 0; i < names.length; i++) {
1147 DefineOwnProperty(obj, names[i], descriptors[i], true);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001148 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001149 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001150}
1151
1152
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001153// Harmony proxies.
1154function ProxyFix(obj) {
1155 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001156 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001157 if (IS_UNDEFINED(props)) {
1158 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1159 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001160
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001161 if (%IsJSFunctionProxy(obj)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001162 var callTrap = %GetCallTrap(obj);
1163 var constructTrap = %GetConstructTrap(obj);
1164 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1165 %Fix(obj); // becomes a regular function
1166 %SetCode(obj, code);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001167 // TODO(rossberg): What about length and other properties? Not specified.
1168 // We just put in some half-reasonable defaults for now.
1169 var prototype = new $Object();
1170 $Object.defineProperty(prototype, "constructor",
danno@chromium.org2c456792011-11-11 12:00:53 +00001171 {value: obj, writable: true, enumerable: false, configurable: true});
1172 // TODO(v8:1530): defineProperty does not handle prototype and length.
1173 %FunctionSetPrototype(obj, prototype);
1174 obj.length = 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001175 } else {
1176 %Fix(obj);
1177 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001178 ObjectDefineProperties(obj, props);
1179}
1180
1181
ager@chromium.orgb5737492010-07-15 09:29:43 +00001182// ES5 section 15.2.3.8.
1183function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001184 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001185 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001186 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001187 if (%IsJSProxy(obj)) {
1188 ProxyFix(obj);
1189 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001190 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001191 for (var i = 0; i < names.length; i++) {
1192 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001193 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001194 if (desc.isConfigurable()) {
1195 desc.setConfigurable(false);
1196 DefineOwnProperty(obj, name, desc, true);
1197 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001198 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001199 %PreventExtensions(obj);
1200 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001201}
1202
1203
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001204// ES5 section 15.2.3.9.
1205function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001206 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001207 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001208 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001209 if (%IsJSProxy(obj)) {
1210 ProxyFix(obj);
1211 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001212 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001213 for (var i = 0; i < names.length; i++) {
1214 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001215 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001216 if (desc.isWritable() || desc.isConfigurable()) {
1217 if (IsDataDescriptor(desc)) desc.setWritable(false);
1218 desc.setConfigurable(false);
1219 DefineOwnProperty(obj, name, desc, true);
1220 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001221 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001222 %PreventExtensions(obj);
1223 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001224}
1225
1226
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001227// ES5 section 15.2.3.10
1228function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001229 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001230 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001231 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001232 if (%IsJSProxy(obj)) {
1233 ProxyFix(obj);
1234 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001235 %PreventExtensions(obj);
1236 return obj;
1237}
1238
1239
ager@chromium.orgb5737492010-07-15 09:29:43 +00001240// ES5 section 15.2.3.11
1241function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001242 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001243 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001244 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001245 if (%IsJSProxy(obj)) {
1246 return false;
1247 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001248 if (%IsExtensible(obj)) {
1249 return false;
1250 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001251 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001252 for (var i = 0; i < names.length; i++) {
1253 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001254 var desc = GetOwnProperty(obj, name);
1255 if (desc.isConfigurable()) return false;
1256 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001257 return true;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001258}
1259
1260
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001261// ES5 section 15.2.3.12
1262function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001263 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001264 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001265 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001266 if (%IsJSProxy(obj)) {
1267 return false;
1268 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001269 if (%IsExtensible(obj)) {
1270 return false;
1271 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001272 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001273 for (var i = 0; i < names.length; i++) {
1274 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001275 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001276 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1277 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001278 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001279 return true;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001280}
1281
1282
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001283// ES5 section 15.2.3.13
1284function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001285 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001286 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001287 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001288 if (%IsJSProxy(obj)) {
1289 return true;
1290 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001291 return %IsExtensible(obj);
1292}
1293
1294
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001295// Harmony egal.
1296function ObjectIs(obj1, obj2) {
1297 if (obj1 === obj2) {
1298 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1299 } else {
1300 return (obj1 !== obj1) && (obj2 !== obj2);
1301 }
1302}
1303
1304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001306 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 if (x == null) return this;
1308 return ToObject(x);
1309 } else {
1310 if (x == null) return { };
1311 return ToObject(x);
1312 }
1313});
1314
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001315%SetExpectedNumberOfProperties($Object, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316
1317// ----------------------------------------------------------------------------
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001318// Object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001320function SetUpObject() {
1321 %CheckIsBootstrapping();
1322 // Set Up non-enumerable functions on the Object.prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001323 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1324 "toString", ObjectToString,
1325 "toLocaleString", ObjectToLocaleString,
1326 "valueOf", ObjectValueOf,
1327 "hasOwnProperty", ObjectHasOwnProperty,
1328 "isPrototypeOf", ObjectIsPrototypeOf,
1329 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1330 "__defineGetter__", ObjectDefineGetter,
1331 "__lookupGetter__", ObjectLookupGetter,
1332 "__defineSetter__", ObjectDefineSetter,
1333 "__lookupSetter__", ObjectLookupSetter
1334 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001335 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001336 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001337 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001338 "defineProperty", ObjectDefineProperty,
1339 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001340 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001341 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001342 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001343 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001344 "is", ObjectIs,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001345 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001346 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001347 "isSealed", ObjectIsSealed,
1348 "preventExtensions", ObjectPreventExtension,
1349 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001350 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001351}
1352
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001353SetUpObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354
1355// ----------------------------------------------------------------------------
1356// Boolean
1357
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001358function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 // NOTE: Both Boolean objects and values can enter here as
1360 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001361 var b = this;
1362 if (!IS_BOOLEAN(b)) {
1363 if (!IS_BOOLEAN_WRAPPER(b)) {
1364 throw new $TypeError('Boolean.prototype.toString is not generic');
1365 }
1366 b = %_ValueOf(b);
1367 }
1368 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001369}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
1371
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001372function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 // NOTE: Both Boolean objects and values can enter here as
1374 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001375 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 throw new $TypeError('Boolean.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001379}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
1381
1382// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001383
1384
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001385function SetUpBoolean () {
1386 %CheckIsBootstrapping();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001387 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1388 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001389 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001390 ));
1391}
1392
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001393SetUpBoolean();
1394
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001395
1396// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397// Number
1398
1399// Set the Number function and constructor.
1400%SetCode($Number, function(x) {
1401 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001402 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 %_SetValueOf(this, value);
1404 } else {
1405 return value;
1406 }
1407});
1408
1409%FunctionSetPrototype($Number, new $Number(0));
1410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001412function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 // NOTE: Both Number objects and values can enter here as
1414 // 'this'. This is not as dictated by ECMA-262.
1415 var number = this;
1416 if (!IS_NUMBER(this)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001417 if (!IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 throw new $TypeError('Number.prototype.toString is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 // Get the value of this number in case it's an object.
1421 number = %_ValueOf(this);
1422 }
1423 // Fast case: Convert number in radix 10.
1424 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001425 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 }
1427
1428 // Convert the radix to an integer and check the range.
1429 radix = TO_INTEGER(radix);
1430 if (radix < 2 || radix > 36) {
1431 throw new $RangeError('toString() radix argument must be between 2 and 36');
1432 }
1433 // Convert the number to a string in the given radix.
1434 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001435}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436
1437
1438// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001439function NumberToLocaleString() {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001440 return %_CallFunction(this, NumberToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001441}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442
1443
1444// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001445function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 // NOTE: Both Number objects and values can enter here as
1447 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001448 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 throw new $TypeError('Number.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001450 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001452}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453
1454
1455// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001456function NumberToFixed(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001457 var x = this;
1458 if (!IS_NUMBER(this)) {
1459 if (!IS_NUMBER_WRAPPER(this)) {
1460 throw MakeTypeError("incompatible_method_receiver",
1461 ["Number.prototype.toFixed", this]);
1462 }
1463 // Get the value of this number in case it's an object.
1464 x = %_ValueOf(this);
1465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 var f = TO_INTEGER(fractionDigits);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468 if (f < 0 || f > 20) {
1469 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1470 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001471
1472 if (NUMBER_IS_NAN(x)) return "NaN";
1473 if (x == 1/0) return "Infinity";
1474 if (x == -1/0) return "-Infinity";
1475
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001477}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
1479
1480// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001481function NumberToExponential(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001482 var x = this;
1483 if (!IS_NUMBER(this)) {
1484 if (!IS_NUMBER_WRAPPER(this)) {
1485 throw MakeTypeError("incompatible_method_receiver",
1486 ["Number.prototype.toExponential", this]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001488 // Get the value of this number in case it's an object.
1489 x = %_ValueOf(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001491 var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
1492
1493 if (NUMBER_IS_NAN(x)) return "NaN";
1494 if (x == 1/0) return "Infinity";
1495 if (x == -1/0) return "-Infinity";
1496
1497 if (IS_UNDEFINED(f)) {
1498 f = -1; // Signal for runtime function that f is not defined.
1499 } else if (f < 0 || f > 20) {
1500 throw new $RangeError("toExponential() argument must be between 0 and 20");
lrn@chromium.org1c092762011-05-09 09:42:16 +00001501 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001503}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504
1505
1506// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001507function NumberToPrecision(precision) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001508 var x = this;
1509 if (!IS_NUMBER(this)) {
1510 if (!IS_NUMBER_WRAPPER(this)) {
1511 throw MakeTypeError("incompatible_method_receiver",
1512 ["Number.prototype.toPrecision", this]);
1513 }
1514 // Get the value of this number in case it's an object.
1515 x = %_ValueOf(this);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1518 var p = TO_INTEGER(precision);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001519
1520 if (NUMBER_IS_NAN(x)) return "NaN";
1521 if (x == 1/0) return "Infinity";
1522 if (x == -1/0) return "-Infinity";
1523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 if (p < 1 || p > 21) {
1525 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001528}
1529
1530
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001531// Harmony isFinite.
1532function NumberIsFinite(number) {
1533 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1534}
1535
1536
1537// Harmony isNaN.
1538function NumberIsNaN(number) {
1539 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1540}
1541
1542
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001543// ----------------------------------------------------------------------------
1544
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001545function SetUpNumber() {
1546 %CheckIsBootstrapping();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001547 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001548 // Set up the constructor property on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001549 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1550
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001551 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001552 // ECMA-262 section 15.7.3.1.
1553 %SetProperty($Number,
1554 "MAX_VALUE",
1555 1.7976931348623157e+308,
1556 DONT_ENUM | DONT_DELETE | READ_ONLY);
1557
1558 // ECMA-262 section 15.7.3.2.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001559 %SetProperty($Number, "MIN_VALUE", 5e-324,
1560 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001561
1562 // ECMA-262 section 15.7.3.3.
1563 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1564
1565 // ECMA-262 section 15.7.3.4.
1566 %SetProperty($Number,
1567 "NEGATIVE_INFINITY",
1568 -1/0,
1569 DONT_ENUM | DONT_DELETE | READ_ONLY);
1570
1571 // ECMA-262 section 15.7.3.5.
1572 %SetProperty($Number,
1573 "POSITIVE_INFINITY",
1574 1/0,
1575 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001576 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001577
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001578 // Set up non-enumerable functions on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001579 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1580 "toString", NumberToString,
1581 "toLocaleString", NumberToLocaleString,
1582 "valueOf", NumberValueOf,
1583 "toFixed", NumberToFixed,
1584 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001585 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001586 ));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001587 InstallFunctions($Number, DONT_ENUM, $Array(
1588 "isFinite", NumberIsFinite,
1589 "isNaN", NumberIsNaN
1590 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001591}
1592
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001593SetUpNumber();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596// ----------------------------------------------------------------------------
1597// Function
1598
1599$Function.prototype.constructor = $Function;
1600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601function FunctionSourceString(func) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001602 while (%IsJSFunctionProxy(func)) {
1603 func = %GetCallTrap(func);
1604 }
1605
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001606 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609
1610 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001611 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 var name = %FunctionGetName(func);
1613 if (name) {
1614 // Mimic what KJS does.
1615 return 'function ' + name + '() { [native code] }';
1616 } else {
1617 return 'function () { [native code] }';
1618 }
1619 }
1620
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001621 var name = %FunctionNameShouldPrintAsAnonymous(func)
1622 ? 'anonymous'
1623 : %FunctionGetName(func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001625}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626
1627
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001628function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001630}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631
1632
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001633// ES5 15.3.4.5
1634function FunctionBind(this_arg) { // Length is 1.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001635 if (!IS_SPEC_FUNCTION(this)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001636 throw new $TypeError('Bind must be called on a function');
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001637 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001638 var boundFunction = function () {
1639 // Poison .arguments and .caller, but is otherwise not detectable.
1640 "use strict";
1641 // This function must not use any object literals (Object, Array, RegExp),
1642 // since the literals-array is being used to store the bound data.
1643 if (%_IsConstructCall()) {
1644 return %NewObjectFromBound(boundFunction);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001645 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001646 var bindings = %BoundFunctionGetBindings(boundFunction);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001647
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001648 var argc = %_ArgumentsLength();
1649 if (argc == 0) {
1650 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1651 }
1652 if (bindings.length === 2) {
1653 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1654 }
1655 var bound_argc = bindings.length - 2;
1656 var argv = new InternalArray(bound_argc + argc);
1657 for (var i = 0; i < bound_argc; i++) {
1658 argv[i] = bindings[i + 2];
1659 }
1660 for (var j = 0; j < argc; j++) {
1661 argv[i++] = %_Arguments(j);
1662 }
1663 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1664 };
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001665
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001666 %FunctionRemovePrototype(boundFunction);
1667 var new_length = 0;
1668 if (%_ClassOf(this) == "Function") {
1669 // Function or FunctionProxy.
1670 var old_length = this.length;
1671 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1672 if ((typeof old_length === "number") &&
1673 ((old_length >>> 0) === old_length)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001674 var argc = %_ArgumentsLength();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001675 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1676 new_length = old_length - argc;
1677 if (new_length < 0) new_length = 0;
1678 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001679 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001680 // This runtime function finds any remaining arguments on the stack,
1681 // so we don't pass the arguments object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001682 var result = %FunctionBindArguments(boundFunction, this,
1683 this_arg, new_length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001684
1685 // We already have caller and arguments properties on functions,
1686 // which are non-configurable. It therefore makes no sence to
1687 // try to redefine these as defined by the spec. The spec says
1688 // that bind should make these throw a TypeError if get or set
1689 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001690 // To be consistent with our normal functions we leave this as it is.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001691 // TODO(lrn): Do set these to be thrower.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001692 return result;
1693}
1694
1695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696function NewFunction(arg1) { // length == 1
1697 var n = %_ArgumentsLength();
1698 var p = '';
1699 if (n > 1) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001700 p = new InternalArray(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001701 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1702 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001703 // If the formal parameters string include ) - an illegal
1704 // character - it may make the combined function expression
1705 // compile. We avoid this problem by checking for this early on.
1706 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1707 }
1708 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001709 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001710
1711 // The call to SetNewFunctionAttributes will ensure the prototype
1712 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001713 var global_receiver = %GlobalReceiver(global);
1714 var f = %_CallFunction(global_receiver, %CompileString(source));
1715
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001716 %FunctionMarkNameShouldPrintAsAnonymous(f);
ager@chromium.org236ad962008-09-25 09:45:57 +00001717 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001718}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719
1720%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001721
1722// ----------------------------------------------------------------------------
1723
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001724function SetUpFunction() {
1725 %CheckIsBootstrapping();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001726 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001727 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001728 "toString", FunctionToString
1729 ));
1730}
1731
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001732SetUpFunction();