blob: f5ab122ff0aa8d2a1604f640ca97de7cb2499d1e [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
29// in runtime.js:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000030// var $Object = global.Object;
31// var $Boolean = global.Boolean;
32// var $Number = global.Number;
33// var $Function = global.Function;
34// var $Array = global.Array;
35// var $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000036//
37// in math.js:
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000038// var $floor = MathFloor
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000039
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000040var $isNaN = GlobalIsNaN;
41var $isFinite = GlobalIsFinite;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000042
43// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000045// Helper function used to install functions on objects.
46function InstallFunctions(object, attributes, functions) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000047 if (functions.length >= 8) {
48 %OptimizeObjectForAddingMultipleProperties(object, functions.length >> 1);
49 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000050 for (var i = 0; i < functions.length; i += 2) {
51 var key = functions[i];
52 var f = functions[i + 1];
53 %FunctionSetName(f, key);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000054 %FunctionRemovePrototype(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000055 %SetProperty(object, key, f, attributes);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000056 %SetNativeFlag(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000057 }
ager@chromium.org5c838252010-02-19 08:53:10 +000058 %ToFastProperties(object);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000059}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000061
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000062// Helper function to install a getter-only accessor property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000063function InstallGetter(object, name, getter) {
64 %FunctionSetName(getter, name);
65 %FunctionRemovePrototype(getter);
66 %DefineOrRedefineAccessorProperty(object, name, getter, null, DONT_ENUM);
67 %SetNativeFlag(getter);
68}
69
70
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000071// Helper function to install a getter/setter accessor property.
72function InstallGetterSetter(object, name, getter, setter) {
73 %FunctionSetName(getter, name);
74 %FunctionSetName(setter, name);
75 %FunctionRemovePrototype(getter);
76 %FunctionRemovePrototype(setter);
77 %DefineOrRedefineAccessorProperty(object, name, getter, setter, DONT_ENUM);
78 %SetNativeFlag(getter);
79 %SetNativeFlag(setter);
80}
81
82
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000083// Prevents changes to the prototype of a built-in function.
fschneider@chromium.org1805e212011-09-05 10:49:12 +000084// The "prototype" property of the function object is made non-configurable,
85// and the prototype object is made non-extensible. The latter prevents
86// changing the __proto__ property.
87function SetUpLockedPrototype(constructor, fields, methods) {
88 %CheckIsBootstrapping();
89 var prototype = constructor.prototype;
90 // Install functions first, because this function is used to initialize
91 // PropertyDescriptor itself.
92 var property_count = (methods.length >> 1) + (fields ? fields.length : 0);
93 if (property_count >= 4) {
94 %OptimizeObjectForAddingMultipleProperties(prototype, property_count);
95 }
96 if (fields) {
97 for (var i = 0; i < fields.length; i++) {
98 %SetProperty(prototype, fields[i], void 0, DONT_ENUM | DONT_DELETE);
99 }
100 }
101 for (var i = 0; i < methods.length; i += 2) {
102 var key = methods[i];
103 var f = methods[i + 1];
104 %SetProperty(prototype, key, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
105 %SetNativeFlag(f);
106 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000107 %SetPrototype(prototype, null);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000108 %ToFastProperties(prototype);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000109}
110
111
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000112// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
114
115// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000116function GlobalIsNaN(number) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000117 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
118 return NUMBER_IS_NAN(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000119}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120
121
122// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000123function GlobalIsFinite(number) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000124 if (!IS_NUMBER(number)) number = NonNumberToNumber(number);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000125 return NUMBER_IS_FINITE(number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000126}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127
128
129// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000130function GlobalParseInt(string, radix) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000131 if (IS_UNDEFINED(radix) || radix === 10 || radix === 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 // Some people use parseInt instead of Math.floor. This
133 // optimization makes parseInt on a Smi 12 times faster (60ns
134 // vs 800ns). The following optimization makes parseInt on a
135 // non-Smi number 9 times faster (230ns vs 2070ns). Together
136 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
137 if (%_IsSmi(string)) return string;
ager@chromium.org381abbb2009-02-25 13:23:22 +0000138 if (IS_NUMBER(string) &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000139 ((0.01 < string && string < 1e9) ||
140 (-1e9 < string && string < -0.01))) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000141 // Truncate number.
142 return string | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000144 string = TO_STRING_INLINE(string);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000145 radix = radix | 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000147 // The spec says ToString should be evaluated before ToInt32.
148 string = TO_STRING_INLINE(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 radix = TO_INT32(radix);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000150 if (!(radix == 0 || (2 <= radix && radix <= 36))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 return $NaN;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000154
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000155 if (%_HasCachedArrayIndex(string) &&
156 (radix == 0 || radix == 10)) {
157 return %_GetCachedArrayIndex(string);
158 }
159 return %StringParseInt(string, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000160}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161
162
163// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000164function GlobalParseFloat(string) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000165 string = TO_STRING_INLINE(string);
166 if (%_HasCachedArrayIndex(string)) return %_GetCachedArrayIndex(string);
167 return %StringParseFloat(string);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000168}
169
170
171function GlobalEval(x) {
172 if (!IS_STRING(x)) return x;
173
ager@chromium.orge2902be2009-06-08 12:21:35 +0000174 var global_receiver = %GlobalReceiver(global);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000175 var global_is_detached = (global === global_receiver);
176
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000177 // For consistency with JSC we require the global object passed to
178 // eval to be the global object from which 'eval' originated. This
179 // is not mandated by the spec.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000180 // We only throw if the global has been detached, since we need the
181 // receiver as this-value for the call.
182 if (global_is_detached) {
183 throw new $EvalError('The "this" value passed to eval must ' +
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000184 'be the global object from which eval originated');
185 }
ager@chromium.orge2902be2009-06-08 12:21:35 +0000186
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000187 var f = %CompileString(x, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000188 if (!IS_FUNCTION(f)) return f;
189
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000190 return %_CallFunction(global_receiver, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000191}
192
193
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000194// ----------------------------------------------------------------------------
195
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000196// Set up global object.
197function SetUpGlobal() {
198 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000199
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200 // ECMA 262 - 15.1.1.1.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000201 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000202
203 // ECMA-262 - 15.1.1.2.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000205
206 // ECMA-262 - 15.1.1.3.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000207 %SetProperty(global, "undefined", void 0,
208 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000209
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000210 // Set up non-enumerable function on the global object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000211 InstallFunctions(global, DONT_ENUM, $Array(
212 "isNaN", GlobalIsNaN,
213 "isFinite", GlobalIsFinite,
214 "parseInt", GlobalParseInt,
215 "parseFloat", GlobalParseFloat,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000216 "eval", GlobalEval
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000217 ));
218}
219
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000220SetUpGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222
223// ----------------------------------------------------------------------------
224// Object
225
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000226// ECMA-262 - 15.2.4.2
227function ObjectToString() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000228 if (IS_UNDEFINED(this) && !IS_UNDETECTABLE(this)) return "[object Undefined]";
229 if (IS_NULL(this)) return "[object Null]";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000230 return "[object " + %_ClassOf(ToObject(this)) + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000231}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232
233
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000234// ECMA-262 - 15.2.4.3
235function ObjectToLocaleString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000236 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
237 throw MakeTypeError("called_on_null_or_undefined",
238 ["Object.prototype.toLocaleString"]);
239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000241}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242
243
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000244// ECMA-262 - 15.2.4.4
245function ObjectValueOf() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 return ToObject(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000247}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
249
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000250// ECMA-262 - 15.2.4.5
251function ObjectHasOwnProperty(V) {
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000252 if (%IsJSProxy(this)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000253 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
254 if (IS_SYMBOL(V)) return false;
255
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000256 var handler = %GetHandler(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000257 return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, ToName(V));
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000258 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000259 return %HasLocalProperty(TO_OBJECT_INLINE(this), ToName(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000260}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
262
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000263// ECMA-262 - 15.2.4.6
264function ObjectIsPrototypeOf(V) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000265 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
266 throw MakeTypeError("called_on_null_or_undefined",
267 ["Object.prototype.isPrototypeOf"]);
268 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000269 if (!IS_SPEC_OBJECT(V)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000270 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000271}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272
273
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000274// ECMA-262 - 15.2.4.6
275function ObjectPropertyIsEnumerable(V) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000276 var P = ToName(V);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000277 if (%IsJSProxy(this)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000278 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
279 if (IS_SYMBOL(V)) return false;
280
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000281 var desc = GetOwnProperty(this, P);
282 return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
283 }
284 return %IsPropertyEnumerable(ToObject(this), P);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000285}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286
287
288// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000289function ObjectDefineGetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000290 var receiver = this;
291 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
292 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000294 if (!IS_SPEC_FUNCTION(fun)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000295 throw new $TypeError(
296 'Object.prototype.__defineGetter__: Expecting function');
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000298 var desc = new PropertyDescriptor();
299 desc.setGet(fun);
300 desc.setEnumerable(true);
301 desc.setConfigurable(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000302 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000303}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304
305
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306function ObjectLookupGetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000307 var receiver = this;
308 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
309 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000310 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000311 return %LookupAccessor(ToObject(receiver), ToName(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313
314
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000315function ObjectDefineSetter(name, fun) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000316 var receiver = this;
317 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
318 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000319 }
lrn@chromium.org34e60782011-09-15 07:25:40 +0000320 if (!IS_SPEC_FUNCTION(fun)) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 throw new $TypeError(
322 'Object.prototype.__defineSetter__: Expecting function');
323 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000324 var desc = new PropertyDescriptor();
325 desc.setSet(fun);
326 desc.setEnumerable(true);
327 desc.setConfigurable(true);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000328 DefineOwnProperty(ToObject(receiver), ToName(name), desc, false);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000329}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
331
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000332function ObjectLookupSetter(name) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000333 var receiver = this;
334 if (receiver == null && !IS_UNDETECTABLE(receiver)) {
335 receiver = %GlobalReceiver(global);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000337 return %LookupAccessor(ToObject(receiver), ToName(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000338}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
340
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000341function ObjectKeys(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000342 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000343 throw MakeTypeError("called_on_non_object", ["Object.keys"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000344 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000345 if (%IsJSProxy(obj)) {
346 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000347 var names = CallTrap0(handler, "keys", DerivedKeysTrap);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000348 return ToNameArray(names, "keys", false);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000349 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000350 return %LocalKeys(obj);
351}
352
353
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000354// ES5 8.10.1.
355function IsAccessorDescriptor(desc) {
356 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000357 return desc.hasGetter() || desc.hasSetter();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000358}
359
360
361// ES5 8.10.2.
362function IsDataDescriptor(desc) {
363 if (IS_UNDEFINED(desc)) return false;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000364 return desc.hasValue() || desc.hasWritable();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000365}
366
367
368// ES5 8.10.3.
369function IsGenericDescriptor(desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000370 if (IS_UNDEFINED(desc)) return false;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000371 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
372}
373
374
375function IsInconsistentDescriptor(desc) {
376 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
377}
378
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000379
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000380// ES5 8.10.4
381function FromPropertyDescriptor(desc) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000382 if (IS_UNDEFINED(desc)) return desc;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000383
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000384 if (IsDataDescriptor(desc)) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000385 return { value: desc.getValue(),
386 writable: desc.isWritable(),
387 enumerable: desc.isEnumerable(),
388 configurable: desc.isConfigurable() };
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000389 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000390 // Must be an AccessorDescriptor then. We never return a generic descriptor.
391 return { get: desc.getGet(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000392 set: desc.getSet() === ObjectSetProto ? ObjectPoisonProto
393 : desc.getSet(),
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000394 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) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000647 var p = ToName(v);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000648 if (%IsJSProxy(obj)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000649 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
650 if (IS_SYMBOL(v)) return void 0;
651
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000652 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000653 var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000654 if (IS_UNDEFINED(descriptor)) return descriptor;
655 var desc = ToCompletePropertyDescriptor(descriptor);
656 if (!desc.isConfigurable()) {
657 throw MakeTypeError("proxy_prop_not_configurable",
658 [handler, "getOwnPropertyDescriptor", p, descriptor]);
659 }
660 return desc;
661 }
662
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000663 // GetOwnProperty returns an array indexed by the constants
664 // defined in macros.py.
665 // If p is not a property on obj undefined is returned.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000666 var props = %GetOwnProperty(ToObject(obj), p);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000667
668 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000669 if (props === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000670
671 return ConvertDescriptorArrayToDescriptor(props);
672}
673
674
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000675// ES5 section 8.12.7.
676function Delete(obj, p, should_throw) {
677 var desc = GetOwnProperty(obj, p);
678 if (IS_UNDEFINED(desc)) return true;
679 if (desc.isConfigurable()) {
680 %DeleteProperty(obj, p, 0);
681 return true;
682 } else if (should_throw) {
683 throw MakeTypeError("define_disallowed", [p]);
684 } else {
685 return;
686 }
687}
688
689
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000690// Harmony proxies.
691function DefineProxyProperty(obj, p, attributes, should_throw) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000692 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
693 if (IS_SYMBOL(p)) return false;
694
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000695 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000696 var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000697 if (!ToBoolean(result)) {
698 if (should_throw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699 throw MakeTypeError("handler_returned_false",
700 [handler, "defineProperty"]);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000701 } else {
702 return false;
703 }
704 }
705 return true;
706}
707
708
lrn@chromium.org25156de2010-04-06 13:10:27 +0000709// ES5 8.12.9.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000710function DefineObjectProperty(obj, p, desc, should_throw) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000711 var current_or_access = %GetOwnProperty(ToObject(obj), ToName(p));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000712 // A false value here means that access checks failed.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000713 if (current_or_access === false) return void 0;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000714
715 var current = ConvertDescriptorArrayToDescriptor(current_or_access);
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 var extensible = %IsExtensible(ToObject(obj));
717
718 // Error handling according to spec.
719 // Step 3
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000720 if (IS_UNDEFINED(current) && !extensible) {
721 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000722 throw MakeTypeError("define_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000723 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000724 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000725 }
726 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000727
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000728 if (!IS_UNDEFINED(current)) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000729 // Step 5 and 6
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000730 if ((IsGenericDescriptor(desc) ||
731 IsDataDescriptor(desc) == IsDataDescriptor(current)) &&
732 (!desc.hasEnumerable() ||
733 SameValue(desc.isEnumerable(), current.isEnumerable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000734 (!desc.hasConfigurable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000735 SameValue(desc.isConfigurable(), current.isConfigurable())) &&
vegorov@chromium.org42841962010-10-18 11:18:59 +0000736 (!desc.hasWritable() ||
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000737 SameValue(desc.isWritable(), current.isWritable())) &&
738 (!desc.hasValue() ||
739 SameValue(desc.getValue(), current.getValue())) &&
740 (!desc.hasGetter() ||
741 SameValue(desc.getGet(), current.getGet())) &&
742 (!desc.hasSetter() ||
743 SameValue(desc.getSet(), current.getSet()))) {
744 return true;
745 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000746 if (!current.isConfigurable()) {
747 // Step 7
748 if (desc.isConfigurable() ||
749 (desc.hasEnumerable() &&
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000750 desc.isEnumerable() != current.isEnumerable())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000751 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000752 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000753 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000754 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000755 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000756 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000757 // Step 8
758 if (!IsGenericDescriptor(desc)) {
759 // Step 9a
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000760 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000761 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000762 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000763 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000765 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000766 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000767 // Step 10a
768 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000769 if (!current.isWritable() && desc.isWritable()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000770 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000771 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000772 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000773 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000774 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000775 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000776 if (!current.isWritable() && desc.hasValue() &&
777 !SameValue(desc.getValue(), current.getValue())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000778 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000779 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000780 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000781 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000782 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 }
784 }
785 // Step 11
786 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000787 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000788 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000789 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000790 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000791 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000792 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000793 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000794 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000795 if (should_throw) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000796 throw MakeTypeError("redefine_disallowed", [p]);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000797 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000798 return false;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000799 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000800 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000801 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000802 }
803 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000804 }
805
lrn@chromium.org25156de2010-04-06 13:10:27 +0000806 // Send flags - enumerable and configurable are common - writable is
ager@chromium.org5c838252010-02-19 08:53:10 +0000807 // only send to the data descriptor.
808 // Take special care if enumerable and configurable is not defined on
809 // desc (we need to preserve the existing values from current).
810 var flag = NONE;
811 if (desc.hasEnumerable()) {
812 flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
813 } else if (!IS_UNDEFINED(current)) {
814 flag |= current.isEnumerable() ? 0 : DONT_ENUM;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000815 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +0000816 flag |= DONT_ENUM;
817 }
818
819 if (desc.hasConfigurable()) {
820 flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
821 } else if (!IS_UNDEFINED(current)) {
822 flag |= current.isConfigurable() ? 0 : DONT_DELETE;
823 } else
824 flag |= DONT_DELETE;
825
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000826 if (IsDataDescriptor(desc) ||
827 (IsGenericDescriptor(desc) &&
828 (IS_UNDEFINED(current) || IsDataDescriptor(current)))) {
829 // There are 3 cases that lead here:
830 // Step 4a - defining a new data property.
831 // Steps 9b & 12 - replacing an existing accessor property with a data
832 // property.
833 // Step 12 - updating an existing data property with a data or generic
834 // descriptor.
835
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000836 if (desc.hasWritable()) {
837 flag |= desc.isWritable() ? 0 : READ_ONLY;
838 } else if (!IS_UNDEFINED(current)) {
839 flag |= current.isWritable() ? 0 : READ_ONLY;
840 } else {
841 flag |= READ_ONLY;
842 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000844 var value = void 0; // Default value is undefined.
845 if (desc.hasValue()) {
846 value = desc.getValue();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 } else if (!IS_UNDEFINED(current) && IsDataDescriptor(current)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000848 value = current.getValue();
849 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000850
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000851 %DefineOrRedefineDataProperty(obj, p, value, flag);
ager@chromium.org5c838252010-02-19 08:53:10 +0000852 } else {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000853 // There are 3 cases that lead here:
854 // Step 4b - defining a new accessor property.
855 // Steps 9c & 12 - replacing an existing data property with an accessor
856 // property.
857 // Step 12 - updating an existing accessor property with an accessor
858 // descriptor.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000859 var getter = desc.hasGetter() ? desc.getGet() : null;
860 var setter = desc.hasSetter() ? desc.getSet() : null;
861 %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000862 }
863 return true;
864}
865
866
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000867// ES5 section 15.4.5.1.
868function DefineArrayProperty(obj, p, desc, should_throw) {
869 // Note that the length of an array is not actually stored as part of the
870 // property, hence we use generated code throughout this function instead of
871 // DefineObjectProperty() to modify its value.
872
873 // Step 3 - Special handling for length property.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000874 if (p === "length") {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000875 var length = obj.length;
876 if (!desc.hasValue()) {
877 return DefineObjectProperty(obj, "length", desc, should_throw);
878 }
879 var new_length = ToUint32(desc.getValue());
880 if (new_length != ToNumber(desc.getValue())) {
881 throw new $RangeError('defineProperty() array length out of range');
882 }
883 var length_desc = GetOwnProperty(obj, "length");
884 if (new_length != length && !length_desc.isWritable()) {
885 if (should_throw) {
886 throw MakeTypeError("redefine_disallowed", [p]);
887 } else {
888 return false;
889 }
890 }
891 var threw = false;
892 while (new_length < length--) {
893 if (!Delete(obj, ToString(length), false)) {
894 new_length = length + 1;
895 threw = true;
896 break;
897 }
898 }
899 // Make sure the below call to DefineObjectProperty() doesn't overwrite
900 // any magic "length" property by removing the value.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000901 // TODO(mstarzinger): This hack should be removed once we have addressed the
902 // respective TODO in Runtime_DefineOrRedefineDataProperty.
903 // For the time being, we need a hack to prevent Object.observe from
904 // generating two change records.
905 var isObserved = %IsObserved(obj);
906 if (isObserved) %SetIsObserved(obj, false);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000907 obj.length = new_length;
908 desc.value_ = void 0;
909 desc.hasValue_ = false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000910 threw = !DefineObjectProperty(obj, "length", desc, should_throw) || threw;
911 if (isObserved) %SetIsObserved(obj, true);
912 if (threw) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000913 if (should_throw) {
914 throw MakeTypeError("redefine_disallowed", [p]);
915 } else {
916 return false;
917 }
918 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000919 if (isObserved) {
920 var new_desc = GetOwnProperty(obj, "length");
921 var updated = length_desc.value_ !== new_desc.value_;
922 var reconfigured = length_desc.writable_ !== new_desc.writable_ ||
923 length_desc.configurable_ !== new_desc.configurable_ ||
924 length_desc.enumerable_ !== new_desc.configurable_;
925 if (updated || reconfigured) {
926 NotifyChange(reconfigured ? "reconfigured" : "updated",
927 obj, "length", length_desc.value_);
928 }
929 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000930 return true;
931 }
932
933 // Step 4 - Special handling for array index.
934 var index = ToUint32(p);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000935 if (ToString(index) == p && index != 4294967295) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000936 var length = obj.length;
937 var length_desc = GetOwnProperty(obj, "length");
938 if ((index >= length && !length_desc.isWritable()) ||
939 !DefineObjectProperty(obj, p, desc, true)) {
940 if (should_throw) {
941 throw MakeTypeError("define_disallowed", [p]);
942 } else {
943 return false;
944 }
945 }
946 if (index >= length) {
947 obj.length = index + 1;
948 }
949 return true;
950 }
951
952 // Step 5 - Fallback to default implementation.
953 return DefineObjectProperty(obj, p, desc, should_throw);
954}
955
956
957// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
958function DefineOwnProperty(obj, p, desc, should_throw) {
959 if (%IsJSProxy(obj)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000960 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
961 if (IS_SYMBOL(p)) return false;
962
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000963 var attributes = FromGenericPropertyDescriptor(desc);
964 return DefineProxyProperty(obj, p, attributes, should_throw);
965 } else if (IS_ARRAY(obj)) {
966 return DefineArrayProperty(obj, p, desc, should_throw);
967 } else {
968 return DefineObjectProperty(obj, p, desc, should_throw);
969 }
970}
971
972
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000973// ES5 section 15.2.3.2.
974function ObjectGetPrototypeOf(obj) {
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", ["Object.getPrototypeOf"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000977 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000978 return %GetPrototype(obj);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000979}
980
981
lrn@chromium.org25156de2010-04-06 13:10:27 +0000982// ES5 section 15.2.3.3
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000983function ObjectGetOwnPropertyDescriptor(obj, p) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000984 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000985 throw MakeTypeError("called_on_non_object",
986 ["Object.getOwnPropertyDescriptor"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000987 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000988 var desc = GetOwnProperty(obj, p);
989 return FromPropertyDescriptor(desc);
990}
991
992
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000993// For Harmony proxies
ulan@chromium.org750145a2013-03-07 15:14:13 +0000994function ToNameArray(obj, trap, includeSymbols) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000995 if (!IS_SPEC_OBJECT(obj)) {
996 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
997 }
998 var n = ToUint32(obj.length);
999 var array = new $Array(n);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001000 var realLength = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001001 var names = { __proto__: null }; // TODO(rossberg): use sets once ready.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001002 for (var index = 0; index < n; index++) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001003 var s = ToName(obj[index]);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001004 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001005 if (IS_SYMBOL(s) && !includeSymbols) continue;
verwaest@chromium.org37141392012-05-31 13:27:02 +00001006 if (%HasLocalProperty(names, s)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001007 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001008 }
1009 array[index] = s;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001010 ++realLength;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001011 names[s] = 0;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001012 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001013 array.length = realLength;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001014 return array;
1015}
1016
1017
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001018// ES5 section 15.2.3.4.
1019function ObjectGetOwnPropertyNames(obj) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001020 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001021 throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001022 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001023 // Special handling for proxies.
1024 if (%IsJSProxy(obj)) {
1025 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001026 var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001027 return ToNameArray(names, "getOwnPropertyNames", false);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001028 }
1029
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001030 var nameArrays = new InternalArray();
1031
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032 // Find all the indexed properties.
1033
1034 // Get the local element names.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001035 var localElementNames = %GetLocalElementNames(obj);
1036 for (var i = 0; i < localElementNames.length; ++i) {
1037 localElementNames[i] = %_NumberToString(localElementNames[i]);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001038 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001039 nameArrays.push(localElementNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001040
1041 // Get names for indexed interceptor properties.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001042 var interceptorInfo = %GetInterceptorInfo(obj);
1043 if ((interceptorInfo & 1) != 0) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001044 var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
1045 if (!IS_UNDEFINED(indexedInterceptorNames)) {
1046 nameArrays.push(indexedInterceptorNames);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001047 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001048 }
1049
1050 // Find all the named properties.
1051
1052 // Get the local property names.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001053 nameArrays.push(%GetLocalPropertyNames(obj, false));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001054
1055 // Get names for named interceptor properties if any.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001056 if ((interceptorInfo & 2) != 0) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001057 var namedInterceptorNames = %GetNamedInterceptorPropertyNames(obj);
1058 if (!IS_UNDEFINED(namedInterceptorNames)) {
1059 nameArrays.push(namedInterceptorNames);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001060 }
1061 }
1062
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001063 var propertyNames =
1064 %Apply(InternalArray.prototype.concat,
1065 nameArrays[0], nameArrays, 1, nameArrays.length - 1);
1066
1067 // Property names are expected to be unique strings,
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001068 // but interceptors can interfere with that assumption.
1069 if (interceptorInfo != 0) {
1070 var propertySet = { __proto__: null };
1071 var j = 0;
1072 for (var i = 0; i < propertyNames.length; ++i) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001073 if (IS_SYMBOL(propertyNames[i])) continue;
1074 var name = ToString(propertyNames[i]);
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001075 // We need to check for the exact property value since for intrinsic
1076 // properties like toString if(propertySet["toString"]) will always
1077 // succeed.
1078 if (propertySet[name] === true) {
1079 continue;
1080 }
1081 propertySet[name] = true;
1082 propertyNames[j++] = name;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001083 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001084 propertyNames.length = j;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001085 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001086
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001087 return propertyNames;
1088}
1089
1090
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001091// ES5 section 15.2.3.5.
1092function ObjectCreate(proto, properties) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001093 if (!IS_SPEC_OBJECT(proto) && proto !== null) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001094 throw MakeTypeError("proto_object_or_null", [proto]);
1095 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001096 var obj = { __proto__: proto };
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001097 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties);
1098 return obj;
1099}
1100
1101
ager@chromium.org5c838252010-02-19 08:53:10 +00001102// ES5 section 15.2.3.6.
1103function ObjectDefineProperty(obj, p, attributes) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001104 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001105 throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001106 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001107 var name = ToName(p);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001108 if (%IsJSProxy(obj)) {
1109 // Clone the attributes object for protection.
1110 // TODO(rossberg): not spec'ed yet, so not sure if this should involve
1111 // non-own properties as it does (or non-enumerable ones, as it doesn't?).
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001112 var attributesClone = { __proto__: null };
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001113 for (var a in attributes) {
1114 attributesClone[a] = attributes[a];
1115 }
1116 DefineProxyProperty(obj, name, attributesClone, true);
1117 // The following would implement the spec as in the current proposal,
1118 // but after recent comments on es-discuss, is most likely obsolete.
1119 /*
1120 var defineObj = FromGenericPropertyDescriptor(desc);
1121 var names = ObjectGetOwnPropertyNames(attributes);
1122 var standardNames =
1123 {value: 0, writable: 0, get: 0, set: 0, enumerable: 0, configurable: 0};
1124 for (var i = 0; i < names.length; i++) {
1125 var N = names[i];
1126 if (!(%HasLocalProperty(standardNames, N))) {
1127 var attr = GetOwnProperty(attributes, N);
1128 DefineOwnProperty(descObj, N, attr, true);
1129 }
1130 }
1131 // This is really confusing the types, but it is what the proxies spec
1132 // currently requires:
1133 desc = descObj;
1134 */
1135 } else {
1136 var desc = ToPropertyDescriptor(attributes);
1137 DefineOwnProperty(obj, name, desc, true);
1138 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001139 return obj;
1140}
1141
1142
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001143function GetOwnEnumerablePropertyNames(properties) {
1144 var names = new InternalArray();
1145 for (var key in properties) {
1146 if (%HasLocalProperty(properties, key)) {
1147 names.push(key);
1148 }
1149 }
1150 return names;
1151}
1152
1153
ager@chromium.org5c838252010-02-19 08:53:10 +00001154// ES5 section 15.2.3.7.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001155function ObjectDefineProperties(obj, properties) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001156 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001157 throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001158 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001159 var props = ToObject(properties);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001160 var names = GetOwnEnumerablePropertyNames(props);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001161 var descriptors = new InternalArray();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001162 for (var i = 0; i < names.length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001163 descriptors.push(ToPropertyDescriptor(props[names[i]]));
1164 }
1165 for (var i = 0; i < names.length; i++) {
1166 DefineOwnProperty(obj, names[i], descriptors[i], true);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001167 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001168 return obj;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001169}
1170
1171
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001172// Harmony proxies.
1173function ProxyFix(obj) {
1174 var handler = %GetHandler(obj);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00001175 var props = CallTrap0(handler, "fix", void 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001176 if (IS_UNDEFINED(props)) {
1177 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
1178 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001179
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001180 if (%IsJSFunctionProxy(obj)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001181 var callTrap = %GetCallTrap(obj);
1182 var constructTrap = %GetConstructTrap(obj);
1183 var code = DelegateCallAndConstruct(callTrap, constructTrap);
1184 %Fix(obj); // becomes a regular function
1185 %SetCode(obj, code);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001186 // TODO(rossberg): What about length and other properties? Not specified.
1187 // We just put in some half-reasonable defaults for now.
1188 var prototype = new $Object();
1189 $Object.defineProperty(prototype, "constructor",
danno@chromium.org2c456792011-11-11 12:00:53 +00001190 {value: obj, writable: true, enumerable: false, configurable: true});
1191 // TODO(v8:1530): defineProperty does not handle prototype and length.
1192 %FunctionSetPrototype(obj, prototype);
1193 obj.length = 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001194 } else {
1195 %Fix(obj);
1196 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001197 ObjectDefineProperties(obj, props);
1198}
1199
1200
ager@chromium.orgb5737492010-07-15 09:29:43 +00001201// ES5 section 15.2.3.8.
1202function ObjectSeal(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001203 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001204 throw MakeTypeError("called_on_non_object", ["Object.seal"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001205 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001206 if (%IsJSProxy(obj)) {
1207 ProxyFix(obj);
1208 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001209 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001210 for (var i = 0; i < names.length; i++) {
1211 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001212 var desc = GetOwnProperty(obj, name);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001213 if (desc.isConfigurable()) {
1214 desc.setConfigurable(false);
1215 DefineOwnProperty(obj, name, desc, true);
1216 }
vegorov@chromium.org42841962010-10-18 11:18:59 +00001217 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001218 %PreventExtensions(obj);
1219 return obj;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001220}
1221
1222
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001223// ES5 section 15.2.3.9.
1224function ObjectFreeze(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001225 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001226 throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001227 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001228 var isProxy = %IsJSProxy(obj);
1229 if (isProxy || %HasNonStrictArgumentsElements(obj)) {
1230 if (isProxy) {
1231 ProxyFix(obj);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001232 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001233 var names = ObjectGetOwnPropertyNames(obj);
1234 for (var i = 0; i < names.length; i++) {
1235 var name = names[i];
1236 var desc = GetOwnProperty(obj, name);
1237 if (desc.isWritable() || desc.isConfigurable()) {
1238 if (IsDataDescriptor(desc)) desc.setWritable(false);
1239 desc.setConfigurable(false);
1240 DefineOwnProperty(obj, name, desc, true);
1241 }
1242 }
1243 %PreventExtensions(obj);
1244 } else {
1245 // TODO(adamk): Is it worth going to this fast path if the
1246 // object's properties are already in dictionary mode?
1247 %ObjectFreeze(obj);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001248 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001249 return obj;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001250}
1251
1252
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001253// ES5 section 15.2.3.10
1254function ObjectPreventExtension(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001255 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001256 throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001257 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001258 if (%IsJSProxy(obj)) {
1259 ProxyFix(obj);
1260 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001261 %PreventExtensions(obj);
1262 return obj;
1263}
1264
1265
ager@chromium.orgb5737492010-07-15 09:29:43 +00001266// ES5 section 15.2.3.11
1267function ObjectIsSealed(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001268 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001269 throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001270 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001271 if (%IsJSProxy(obj)) {
1272 return false;
1273 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001274 if (%IsExtensible(obj)) {
1275 return false;
1276 }
ager@chromium.orgb5737492010-07-15 09:29:43 +00001277 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001278 for (var i = 0; i < names.length; i++) {
1279 var name = names[i];
ager@chromium.orgb5737492010-07-15 09:29:43 +00001280 var desc = GetOwnProperty(obj, name);
1281 if (desc.isConfigurable()) return false;
1282 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001283 return true;
ager@chromium.orgb5737492010-07-15 09:29:43 +00001284}
1285
1286
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001287// ES5 section 15.2.3.12
1288function ObjectIsFrozen(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001289 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001290 throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001291 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001292 if (%IsJSProxy(obj)) {
1293 return false;
1294 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001295 if (%IsExtensible(obj)) {
1296 return false;
1297 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001298 var names = ObjectGetOwnPropertyNames(obj);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001299 for (var i = 0; i < names.length; i++) {
1300 var name = names[i];
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001301 var desc = GetOwnProperty(obj, name);
ager@chromium.orgb5737492010-07-15 09:29:43 +00001302 if (IsDataDescriptor(desc) && desc.isWritable()) return false;
1303 if (desc.isConfigurable()) return false;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001304 }
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001305 return true;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001306}
1307
1308
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001309// ES5 section 15.2.3.13
1310function ObjectIsExtensible(obj) {
ricow@chromium.org4980dff2010-07-19 08:33:45 +00001311 if (!IS_SPEC_OBJECT(obj)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001312 throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001313 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001314 if (%IsJSProxy(obj)) {
1315 return true;
1316 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001317 return %IsExtensible(obj);
1318}
1319
1320
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001321// Harmony egal.
1322function ObjectIs(obj1, obj2) {
1323 if (obj1 === obj2) {
1324 return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
1325 } else {
1326 return (obj1 !== obj1) && (obj2 !== obj2);
1327 }
1328}
1329
1330
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001331// Harmony __proto__ getter.
1332function ObjectGetProto() {
1333 return %GetPrototype(this);
1334}
1335
1336
1337// Harmony __proto__ setter.
1338function ObjectSetProto(obj) {
1339 return %SetPrototype(this, obj);
1340}
1341
1342
1343// Harmony __proto__ poison pill.
1344function ObjectPoisonProto(obj) {
1345 throw MakeTypeError("proto_poison_pill", []);
1346}
1347
1348
1349function ObjectConstructor(x) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001350 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 if (x == null) return this;
1352 return ToObject(x);
1353 } else {
1354 if (x == null) return { };
1355 return ToObject(x);
1356 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001357}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
1359
1360// ----------------------------------------------------------------------------
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361// Object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001363function SetUpObject() {
1364 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001365
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001366 %SetNativeFlag($Object);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001367 %SetCode($Object, ObjectConstructor);
1368 %FunctionSetName(ObjectPoisonProto, "__proto__");
1369 %FunctionRemovePrototype(ObjectPoisonProto);
1370 %SetExpectedNumberOfProperties($Object, 4);
1371
1372 %SetProperty($Object.prototype, "constructor", $Object, DONT_ENUM);
1373
1374 // Set up non-enumerable functions on the Object.prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001375 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
1376 "toString", ObjectToString,
1377 "toLocaleString", ObjectToLocaleString,
1378 "valueOf", ObjectValueOf,
1379 "hasOwnProperty", ObjectHasOwnProperty,
1380 "isPrototypeOf", ObjectIsPrototypeOf,
1381 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
1382 "__defineGetter__", ObjectDefineGetter,
1383 "__lookupGetter__", ObjectLookupGetter,
1384 "__defineSetter__", ObjectDefineSetter,
1385 "__lookupSetter__", ObjectLookupSetter
1386 ));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001387 InstallGetterSetter($Object.prototype, "__proto__",
1388 ObjectGetProto, ObjectSetProto);
1389
1390 // Set up non-enumerable functions in the Object object.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001391 InstallFunctions($Object, DONT_ENUM, $Array(
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001392 "keys", ObjectKeys,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001393 "create", ObjectCreate,
ager@chromium.org5c838252010-02-19 08:53:10 +00001394 "defineProperty", ObjectDefineProperty,
1395 "defineProperties", ObjectDefineProperties,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001396 "freeze", ObjectFreeze,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001397 "getPrototypeOf", ObjectGetPrototypeOf,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001398 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001399 "getOwnPropertyNames", ObjectGetOwnPropertyNames,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001400 "is", ObjectIs,
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001401 "isExtensible", ObjectIsExtensible,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001402 "isFrozen", ObjectIsFrozen,
ager@chromium.orgb5737492010-07-15 09:29:43 +00001403 "isSealed", ObjectIsSealed,
1404 "preventExtensions", ObjectPreventExtension,
1405 "seal", ObjectSeal
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001406 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001407}
1408
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001409SetUpObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412// ----------------------------------------------------------------------------
1413// Boolean
1414
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001415function BooleanConstructor(x) {
1416 if (%_IsConstructCall()) {
1417 %_SetValueOf(this, ToBoolean(x));
1418 } else {
1419 return ToBoolean(x);
1420 }
1421}
1422
1423
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001424function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 // NOTE: Both Boolean objects and values can enter here as
1426 // 'this'. This is not as dictated by ECMA-262.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001427 var b = this;
1428 if (!IS_BOOLEAN(b)) {
1429 if (!IS_BOOLEAN_WRAPPER(b)) {
1430 throw new $TypeError('Boolean.prototype.toString is not generic');
1431 }
1432 b = %_ValueOf(b);
1433 }
1434 return b ? 'true' : 'false';
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001435}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436
1437
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001438function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439 // NOTE: Both Boolean objects and values can enter here as
1440 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001441 if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 throw new $TypeError('Boolean.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001445}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446
1447
1448// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001449
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001450function SetUpBoolean () {
1451 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001452
1453 %SetCode($Boolean, BooleanConstructor);
1454 %FunctionSetPrototype($Boolean, new $Boolean(false));
1455 %SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
1456
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001457 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
1458 "toString", BooleanToString,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001459 "valueOf", BooleanValueOf
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001460 ));
1461}
1462
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001463SetUpBoolean();
1464
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001465
1466// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467// Number
1468
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001469function NumberConstructor(x) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001471 if (%_IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 %_SetValueOf(this, value);
1473 } else {
1474 return value;
1475 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001476}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001480function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // NOTE: Both Number objects and values can enter here as
1482 // 'this'. This is not as dictated by ECMA-262.
1483 var number = this;
1484 if (!IS_NUMBER(this)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001485 if (!IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 throw new $TypeError('Number.prototype.toString is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001487 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 // Get the value of this number in case it's an object.
1489 number = %_ValueOf(this);
1490 }
1491 // Fast case: Convert number in radix 10.
1492 if (IS_UNDEFINED(radix) || radix === 10) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001493 return %_NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 }
1495
1496 // Convert the radix to an integer and check the range.
1497 radix = TO_INTEGER(radix);
1498 if (radix < 2 || radix > 36) {
1499 throw new $RangeError('toString() radix argument must be between 2 and 36');
1500 }
1501 // Convert the number to a string in the given radix.
1502 return %NumberToRadixString(number, radix);
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.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001507function NumberToLocaleString() {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001508 return %_CallFunction(this, NumberToString);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001509}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
1511
1512// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001513function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // NOTE: Both Number objects and values can enter here as
1515 // 'this'. This is not as dictated by ECMA-262.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001516 if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 throw new $TypeError('Number.prototype.valueOf is not generic');
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001518 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001520}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521
1522
1523// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001524function NumberToFixed(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001525 var x = this;
1526 if (!IS_NUMBER(this)) {
1527 if (!IS_NUMBER_WRAPPER(this)) {
1528 throw MakeTypeError("incompatible_method_receiver",
1529 ["Number.prototype.toFixed", this]);
1530 }
1531 // Get the value of this number in case it's an object.
1532 x = %_ValueOf(this);
1533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 var f = TO_INTEGER(fractionDigits);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 if (f < 0 || f > 20) {
1537 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
1538 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001539
1540 if (NUMBER_IS_NAN(x)) return "NaN";
1541 if (x == 1/0) return "Infinity";
1542 if (x == -1/0) return "-Infinity";
1543
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001545}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546
1547
1548// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001549function NumberToExponential(fractionDigits) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001550 var x = this;
1551 if (!IS_NUMBER(this)) {
1552 if (!IS_NUMBER_WRAPPER(this)) {
1553 throw MakeTypeError("incompatible_method_receiver",
1554 ["Number.prototype.toExponential", this]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001556 // Get the value of this number in case it's an object.
1557 x = %_ValueOf(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001559 var f = IS_UNDEFINED(fractionDigits) ? void 0 : TO_INTEGER(fractionDigits);
1560
1561 if (NUMBER_IS_NAN(x)) return "NaN";
1562 if (x == 1/0) return "Infinity";
1563 if (x == -1/0) return "-Infinity";
1564
1565 if (IS_UNDEFINED(f)) {
1566 f = -1; // Signal for runtime function that f is not defined.
1567 } else if (f < 0 || f > 20) {
1568 throw new $RangeError("toExponential() argument must be between 0 and 20");
lrn@chromium.org1c092762011-05-09 09:42:16 +00001569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001571}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572
1573
1574// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001575function NumberToPrecision(precision) {
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001576 var x = this;
1577 if (!IS_NUMBER(this)) {
1578 if (!IS_NUMBER_WRAPPER(this)) {
1579 throw MakeTypeError("incompatible_method_receiver",
1580 ["Number.prototype.toPrecision", this]);
1581 }
1582 // Get the value of this number in case it's an object.
1583 x = %_ValueOf(this);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
1586 var p = TO_INTEGER(precision);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001587
1588 if (NUMBER_IS_NAN(x)) return "NaN";
1589 if (x == 1/0) return "Infinity";
1590 if (x == -1/0) return "-Infinity";
1591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 if (p < 1 || p > 21) {
1593 throw new $RangeError("toPrecision() argument must be between 1 and 21");
1594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001596}
1597
1598
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001599// Harmony isFinite.
1600function NumberIsFinite(number) {
1601 return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
1602}
1603
1604
1605// Harmony isNaN.
1606function NumberIsNaN(number) {
1607 return IS_NUMBER(number) && NUMBER_IS_NAN(number);
1608}
1609
1610
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001611// ----------------------------------------------------------------------------
1612
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001613function SetUpNumber() {
1614 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001615
1616 %SetCode($Number, NumberConstructor);
1617 %FunctionSetPrototype($Number, new $Number(0));
1618
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001619 %OptimizeObjectForAddingMultipleProperties($Number.prototype, 8);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001620 // Set up the constructor property on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001621 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
1622
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001623 %OptimizeObjectForAddingMultipleProperties($Number, 5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001624 // ECMA-262 section 15.7.3.1.
1625 %SetProperty($Number,
1626 "MAX_VALUE",
1627 1.7976931348623157e+308,
1628 DONT_ENUM | DONT_DELETE | READ_ONLY);
1629
1630 // ECMA-262 section 15.7.3.2.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001631 %SetProperty($Number, "MIN_VALUE", 5e-324,
1632 DONT_ENUM | DONT_DELETE | READ_ONLY);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001633
1634 // ECMA-262 section 15.7.3.3.
1635 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
1636
1637 // ECMA-262 section 15.7.3.4.
1638 %SetProperty($Number,
1639 "NEGATIVE_INFINITY",
1640 -1/0,
1641 DONT_ENUM | DONT_DELETE | READ_ONLY);
1642
1643 // ECMA-262 section 15.7.3.5.
1644 %SetProperty($Number,
1645 "POSITIVE_INFINITY",
1646 1/0,
1647 DONT_ENUM | DONT_DELETE | READ_ONLY);
ager@chromium.org5c838252010-02-19 08:53:10 +00001648 %ToFastProperties($Number);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001649
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001650 // Set up non-enumerable functions on the Number prototype object.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001651 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
1652 "toString", NumberToString,
1653 "toLocaleString", NumberToLocaleString,
1654 "valueOf", NumberValueOf,
1655 "toFixed", NumberToFixed,
1656 "toExponential", NumberToExponential,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001657 "toPrecision", NumberToPrecision
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001658 ));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001659 InstallFunctions($Number, DONT_ENUM, $Array(
1660 "isFinite", NumberIsFinite,
1661 "isNaN", NumberIsNaN
1662 ));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001663}
1664
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001665SetUpNumber();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001668// ----------------------------------------------------------------------------
1669// Function
1670
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671function FunctionSourceString(func) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001672 while (%IsJSFunctionProxy(func)) {
1673 func = %GetCallTrap(func);
1674 }
1675
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001676 if (!IS_FUNCTION(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 throw new $TypeError('Function.prototype.toString is not generic');
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001678 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679
1680 var source = %FunctionGetSourceCode(func);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001681 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 var name = %FunctionGetName(func);
1683 if (name) {
1684 // Mimic what KJS does.
1685 return 'function ' + name + '() { [native code] }';
1686 } else {
1687 return 'function () { [native code] }';
1688 }
1689 }
1690
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001691 var name = %FunctionNameShouldPrintAsAnonymous(func)
1692 ? 'anonymous'
1693 : %FunctionGetName(func);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001694 var head = %FunctionIsGenerator(func) ? 'function* ' : 'function ';
1695 return head + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001696}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697
1698
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001699function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001701}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702
1703
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001704// ES5 15.3.4.5
1705function FunctionBind(this_arg) { // Length is 1.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001706 if (!IS_SPEC_FUNCTION(this)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001707 throw new $TypeError('Bind must be called on a function');
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001708 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001709 var boundFunction = function () {
1710 // Poison .arguments and .caller, but is otherwise not detectable.
1711 "use strict";
1712 // This function must not use any object literals (Object, Array, RegExp),
1713 // since the literals-array is being used to store the bound data.
1714 if (%_IsConstructCall()) {
1715 return %NewObjectFromBound(boundFunction);
vegorov@chromium.org42841962010-10-18 11:18:59 +00001716 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001717 var bindings = %BoundFunctionGetBindings(boundFunction);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001718
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001719 var argc = %_ArgumentsLength();
1720 if (argc == 0) {
1721 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
1722 }
1723 if (bindings.length === 2) {
1724 return %Apply(bindings[0], bindings[1], arguments, 0, argc);
1725 }
1726 var bound_argc = bindings.length - 2;
1727 var argv = new InternalArray(bound_argc + argc);
1728 for (var i = 0; i < bound_argc; i++) {
1729 argv[i] = bindings[i + 2];
1730 }
1731 for (var j = 0; j < argc; j++) {
1732 argv[i++] = %_Arguments(j);
1733 }
1734 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc);
1735 };
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001736
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001737 %FunctionRemovePrototype(boundFunction);
1738 var new_length = 0;
1739 if (%_ClassOf(this) == "Function") {
1740 // Function or FunctionProxy.
1741 var old_length = this.length;
1742 // FunctionProxies might provide a non-UInt32 value. If so, ignore it.
1743 if ((typeof old_length === "number") &&
1744 ((old_length >>> 0) === old_length)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001745 var argc = %_ArgumentsLength();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001746 if (argc > 0) argc--; // Don't count the thisArg as parameter.
1747 new_length = old_length - argc;
1748 if (new_length < 0) new_length = 0;
1749 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001750 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001751 // This runtime function finds any remaining arguments on the stack,
1752 // so we don't pass the arguments object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001753 var result = %FunctionBindArguments(boundFunction, this,
1754 this_arg, new_length);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001755
1756 // We already have caller and arguments properties on functions,
1757 // which are non-configurable. It therefore makes no sence to
1758 // try to redefine these as defined by the spec. The spec says
1759 // that bind should make these throw a TypeError if get or set
1760 // is called and make them non-enumerable and non-configurable.
vegorov@chromium.org42841962010-10-18 11:18:59 +00001761 // To be consistent with our normal functions we leave this as it is.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001762 // TODO(lrn): Do set these to be thrower.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001763 return result;
1764}
1765
1766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767function NewFunction(arg1) { // length == 1
1768 var n = %_ArgumentsLength();
1769 var p = '';
1770 if (n > 1) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001771 p = new InternalArray(n - 1);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001772 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i);
1773 p = Join(p, n - 1, ',', NonStringToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 // If the formal parameters string include ) - an illegal
1775 // character - it may make the combined function expression
1776 // compile. We avoid this problem by checking for this early on.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001777 if (%_CallFunction(p, ')', StringIndexOf) != -1) {
1778 throw MakeSyntaxError('paren_in_arg_string',[]);
1779 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001780 // If the formal parameters include an unbalanced block comment, the
1781 // function must be rejected. Since JavaScript does not allow nested
1782 // comments we can include a trailing block comment to catch this.
1783 p += '\n/' + '**/';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 }
1785 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +00001786 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001788 var global_receiver = %GlobalReceiver(global);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001789 var f = %_CallFunction(global_receiver, %CompileString(source, true));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001790
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001791 %FunctionMarkNameShouldPrintAsAnonymous(f);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001792 return f;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001793}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001795
1796// ----------------------------------------------------------------------------
1797
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001798function SetUpFunction() {
1799 %CheckIsBootstrapping();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001800
1801 %SetCode($Function, NewFunction);
1802 %SetProperty($Function.prototype, "constructor", $Function, DONT_ENUM);
1803
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001804 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001805 "bind", FunctionBind,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001806 "toString", FunctionToString
1807 ));
1808}
1809
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001810SetUpFunction();