blob: e8752c84b8b1389dc30ac7315b394243d92fb947 [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() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000234 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
235 return '[object Undefined]';
236 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000237 if (IS_NULL(this)) return '[object Null]';
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000239}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
241
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000242// ECMA-262 - 15.2.4.3
243function ObjectToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000244 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
245 throw MakeTypeError("called_on_null_or_undefined",
246 ["Object.prototype.toLocaleString"]);
247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000249}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250
251
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000252// ECMA-262 - 15.2.4.4
253function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000254 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000255}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000256
257
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000258// ECMA-262 - 15.2.4.5
259function ObjectHasOwnProperty(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000260 if (%IsJSProxy(this)) {
261 var handler = %GetHandler(this);
262 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
263 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000264 return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000265}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266
267
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000268// ECMA-262 - 15.2.4.6
269function ObjectIsPrototypeOf(V) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000270 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
271 throw MakeTypeError("called_on_null_or_undefined",
272 ["Object.prototype.isPrototypeOf"]);
273 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000274 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000276}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277
278
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000279// ECMA-262 - 15.2.4.6
280function ObjectPropertyIsEnumerable(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000281 var P = ToString(V);
282 if (%IsJSProxy(this)) {
283 var desc = GetOwnProperty(this, P);
284 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
285 }
286 return %IsPropertyEnumerable(ToObject(this), P);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000287}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288
289
290// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000291function ObjectDefineGetter(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 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000296 if (!IS_SPEC_FUNCTION(fun)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000297 throw new $TypeError(
298 'Object.prototype.__defineGetter__: Expecting function');
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000300 var desc = new PropertyDescriptor();
301 desc.setGet(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 ObjectLookupGetter(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), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000314}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315
316
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000317function ObjectDefineSetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000318 var receiver = this;
319 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
320 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000322 if (!IS_SPEC_FUNCTION(fun)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000323 throw new $TypeError(
324 'Object.prototype.__defineSetter__: Expecting function');
325 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000326 var desc = new PropertyDescriptor();
327 desc.setSet(fun);
328 desc.setEnumerable(true);
329 desc.setConfigurable(true);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000330 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000331}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332
333
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334function ObjectLookupSetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000335 var receiver = this;
336 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
337 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000338 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000339 return %LookupAccessor(ToObject(receiver), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000340}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341
342
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000343function ObjectKeys(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000344 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000345 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000346 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000347 if (%IsJSProxy(obj)) {
348 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000349 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000350 return ToStringArray(names, "keys");
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000351 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000352 return %LocalKeys(obj);
353}
354
355
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000356// ES5 8.10.1.
357function IsAccessorDescriptor(desc) {
358 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000359 return desc.hasGetter() || desc.hasSetter();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000360}
361
362
363// ES5 8.10.2.
364function IsDataDescriptor(desc) {
365 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000366 return desc.hasValue() || desc.hasWritable();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000367}
368
369
370// ES5 8.10.3.
371function IsGenericDescriptor(desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000372 if (IS_UNDEFINED(desc)) return false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000373 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
374}
375
376
377function IsInconsistentDescriptor(desc) {
378 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
379}
380
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000381
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000382// ES5 8.10.4
383function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000384 if (IS_UNDEFINED(desc)) return desc;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000385
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000386 if (IsDataDescriptor(desc)) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000387 return { value: desc.getValue(),
388 writable: desc.isWritable(),
389 enumerable: desc.isEnumerable(),
390 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000391 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000392 // Must be an AccessorDescriptor then. We never return a generic descriptor.
393 return { get: desc.getGet(),
394 set: desc.getSet(),
395 enumerable: desc.isEnumerable(),
396 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000397}
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000398
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000399
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000400// Harmony Proxies
401function FromGenericPropertyDescriptor(desc) {
402 if (IS_UNDEFINED(desc)) return desc;
403 var obj = new $Object();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000404
405 if (desc.hasValue()) {
406 %IgnoreAttributesAndSetProperty(obj, "value", desc.getValue(), NONE);
407 }
408 if (desc.hasWritable()) {
409 %IgnoreAttributesAndSetProperty(obj, "writable", desc.isWritable(), NONE);
410 }
411 if (desc.hasGetter()) {
412 %IgnoreAttributesAndSetProperty(obj, "get", desc.getGet(), NONE);
413 }
414 if (desc.hasSetter()) {
415 %IgnoreAttributesAndSetProperty(obj, "set", desc.getSet(), NONE);
416 }
417 if (desc.hasEnumerable()) {
418 %IgnoreAttributesAndSetProperty(obj, "enumerable",
419 desc.isEnumerable(), NONE);
420 }
421 if (desc.hasConfigurable()) {
422 %IgnoreAttributesAndSetProperty(obj, "configurable",
423 desc.isConfigurable(), NONE);
424 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000425 return obj;
426}
427
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000428
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000429// ES5 8.10.5.
430function ToPropertyDescriptor(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000431 if (!IS_SPEC_OBJECT(obj)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000432 throw MakeTypeError("property_desc_object", [obj]);
433 }
434 var desc = new PropertyDescriptor();
435
436 if ("enumerable" in obj) {
437 desc.setEnumerable(ToBoolean(obj.enumerable));
438 }
439
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000440 if ("configurable" in obj) {
441 desc.setConfigurable(ToBoolean(obj.configurable));
442 }
443
444 if ("value" in obj) {
445 desc.setValue(obj.value);
446 }
447
448 if ("writable" in obj) {
449 desc.setWritable(ToBoolean(obj.writable));
450 }
451
452 if ("get" in obj) {
453 var get = obj.get;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000454 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455 throw MakeTypeError("getter_must_be_callable", [get]);
456 }
457 desc.setGet(get);
458 }
459
460 if ("set" in obj) {
461 var set = obj.set;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000462 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000463 throw MakeTypeError("setter_must_be_callable", [set]);
464 }
465 desc.setSet(set);
466 }
467
468 if (IsInconsistentDescriptor(desc)) {
469 throw MakeTypeError("value_and_accessor", [obj]);
470 }
471 return desc;
472}
473
474
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000475// For Harmony proxies.
476function ToCompletePropertyDescriptor(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000477 var desc = ToPropertyDescriptor(obj);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000478 if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000479 if (!desc.hasValue()) desc.setValue(void 0);
480 if (!desc.hasWritable()) desc.setWritable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000481 } else {
482 // Is accessor descriptor.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000483 if (!desc.hasGetter()) desc.setGet(void 0);
484 if (!desc.hasSetter()) desc.setSet(void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000485 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000486 if (!desc.hasEnumerable()) desc.setEnumerable(false);
487 if (!desc.hasConfigurable()) desc.setConfigurable(false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000488 return desc;
489}
490
491
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000492function PropertyDescriptor() {
493 // Initialize here so they are all in-object and have the same map.
494 // Default values from ES5 8.6.1.
495 this.value_ = void 0;
496 this.hasValue_ = false;
497 this.writable_ = false;
498 this.hasWritable_ = false;
499 this.enumerable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000500 this.hasEnumerable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 this.configurable_ = false;
ager@chromium.org5c838252010-02-19 08:53:10 +0000502 this.hasConfigurable_ = false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 this.get_ = void 0;
504 this.hasGetter_ = false;
505 this.set_ = void 0;
506 this.hasSetter_ = false;
507}
508
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000509SetUpLockedPrototype(PropertyDescriptor, $Array(
510 "value_",
511 "hasValue_",
512 "writable_",
513 "hasWritable_",
514 "enumerable_",
515 "hasEnumerable_",
516 "configurable_",
517 "hasConfigurable_",
518 "get_",
519 "hasGetter_",
520 "set_",
521 "hasSetter_"
522 ), $Array(
523 "toString", function() {
524 return "[object PropertyDescriptor]";
525 },
526 "setValue", function(value) {
527 this.value_ = value;
528 this.hasValue_ = true;
529 },
530 "getValue", function() {
531 return this.value_;
532 },
533 "hasValue", function() {
534 return this.hasValue_;
535 },
536 "setEnumerable", function(enumerable) {
537 this.enumerable_ = enumerable;
538 this.hasEnumerable_ = true;
539 },
540 "isEnumerable", function () {
541 return this.enumerable_;
542 },
543 "hasEnumerable", function() {
544 return this.hasEnumerable_;
545 },
546 "setWritable", function(writable) {
547 this.writable_ = writable;
548 this.hasWritable_ = true;
549 },
550 "isWritable", function() {
551 return this.writable_;
552 },
553 "hasWritable", function() {
554 return this.hasWritable_;
555 },
556 "setConfigurable", function(configurable) {
557 this.configurable_ = configurable;
558 this.hasConfigurable_ = true;
559 },
560 "hasConfigurable", function() {
561 return this.hasConfigurable_;
562 },
563 "isConfigurable", function() {
564 return this.configurable_;
565 },
566 "setGet", function(get) {
567 this.get_ = get;
568 this.hasGetter_ = true;
569 },
570 "getGet", function() {
571 return this.get_;
572 },
573 "hasGetter", function() {
574 return this.hasGetter_;
575 },
576 "setSet", function(set) {
577 this.set_ = set;
578 this.hasSetter_ = true;
579 },
580 "getSet", function() {
581 return this.set_;
582 },
583 "hasSetter", function() {
584 return this.hasSetter_;
585 }));
ager@chromium.org5c838252010-02-19 08:53:10 +0000586
587
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000588// Converts an array returned from Runtime_GetOwnProperty to an actual
589// property descriptor. For a description of the array layout please
590// see the runtime.cc file.
591function ConvertDescriptorArrayToDescriptor(desc_array) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000592 if (desc_array === false) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000593 throw 'Internal error: invalid desc_array';
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000594 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000595
596 if (IS_UNDEFINED(desc_array)) {
597 return void 0;
598 }
599
600 var desc = new PropertyDescriptor();
601 // This is an accessor.
602 if (desc_array[IS_ACCESSOR_INDEX]) {
603 desc.setGet(desc_array[GETTER_INDEX]);
604 desc.setSet(desc_array[SETTER_INDEX]);
605 } else {
606 desc.setValue(desc_array[VALUE_INDEX]);
607 desc.setWritable(desc_array[WRITABLE_INDEX]);
608 }
609 desc.setEnumerable(desc_array[ENUMERABLE_INDEX]);
610 desc.setConfigurable(desc_array[CONFIGURABLE_INDEX]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000611
612 return desc;
613}
614
615
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000616// For Harmony proxies.
617function GetTrap(handler, name, defaultTrap) {
618 var trap = handler[name];
619 if (IS_UNDEFINED(trap)) {
620 if (IS_UNDEFINED(defaultTrap)) {
621 throw MakeTypeError("handler_trap_missing", [handler, name]);
622 }
623 trap = defaultTrap;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000624 } else if (!IS_SPEC_FUNCTION(trap)) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000625 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
626 }
627 return trap;
628}
629
630
631function CallTrap0(handler, name, defaultTrap) {
632 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
633}
634
635
636function CallTrap1(handler, name, defaultTrap, x) {
637 return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
638}
639
640
641function CallTrap2(handler, name, defaultTrap, x, y) {
642 return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
643}
644
645
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000646// ES5 section 8.12.1.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000647function GetOwnProperty(obj, v) {
648 var p = ToString(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000649 if (%IsJSProxy(obj)) {
650 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000651 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000652 if (IS_UNDEFINED(descriptor)) return descriptor;
653 var desc = ToCompletePropertyDescriptor(descriptor);
654 if (!desc.isConfigurable()) {
655 throw MakeTypeError("proxy_prop_not_configurable",
656 [handler, "getOwnPropertyDescriptor", p, descriptor]);
657 }
658 return desc;
659 }
660
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000661 // GetOwnProperty returns an array indexed by the constants
662 // defined in macros.py.
663 // If p is not a property on obj undefined is returned.
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000664 var props = %GetOwnProperty(ToObject(obj), ToString(v));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000665
666 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000667 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000668
669 return ConvertDescriptorArrayToDescriptor(props);
670}
671
672
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000673// ES5 section 8.12.7.
674function Delete(obj, p, should_throw) {
675 var desc = GetOwnProperty(obj, p);
676 if (IS_UNDEFINED(desc)) return true;
677 if (desc.isConfigurable()) {
678 %DeleteProperty(obj, p, 0);
679 return true;
680 } else if (should_throw) {
681 throw MakeTypeError("define_disallowed", [p]);
682 } else {
683 return;
684 }
685}
686
687
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000688// Harmony proxies.
689function DefineProxyProperty(obj, p, attributes, should_throw) {
690 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000691 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000692 if (!ToBoolean(result)) {
693 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000694 throw MakeTypeError("handler_returned_false",
695 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000696 } else {
697 return false;
698 }
699 }
700 return true;
701}
702
703
lrn@chromium.org25156de2010-04-06 13:10:27 +0000704// ES5 8.12.9.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000705function DefineObjectProperty(obj, p, desc, should_throw) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000706 var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
707 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000708 if (current_or_access === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000709
710 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000711 var extensible = %IsExtensible(ToObject(obj));
712
713 // Error handling according to spec.
714 // Step 3
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000715 if (IS_UNDEFINED(current) && !extensible) {
716 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000717 throw MakeTypeError("define_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000718 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000719 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000720 }
721 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000722
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000723 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000724 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000725 if ((IsGenericDescriptor(desc) ||
726 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
727 (!desc.hasEnumerable() ||
728 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000729 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000730 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000731 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000732 SameValue(desc.isWritable(), current.isWritable())) &&
733 (!desc.hasValue() ||
734 SameValue(desc.getValue(), current.getValue())) &&
735 (!desc.hasGetter() ||
736 SameValue(desc.getGet(), current.getGet())) &&
737 (!desc.hasSetter() ||
738 SameValue(desc.getSet(), current.getSet()))) {
739 return true;
740 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000741 if (!current.isConfigurable()) {
742 // Step 7
743 if (desc.isConfigurable() ||
744 (desc.hasEnumerable() &&
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000745 desc.isEnumerable() != current.isEnumerable())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000746 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000747 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000748 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000749 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000750 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000751 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Step 8
753 if (!IsGenericDescriptor(desc)) {
754 // Step 9a
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000755 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000756 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000757 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000758 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000759 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000760 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000761 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000762 // Step 10a
763 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000764 if (!current.isWritable() && desc.isWritable()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000765 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000766 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000767 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000768 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000769 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000770 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000771 if (!current.isWritable() && desc.hasValue() &&
772 !SameValue(desc.getValue(), current.getValue())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000773 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000774 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000775 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000776 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000777 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000778 }
779 }
780 // Step 11
781 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000782 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000783 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000784 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000785 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000786 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000787 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000789 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000790 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000791 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000792 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000793 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000794 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000795 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000796 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000797 }
798 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000799 }
800
lrn@chromium.org25156de2010-04-06 13:10:27 +0000801 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 // only send to the data descriptor.
803 // Take special care if enumerable and configurable is not defined on
804 // desc (we need to preserve the existing values from current).
805 var flag = NONE;
806 if (desc.hasEnumerable()) {
807 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
808 } else if (!IS_UNDEFINED(current)) {
809 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000810 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000811 flag |= DONT_ENUM;
812 }
813
814 if (desc.hasConfigurable()) {
815 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
816 } else if (!IS_UNDEFINED(current)) {
817 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
818 } else
819 flag |= DONT_DELETE;
820
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000821 if (IsDataDescriptor(desc) ||
822 (IsGenericDescriptor(desc) &&
823 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
824 // There are 3 cases that lead here:
825 // Step 4a - defining a new data property.
826 // Steps 9b & 12 - replacing an existing accessor property with a data
827 // property.
828 // Step 12 - updating an existing data property with a data or generic
829 // descriptor.
830
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000831 if (desc.hasWritable()) {
832 flag |= desc.isWritable() ? 0 : READ_ONLY;
833 } else if (!IS_UNDEFINED(current)) {
834 flag |= current.isWritable() ? 0 : READ_ONLY;
835 } else {
836 flag |= READ_ONLY;
837 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000838
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000839 var value = void 0; // Default value is undefined.
840 if (desc.hasValue()) {
841 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000842 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000843 value = current.getValue();
844 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000846 %DefineOrRedefineDataProperty(obj, p, value, flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000847 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000848 // There are 3 cases that lead here:
849 // Step 4b - defining a new accessor property.
850 // Steps 9c & 12 - replacing an existing data property with an accessor
851 // property.
852 // Step 12 - updating an existing accessor property with an accessor
853 // descriptor.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000854 var getter = desc.hasGetter() ? desc.getGet() : null;
855 var setter = desc.hasSetter() ? desc.getSet() : null;
856 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000857 }
858 return true;
859}
860
861
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000862// ES5 section 15.4.5.1.
863function DefineArrayProperty(obj, p, desc, should_throw) {
864 // Note that the length of an array is not actually stored as part of the
865 // property, hence we use generated code throughout this function instead of
866 // DefineObjectProperty() to modify its value.
867
868 // Step 3 - Special handling for length property.
869 if (p == "length") {
870 var length = obj.length;
871 if (!desc.hasValue()) {
872 return DefineObjectProperty(obj, "length", desc, should_throw);
873 }
874 var new_length = ToUint32(desc.getValue());
875 if (new_length != ToNumber(desc.getValue())) {
876 throw new $RangeError('defineProperty() array length out of range');
877 }
878 var length_desc = GetOwnProperty(obj, "length");
879 if (new_length != length && !length_desc.isWritable()) {
880 if (should_throw) {
881 throw MakeTypeError("redefine_disallowed", [p]);
882 } else {
883 return false;
884 }
885 }
886 var threw = false;
887 while (new_length < length--) {
888 if (!Delete(obj, ToString(length), false)) {
889 new_length = length + 1;
890 threw = true;
891 break;
892 }
893 }
894 // Make sure the below call to DefineObjectProperty() doesn't overwrite
895 // any magic "length" property by removing the value.
896 obj.length = new_length;
897 desc.value_ = void 0;
898 desc.hasValue_ = false;
899 if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) {
900 if (should_throw) {
901 throw MakeTypeError("redefine_disallowed", [p]);
902 } else {
903 return false;
904 }
905 }
906 return true;
907 }
908
909 // Step 4 - Special handling for array index.
910 var index = ToUint32(p);
911 if (index == ToNumber(p) && index != 4294967295) {
912 var length = obj.length;
913 var length_desc = GetOwnProperty(obj, "length");
914 if ((index >= length && !length_desc.isWritable()) ||
915 !DefineObjectProperty(obj, p, desc, true)) {
916 if (should_throw) {
917 throw MakeTypeError("define_disallowed", [p]);
918 } else {
919 return false;
920 }
921 }
922 if (index >= length) {
923 obj.length = index + 1;
924 }
925 return true;
926 }
927
928 // Step 5 - Fallback to default implementation.
929 return DefineObjectProperty(obj, p, desc, should_throw);
930}
931
932
933// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
934function DefineOwnProperty(obj, p, desc, should_throw) {
935 if (%IsJSProxy(obj)) {
936 var attributes = FromGenericPropertyDescriptor(desc);
937 return DefineProxyProperty(obj, p, attributes, should_throw);
938 } else if (IS_ARRAY(obj)) {
939 return DefineArrayProperty(obj, p, desc, should_throw);
940 } else {
941 return DefineObjectProperty(obj, p, desc, should_throw);
942 }
943}
944
945
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000946// ES5 section 15.2.3.2.
947function ObjectGetPrototypeOf(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000948 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000949 throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000950 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000951 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000952}
953
954
lrn@chromium.org25156de2010-04-06 13:10:27 +0000955// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000956function ObjectGetOwnPropertyDescriptor(obj, p) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000957 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000958 throw MakeTypeError("called_on_non_object",
959 ["Object.getOwnPropertyDescriptor"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000960 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000961 var desc = GetOwnProperty(obj, p);
962 return FromPropertyDescriptor(desc);
963}
964
965
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000966// For Harmony proxies
967function ToStringArray(obj, trap) {
968 if (!IS_SPEC_OBJECT(obj)) {
969 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
970 }
971 var n = ToUint32(obj.length);
972 var array = new $Array(n);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000973 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000974 for (var index = 0; index < n; index++) {
975 var s = ToString(obj[index]);
verwaest@chromium.org37141392012-05-31 13:27:02 +0000976 if (%HasLocalProperty(names, s)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000977 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000978 }
979 array[index] = s;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000980 names[s] = 0;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000981 }
982 return array;
983}
984
985
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986// ES5 section 15.2.3.4.
987function ObjectGetOwnPropertyNames(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000988 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000989 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000990 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000991 // Special handling for proxies.
992 if (%IsJSProxy(obj)) {
993 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000994 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000995 return ToStringArray(names, "getOwnPropertyNames");
996 }
997
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000998 // Find all the indexed properties.
999
1000 // Get the local element names.
1001 var propertyNames = %GetLocalElementNames(obj);
1002
1003 // Get names for indexed interceptor properties.
1004 if (%GetInterceptorInfo(obj) & 1) {
1005 var indexedInterceptorNames =
1006 %GetIndexedInterceptorElementNames(obj);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001007 if (indexedInterceptorNames) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001008 propertyNames = propertyNames.concat(indexedInterceptorNames);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001009 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001010 }
1011
1012 // Find all the named properties.
1013
1014 // Get the local property names.
1015 propertyNames = propertyNames.concat(%GetLocalPropertyNames(obj));
1016
1017 // Get names for named interceptor properties if any.
1018
1019 if (%GetInterceptorInfo(obj) & 2) {
1020 var namedInterceptorNames =
1021 %GetNamedInterceptorPropertyNames(obj);
1022 if (namedInterceptorNames) {
1023 propertyNames = propertyNames.concat(namedInterceptorNames);
1024 }
1025 }
1026
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001027 // Property names are expected to be unique strings.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001028 var propertySet = { __proto__: null };
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001029 var j = 0;
1030 for (var i = 0; i < propertyNames.length; ++i) {
1031 var name = ToString(propertyNames[i]);
1032 // We need to check for the exact property value since for intrinsic
1033 // properties like toString if(propertySet["toString"]) will always
1034 // succeed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001035 if (propertySet[name] === true) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001036 continue;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001037 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001038 propertySet[name] = true;
1039 propertyNames[j++] = name;
1040 }
1041 propertyNames.length = j;
ager@chromium.org5c838252010-02-19 08:53:10 +00001042
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001043 return propertyNames;
1044}
1045
1046
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001047// ES5 section 15.2.3.5.
1048function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001049 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001050 throw MakeTypeError("proto_object_or_null", [proto]);
1051 }
1052 var obj = new $Object();
1053 obj.__proto__ = proto;
1054 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1055 return obj;
1056}
1057
1058
ager@chromium.org5c838252010-02-19 08:53:10 +00001059// ES5 section 15.2.3.6.
1060function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001061 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001062 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001063 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001064 var name = ToString(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001065 if (%IsJSProxy(obj)) {
1066 // Clone the attributes object for protection.
1067 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1068 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001069 var attributesClone = { __proto__: null };
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001070 for (var a in attributes) {
1071 attributesClone[a] = attributes[a];
1072 }
1073 DefineProxyProperty(obj, name, attributesClone, true);
1074 // The following would implement the spec as in the current proposal,
1075 // but after recent comments on es-discuss, is most likely obsolete.
1076 /*
1077 var defineObj = FromGenericPropertyDescriptor(desc);
1078 var names = ObjectGetOwnPropertyNames(attributes);
1079 var standardNames =
1080 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1081 for (var i = 0; i < names.length; i++) {
1082 var N = names[i];
1083 if (!(%HasLocalProperty(standardNames, N))) {
1084 var attr = GetOwnProperty(attributes, N);
1085 DefineOwnProperty(descObj, N, attr, true);
1086 }
1087 }
1088 // This is really confusing the types, but it is what the proxies spec
1089 // currently requires:
1090 desc = descObj;
1091 */
1092 } else {
1093 var desc = ToPropertyDescriptor(attributes);
1094 DefineOwnProperty(obj, name, desc, true);
1095 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001096 return obj;
1097}
1098
1099
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001100function GetOwnEnumerablePropertyNames(properties) {
1101 var names = new InternalArray();
1102 for (var key in properties) {
1103 if (%HasLocalProperty(properties, key)) {
1104 names.push(key);
1105 }
1106 }
1107 return names;
1108}
1109
1110
ager@chromium.org5c838252010-02-19 08:53:10 +00001111// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001112function ObjectDefineProperties(obj, properties) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001113 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001114 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001115 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001116 var props = ToObject(properties);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001117 var names = GetOwnEnumerablePropertyNames(props);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001118 var descriptors = new InternalArray();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001119 for (var i = 0; i < names.length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001120 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1121 }
1122 for (var i = 0; i < names.length; i++) {
1123 DefineOwnProperty(obj, names[i], descriptors[i], true);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001124 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001125 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001126}
1127
1128
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001129// Harmony proxies.
1130function ProxyFix(obj) {
1131 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001132 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001133 if (IS_UNDEFINED(props)) {
1134 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1135 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001136
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001137 if (%IsJSFunctionProxy(obj)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001138 var callTrap = %GetCallTrap(obj);
1139 var constructTrap = %GetConstructTrap(obj);
1140 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1141 %Fix(obj); // becomes a regular function
1142 %SetCode(obj, code);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001143 // TODO(rossberg): What about length and other properties? Not specified.
1144 // We just put in some half-reasonable defaults for now.
1145 var prototype = new $Object();
1146 $Object.defineProperty(prototype, "constructor",
danno@chromium.org2c456792011-11-11 12:00:53 +00001147 {value: obj, writable: true, enumerable: false, configurable: true});
1148 // TODO(v8:1530): defineProperty does not handle prototype and length.
1149 %FunctionSetPrototype(obj, prototype);
1150 obj.length = 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001151 } else {
1152 %Fix(obj);
1153 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001154 ObjectDefineProperties(obj, props);
1155}
1156
1157
ager@chromium.orgb5737492010-07-15 09:29:43 +00001158// ES5 section 15.2.3.8.
1159function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001160 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001161 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001162 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001163 if (%IsJSProxy(obj)) {
1164 ProxyFix(obj);
1165 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001166 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001167 for (var i = 0; i < names.length; i++) {
1168 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001169 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001170 if (desc.isConfigurable()) {
1171 desc.setConfigurable(false);
1172 DefineOwnProperty(obj, name, desc, true);
1173 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001174 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001175 %PreventExtensions(obj);
1176 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001177}
1178
1179
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001180// ES5 section 15.2.3.9.
1181function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001182 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001183 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001184 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001185 if (%IsJSProxy(obj)) {
1186 ProxyFix(obj);
1187 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001188 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001189 for (var i = 0; i < names.length; i++) {
1190 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001191 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001192 if (desc.isWritable() || desc.isConfigurable()) {
1193 if (IsDataDescriptor(desc)) desc.setWritable(false);
1194 desc.setConfigurable(false);
1195 DefineOwnProperty(obj, name, desc, true);
1196 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001197 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001198 %PreventExtensions(obj);
1199 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001200}
1201
1202
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001203// ES5 section 15.2.3.10
1204function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001205 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001206 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001207 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001208 if (%IsJSProxy(obj)) {
1209 ProxyFix(obj);
1210 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001211 %PreventExtensions(obj);
1212 return obj;
1213}
1214
1215
ager@chromium.orgb5737492010-07-15 09:29:43 +00001216// ES5 section 15.2.3.11
1217function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001218 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001219 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001220 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001221 if (%IsJSProxy(obj)) {
1222 return false;
1223 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001224 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001225 for (var i = 0; i < names.length; i++) {
1226 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001227 var desc = GetOwnProperty(obj, name);
1228 if (desc.isConfigurable()) return false;
1229 }
1230 if (!ObjectIsExtensible(obj)) {
1231 return true;
1232 }
1233 return false;
1234}
1235
1236
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001237// ES5 section 15.2.3.12
1238function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001239 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001240 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001241 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001242 if (%IsJSProxy(obj)) {
1243 return false;
1244 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001245 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001246 for (var i = 0; i < names.length; i++) {
1247 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001248 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001249 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1250 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001251 }
1252 if (!ObjectIsExtensible(obj)) {
1253 return true;
1254 }
1255 return false;
1256}
1257
1258
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001259// ES5 section 15.2.3.13
1260function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001261 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001262 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001263 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001264 if (%IsJSProxy(obj)) {
1265 return true;
1266 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001267 return %IsExtensible(obj);
1268}
1269
1270
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001271// Harmony egal.
1272function ObjectIs(obj1, obj2) {
1273 if (obj1 === obj2) {
1274 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1275 } else {
1276 return (obj1 !== obj1) && (obj2 !== obj2);
1277 }
1278}
1279
1280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281%SetCode($Object, function(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001282 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 if (x == null) return this;
1284 return ToObject(x);
1285 } else {
1286 if (x == null) return { };
1287 return ToObject(x);
1288 }
1289});
1290
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001291%SetExpectedNumberOfProperties($Object, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292
1293// ----------------------------------------------------------------------------
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001294// Object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001296function SetUpObject() {
1297 %CheckIsBootstrapping();
1298 // Set Up non-enumerable functions on the Object.prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001299 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1300 "toString", ObjectToString,
1301 "toLocaleString", ObjectToLocaleString,
1302 "valueOf", ObjectValueOf,
1303 "hasOwnProperty", ObjectHasOwnProperty,
1304 "isPrototypeOf", ObjectIsPrototypeOf,
1305 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1306 "__defineGetter__", ObjectDefineGetter,
1307 "__lookupGetter__", ObjectLookupGetter,
1308 "__defineSetter__", ObjectDefineSetter,
1309 "__lookupSetter__", ObjectLookupSetter
1310 ));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001311 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001312 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001313 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001314 "defineProperty", ObjectDefineProperty,
1315 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001316 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001317 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001318 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001319 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001320 "is", ObjectIs,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001321 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001322 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001323 "isSealed", ObjectIsSealed,
1324 "preventExtensions", ObjectPreventExtension,
1325 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001326 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001327}
1328
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001329SetUpObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330
1331// ----------------------------------------------------------------------------
1332// Boolean
1333
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001334function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 // NOTE: Both Boolean objects and values can enter here as
1336 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001337 var b = this;
1338 if (!IS_BOOLEAN(b)) {
1339 if (!IS_BOOLEAN_WRAPPER(b)) {
1340 throw new $TypeError('Boolean.prototype.toString is not generic');
1341 }
1342 b = %_ValueOf(b);
1343 }
1344 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001345}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346
1347
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001348function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // NOTE: Both Boolean objects and values can enter here as
1350 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001351 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 throw new $TypeError('Boolean.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001355}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356
1357
1358// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001359
1360
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361function SetUpBoolean () {
1362 %CheckIsBootstrapping();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001363 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1364 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001365 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001366 ));
1367}
1368
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001369SetUpBoolean();
1370
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001371
1372// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373// Number
1374
1375// Set the Number function and constructor.
1376%SetCode($Number, function(x) {
1377 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001378 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 %_SetValueOf(this, value);
1380 } else {
1381 return value;
1382 }
1383});
1384
1385%FunctionSetPrototype($Number, new $Number(0));
1386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001388function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 // NOTE: Both Number objects and values can enter here as
1390 // 'this'. This is not as dictated by ECMA-262.
1391 var number = this;
1392 if (!IS_NUMBER(this)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001393 if (!IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394 throw new $TypeError('Number.prototype.toString is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001395 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 // Get the value of this number in case it's an object.
1397 number = %_ValueOf(this);
1398 }
1399 // Fast case: Convert number in radix 10.
1400 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001401 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403
1404 // Convert the radix to an integer and check the range.
1405 radix = TO_INTEGER(radix);
1406 if (radix < 2 || radix > 36) {
1407 throw new $RangeError('toString() radix argument must be between 2 and 36');
1408 }
1409 // Convert the number to a string in the given radix.
1410 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001411}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412
1413
1414// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001415function NumberToLocaleString() {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001416 return %_CallFunction(this, NumberToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001417}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418
1419
1420// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001421function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 // NOTE: Both Number objects and values can enter here as
1423 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001424 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 throw new $TypeError('Number.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001426 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001428}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429
1430
1431// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001432function NumberToFixed(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001433 var x = this;
1434 if (!IS_NUMBER(this)) {
1435 if (!IS_NUMBER_WRAPPER(this)) {
1436 throw MakeTypeError("incompatible_method_receiver",
1437 ["Number.prototype.toFixed", this]);
1438 }
1439 // Get the value of this number in case it's an object.
1440 x = %_ValueOf(this);
1441 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 var f = TO_INTEGER(fractionDigits);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 if (f < 0 || f > 20) {
1445 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1446 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001447
1448 if (NUMBER_IS_NAN(x)) return "NaN";
1449 if (x == 1/0) return "Infinity";
1450 if (x == -1/0) return "-Infinity";
1451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001453}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454
1455
1456// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001457function NumberToExponential(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001458 var x = this;
1459 if (!IS_NUMBER(this)) {
1460 if (!IS_NUMBER_WRAPPER(this)) {
1461 throw MakeTypeError("incompatible_method_receiver",
1462 ["Number.prototype.toExponential", this]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001464 // Get the value of this number in case it's an object.
1465 x = %_ValueOf(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001467 var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
1468
1469 if (NUMBER_IS_NAN(x)) return "NaN";
1470 if (x == 1/0) return "Infinity";
1471 if (x == -1/0) return "-Infinity";
1472
1473 if (IS_UNDEFINED(f)) {
1474 f = -1; // Signal for runtime function that f is not defined.
1475 } else if (f < 0 || f > 20) {
1476 throw new $RangeError("toExponential() argument must be between 0 and 20");
lrn@chromium.org1c092762011-05-09 09:42:16 +00001477 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001479}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
1481
1482// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001483function NumberToPrecision(precision) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001484 var x = this;
1485 if (!IS_NUMBER(this)) {
1486 if (!IS_NUMBER_WRAPPER(this)) {
1487 throw MakeTypeError("incompatible_method_receiver",
1488 ["Number.prototype.toPrecision", this]);
1489 }
1490 // Get the value of this number in case it's an object.
1491 x = %_ValueOf(this);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001492 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1494 var p = TO_INTEGER(precision);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001495
1496 if (NUMBER_IS_NAN(x)) return "NaN";
1497 if (x == 1/0) return "Infinity";
1498 if (x == -1/0) return "-Infinity";
1499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 if (p < 1 || p > 21) {
1501 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001504}
1505
1506
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001507// Harmony isFinite.
1508function NumberIsFinite(number) {
1509 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1510}
1511
1512
1513// Harmony isNaN.
1514function NumberIsNaN(number) {
1515 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1516}
1517
1518
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001519// ----------------------------------------------------------------------------
1520
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001521function SetUpNumber() {
1522 %CheckIsBootstrapping();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001523 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001524 // Set up the constructor property on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001525 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1526
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001527 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001528 // ECMA-262 section 15.7.3.1.
1529 %SetProperty($Number,
1530 "MAX_VALUE",
1531 1.7976931348623157e+308,
1532 DONT_ENUM | DONT_DELETE | READ_ONLY);
1533
1534 // ECMA-262 section 15.7.3.2.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001535 %SetProperty($Number, "MIN_VALUE", 5e-324,
1536 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001537
1538 // ECMA-262 section 15.7.3.3.
1539 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1540
1541 // ECMA-262 section 15.7.3.4.
1542 %SetProperty($Number,
1543 "NEGATIVE_INFINITY",
1544 -1/0,
1545 DONT_ENUM | DONT_DELETE | READ_ONLY);
1546
1547 // ECMA-262 section 15.7.3.5.
1548 %SetProperty($Number,
1549 "POSITIVE_INFINITY",
1550 1/0,
1551 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001552 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001553
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001554 // Set up non-enumerable functions on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001555 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1556 "toString", NumberToString,
1557 "toLocaleString", NumberToLocaleString,
1558 "valueOf", NumberValueOf,
1559 "toFixed", NumberToFixed,
1560 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001561 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001562 ));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001563 InstallFunctions($Number, DONT_ENUM, $Array(
1564 "isFinite", NumberIsFinite,
1565 "isNaN", NumberIsNaN
1566 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001567}
1568
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001569SetUpNumber();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572// ----------------------------------------------------------------------------
1573// Function
1574
1575$Function.prototype.constructor = $Function;
1576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577function FunctionSourceString(func) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001578 while (%IsJSFunctionProxy(func)) {
1579 func = %GetCallTrap(func);
1580 }
1581
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001582 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585
1586 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001587 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 var name = %FunctionGetName(func);
1589 if (name) {
1590 // Mimic what KJS does.
1591 return 'function ' + name + '() { [native code] }';
1592 } else {
1593 return 'function () { [native code] }';
1594 }
1595 }
1596
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001597 var name = %FunctionNameShouldPrintAsAnonymous(func)
1598 ? 'anonymous'
1599 : %FunctionGetName(func);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001601}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
1603
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001604function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001606}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
1608
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001609// ES5 15.3.4.5
1610function FunctionBind(this_arg) { // Length is 1.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001611 if (!IS_SPEC_FUNCTION(this)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001612 throw new $TypeError('Bind must be called on a function');
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001613 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001614 var boundFunction = function () {
1615 // Poison .arguments and .caller, but is otherwise not detectable.
1616 "use strict";
1617 // This function must not use any object literals (Object, Array, RegExp),
1618 // since the literals-array is being used to store the bound data.
1619 if (%_IsConstructCall()) {
1620 return %NewObjectFromBound(boundFunction);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001621 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001622 var bindings = %BoundFunctionGetBindings(boundFunction);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001623
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001624 var argc = %_ArgumentsLength();
1625 if (argc == 0) {
1626 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1627 }
1628 if (bindings.length === 2) {
1629 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1630 }
1631 var bound_argc = bindings.length - 2;
1632 var argv = new InternalArray(bound_argc + argc);
1633 for (var i = 0; i < bound_argc; i++) {
1634 argv[i] = bindings[i + 2];
1635 }
1636 for (var j = 0; j < argc; j++) {
1637 argv[i++] = %_Arguments(j);
1638 }
1639 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1640 };
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001641
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001642 %FunctionRemovePrototype(boundFunction);
1643 var new_length = 0;
1644 if (%_ClassOf(this) == "Function") {
1645 // Function or FunctionProxy.
1646 var old_length = this.length;
1647 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1648 if ((typeof old_length === "number") &&
1649 ((old_length >>> 0) === old_length)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001650 var argc = %_ArgumentsLength();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001651 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1652 new_length = old_length - argc;
1653 if (new_length < 0) new_length = 0;
1654 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001655 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 // This runtime function finds any remaining arguments on the stack,
1657 // so we don't pass the arguments object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001658 var result = %FunctionBindArguments(boundFunction, this,
1659 this_arg, new_length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001660
1661 // We already have caller and arguments properties on functions,
1662 // which are non-configurable. It therefore makes no sence to
1663 // try to redefine these as defined by the spec. The spec says
1664 // that bind should make these throw a TypeError if get or set
1665 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001666 // To be consistent with our normal functions we leave this as it is.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001667 // TODO(lrn): Do set these to be thrower.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001668 return result;
1669}
1670
1671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672function NewFunction(arg1) { // length == 1
1673 var n = %_ArgumentsLength();
1674 var p = '';
1675 if (n > 1) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001676 p = new InternalArray(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001677 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1678 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 // If the formal parameters string include ) - an illegal
1680 // character - it may make the combined function expression
1681 // compile. We avoid this problem by checking for this early on.
1682 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
1683 }
1684 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001685 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686
1687 // The call to SetNewFunctionAttributes will ensure the prototype
1688 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001689 var global_receiver = %GlobalReceiver(global);
1690 var f = %_CallFunction(global_receiver, %CompileString(source));
1691
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001692 %FunctionMarkNameShouldPrintAsAnonymous(f);
ager@chromium.org236ad962008-09-25 09:45:57 +00001693 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001694}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695
1696%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001697
1698// ----------------------------------------------------------------------------
1699
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001700function SetUpFunction() {
1701 %CheckIsBootstrapping();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001702 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001703 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001704 "toString", FunctionToString
1705 ));
1706}
1707
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001708SetUpFunction();