blob: cbf1705429fdcae252645f0d3d416f0dbfd6388d [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +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
28#include <stdlib.h>
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000029#include <limits>
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030
31#include "v8.h"
32
33#include "accessors.h"
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000034#include "allocation-site-scopes.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "api.h"
36#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000037#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000038#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000039#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "compiler.h"
41#include "cpu.h"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000042#include "cpu-profiler.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000043#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000046#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "execution.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000048#include "full-codegen.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000050#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "jsregexp.h"
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000052#include "jsregexp-inl.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000053#include "json-parser.h"
danno@chromium.org72204d52012-10-31 10:02:10 +000054#include "json-stringifier.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000055#include "liveedit.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000056#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000059#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061#include "scopeinfo.h"
yangguo@chromium.org304cc332012-07-24 07:59:48 +000062#include "smart-pointers.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000063#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000064#include "stub-cache.h"
ulan@chromium.org2e04b582013-02-21 14:06:02 +000065#include "uri.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000066#include "v8conversions.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000067#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000068#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
danno@chromium.org59400602013-08-13 17:09:37 +000070#ifdef V8_I18N_SUPPORT
71#include "i18n.h"
72#include "unicode/brkiter.h"
73#include "unicode/calendar.h"
74#include "unicode/coll.h"
75#include "unicode/curramt.h"
76#include "unicode/datefmt.h"
77#include "unicode/dcfmtsym.h"
78#include "unicode/decimfmt.h"
79#include "unicode/dtfmtsym.h"
80#include "unicode/dtptngen.h"
81#include "unicode/locid.h"
82#include "unicode/numfmt.h"
83#include "unicode/numsys.h"
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000084#include "unicode/rbbi.h"
danno@chromium.org59400602013-08-13 17:09:37 +000085#include "unicode/smpdtfmt.h"
86#include "unicode/timezone.h"
87#include "unicode/uchar.h"
88#include "unicode/ucol.h"
89#include "unicode/ucurr.h"
90#include "unicode/uloc.h"
91#include "unicode/unum.h"
92#include "unicode/uversion.h"
93#endif
94
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000095#ifndef _STLP_VENDOR_CSTD
96// STLPort doesn't import fpclassify and isless into the std namespace.
97using std::fpclassify;
98using std::isless;
99#endif
100
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000101namespace v8 {
102namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
ager@chromium.org3e875802009-06-29 08:26:34 +0000105#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
108// Cast the given object to a value of the specified type and store
109// it in a variable with the given name. If the object is not of the
110// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111#define CONVERT_ARG_CHECKED(Type, name, index) \
112 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000113 Type* name = Type::cast(args[index]);
114
115#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
116 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117 Handle<Type> name = args.at<Type>(index);
118
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000119// Cast the given object to a boolean and store it in a variable with
120// the given name. If the object is not a boolean call IllegalOperation
121// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000122#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
123 RUNTIME_ASSERT(args[index]->IsBoolean()); \
124 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000125
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000126// Cast the given argument to a Smi and store its value in an int variable
127// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000128// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000129#define CONVERT_SMI_ARG_CHECKED(name, index) \
130 RUNTIME_ASSERT(args[index]->IsSmi()); \
131 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000133// Cast the given argument to a double and store it in a variable with
134// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000136#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
137 RUNTIME_ASSERT(args[index]->IsNumber()); \
138 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139
140// Call the specified converter on the object *comand store the result in
141// a variable of the specified type with the given name. If the
142// object is not a Number call IllegalOperation and return.
143#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
144 RUNTIME_ASSERT(obj->IsNumber()); \
145 type name = NumberTo##Type(obj);
146
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000148// Cast the given argument to PropertyDetails and store its value in a
149// variable with the given name. If the argument is not a Smi call
150// IllegalOperation and return.
151#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
152 RUNTIME_ASSERT(args[index]->IsSmi()); \
153 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
154
155
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000156// Assert that the given argument has a valid value for a StrictModeFlag
157// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000158#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
159 RUNTIME_ASSERT(args[index]->IsSmi()); \
160 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
161 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000162 StrictModeFlag name = \
163 static_cast<StrictModeFlag>(args.smi_at(index));
164
165
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000166// Assert that the given argument has a valid value for a LanguageMode
167// and store it in a LanguageMode variable with the given name.
168#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
169 ASSERT(args[index]->IsSmi()); \
170 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
171 args.smi_at(index) == STRICT_MODE || \
172 args.smi_at(index) == EXTENDED_MODE); \
173 LanguageMode name = \
174 static_cast<LanguageMode>(args.smi_at(index));
175
176
ager@chromium.org236ad962008-09-25 09:45:57 +0000177static Handle<Map> ComputeObjectLiteralMap(
178 Handle<Context> context,
179 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000180 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000182 int properties_length = constant_properties->length();
183 int number_of_properties = properties_length / 2;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000184 // Check that there are only internal strings and array indices among keys.
185 int number_of_string_keys = 0;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000186 for (int p = 0; p != properties_length; p += 2) {
187 Object* key = constant_properties->get(p);
188 uint32_t element_index = 0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000189 if (key->IsInternalizedString()) {
190 number_of_string_keys++;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000191 } else if (key->ToArrayIndex(&element_index)) {
192 // An index key does not require space in the property backing store.
193 number_of_properties--;
194 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000195 // Bail out as a non-internalized-string non-index key makes caching
196 // impossible.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000197 // ASSERT to make sure that the if condition after the loop is false.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000198 ASSERT(number_of_string_keys != number_of_properties);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000199 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000200 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000201 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000202 // If we only have internalized strings and array indices among keys then we
203 // can use the map cache in the native context.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000204 const int kMaxKeys = 10;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000205 if ((number_of_string_keys == number_of_properties) &&
206 (number_of_string_keys < kMaxKeys)) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000207 // Create the fixed array with the key.
208 Handle<FixedArray> keys =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000209 isolate->factory()->NewFixedArray(number_of_string_keys);
210 if (number_of_string_keys > 0) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000211 int index = 0;
212 for (int p = 0; p < properties_length; p += 2) {
213 Object* key = constant_properties->get(p);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000214 if (key->IsInternalizedString()) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000215 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000216 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000217 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000218 ASSERT(index == number_of_string_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000219 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000220 *is_result_from_cache = true;
221 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000222 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000223 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000224 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000225 Handle<Map>(context->object_function()->initial_map()),
226 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000227}
228
229
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232 Handle<FixedArray> literals,
233 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000234
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235
236static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000239 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000240 bool should_have_fast_elements,
241 bool has_function_literal) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000242 // Get the native context from the literals array. This is the
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000243 // context in which the function was created and we use the object
244 // function from this context to create the object literal. We do
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000245 // not use the object function from the current native context
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000246 // because this might be the object function from another context
247 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 Handle<Context> context =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000249 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
ager@chromium.org236ad962008-09-25 09:45:57 +0000250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 // In case we have function literals, we want the object to be in
252 // slow properties mode for now. We don't go in the map cache because
253 // maps with constant functions can't be shared if the functions are
254 // not the same (which is the common case).
255 bool is_result_from_cache = false;
256 Handle<Map> map = has_function_literal
257 ? Handle<Map>(context->object_function()->initial_map())
258 : ComputeObjectLiteralMap(context,
259 constant_properties,
260 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000262 Handle<JSObject> boilerplate =
263 isolate->factory()->NewJSObjectFromMap(
264 map, isolate->heap()->GetPretenureMode());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000265
266 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000267 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 // Add the constant properties to the boilerplate.
270 int length = constant_properties->length();
271 bool should_transform =
272 !is_result_from_cache && boilerplate->HasFastProperties();
273 if (should_transform || has_function_literal) {
274 // Normalize the properties of object to avoid n^2 behavior
275 // when extending the object multiple properties. Indicate the number of
276 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000277 JSObject::NormalizeProperties(
278 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 }
280
danno@chromium.orgf005df62013-04-30 16:36:45 +0000281 // TODO(verwaest): Support tracking representations in the boilerplate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 for (int index = 0; index < length; index +=2) {
283 Handle<Object> key(constant_properties->get(index+0), isolate);
284 Handle<Object> value(constant_properties->get(index+1), isolate);
285 if (value->IsFixedArray()) {
286 // The value contains the constant_properties of a
287 // simple object or array literal.
288 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
289 value = CreateLiteralBoilerplate(isolate, literals, array);
290 if (value.is_null()) return value;
291 }
292 Handle<Object> result;
293 uint32_t element_index = 0;
rossberg@chromium.org92597162013-08-23 13:28:00 +0000294 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000295 if (key->IsInternalizedString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
297 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000298 result = JSObject::SetOwnElement(
299 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<String> name(String::cast(*key));
302 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000303 result = JSObject::SetLocalPropertyIgnoreAttributes(
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000304 boilerplate, name, value, NONE,
305 Object::OPTIMAL_REPRESENTATION, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000307 } else if (key->ToArrayIndex(&element_index)) {
308 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000309 result = JSObject::SetOwnElement(
310 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000311 } else {
312 // Non-uint32 number.
313 ASSERT(key->IsNumber());
314 double num = key->Number();
315 char arr[100];
316 Vector<char> buffer(arr, ARRAY_SIZE(arr));
317 const char* str = DoubleToCString(num, buffer);
318 Handle<String> name =
319 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000320 result = JSObject::SetLocalPropertyIgnoreAttributes(
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000321 boilerplate, name, value, NONE,
322 Object::OPTIMAL_REPRESENTATION, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 // If setting the property on the boilerplate throws an
325 // exception, the exception is converted to an empty handle in
326 // the handle based operations. In that case, we need to
327 // convert back to an exception.
328 if (result.is_null()) return result;
329 }
330
331 // Transform to fast properties if necessary. For object literals with
332 // containing function literals we defer this operation until after all
333 // computed properties have been assigned so that we can generate
334 // constant function properties.
335 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000336 JSObject::TransformToFastProperties(
337 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 }
339
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000340 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000341}
342
343
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000344MaybeObject* TransitionElements(Handle<Object> object,
345 ElementsKind to_kind,
346 Isolate* isolate) {
347 HandleScope scope(isolate);
348 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
349 ElementsKind from_kind =
350 Handle<JSObject>::cast(object)->map()->elements_kind();
351 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000352 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
353 return *object;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000354 }
355 return isolate->ThrowIllegalOperation();
356}
357
358
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000359static const int kSmiLiteralMinimumLength = 1024;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000360
361
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000362Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 Handle<FixedArray> literals,
365 Handle<FixedArray> elements) {
366 // Create the JSArray.
367 Handle<JSFunction> constructor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000368 JSFunction::NativeContextFromLiterals(*literals)->array_function());
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000369
370 Handle<JSArray> object = Handle<JSArray>::cast(
371 isolate->factory()->NewJSObject(
372 constructor, isolate->heap()->GetPretenureMode()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000373
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000374 ElementsKind constant_elements_kind =
375 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
376 Handle<FixedArrayBase> constant_elements_values(
377 FixedArrayBase::cast(elements->get(1)));
378
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000379 ASSERT(IsFastElementsKind(constant_elements_kind));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000380 Context* native_context = isolate->context()->native_context();
381 Object* maybe_maps_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000382 ASSERT(!maybe_maps_array->IsUndefined());
383 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
384 constant_elements_kind);
385 ASSERT(maybe_map->IsMap());
386 object->set_map(Map::cast(maybe_map));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000387
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000388 Handle<FixedArrayBase> copied_elements_values;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000389 if (IsFastDoubleElementsKind(constant_elements_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000390 ASSERT(FLAG_smi_only_arrays);
391 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
392 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000393 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000394 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000395 const bool is_cow =
396 (constant_elements_values->map() ==
397 isolate->heap()->fixed_cow_array_map());
398 if (is_cow) {
399 copied_elements_values = constant_elements_values;
400#if DEBUG
401 Handle<FixedArray> fixed_array_values =
402 Handle<FixedArray>::cast(copied_elements_values);
403 for (int i = 0; i < fixed_array_values->length(); i++) {
404 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
405 }
406#endif
407 } else {
408 Handle<FixedArray> fixed_array_values =
409 Handle<FixedArray>::cast(constant_elements_values);
410 Handle<FixedArray> fixed_array_values_copy =
411 isolate->factory()->CopyFixedArray(fixed_array_values);
412 copied_elements_values = fixed_array_values_copy;
413 for (int i = 0; i < fixed_array_values->length(); i++) {
414 Object* current = fixed_array_values->get(i);
415 if (current->IsFixedArray()) {
416 // The value contains the constant_properties of a
417 // simple object or array literal.
418 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
419 Handle<Object> result =
420 CreateLiteralBoilerplate(isolate, literals, fa);
421 if (result.is_null()) return result;
422 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000423 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000424 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000425 }
426 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000427 object->set_elements(*copied_elements_values);
428 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000429
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000430 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000431 // on or the object is larger than the threshold.
432 if (!FLAG_smi_only_arrays &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000433 constant_elements_values->length() < kSmiLiteralMinimumLength) {
434 ElementsKind elements_kind = object->GetElementsKind();
435 if (!IsFastObjectElementsKind(elements_kind)) {
436 if (IsFastHoleyElementsKind(elements_kind)) {
437 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
438 isolate)->IsFailure());
439 } else {
440 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
441 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000442 }
443 }
444
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000445 object->ValidateElements();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000446 return object;
447}
448
449
450static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 Handle<FixedArray> literals,
453 Handle<FixedArray> array) {
454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000455 const bool kHasNoFunctionLiteral = false;
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000456 switch (CompileTimeValue::GetLiteralType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 return CreateObjectLiteralBoilerplate(isolate,
459 literals,
460 elements,
461 true,
462 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 return CreateObjectLiteralBoilerplate(isolate,
465 literals,
466 elements,
467 false,
468 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000470 return Runtime::CreateArrayLiteralBoilerplate(
471 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000472 default:
473 UNREACHABLE();
474 return Handle<Object>::null();
475 }
476}
477
478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000479RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000481 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000482 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000483 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000484 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000485 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
487 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488
489 // Check if boilerplate exists. If not, create it first.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000490 Handle<Object> literal_site(literals->get(literals_index), isolate);
491 Handle<AllocationSite> site;
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000492 Handle<JSObject> boilerplate;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000493 if (*literal_site == isolate->heap()->undefined_value()) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000494 Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate(
495 isolate,
496 literals,
497 constant_properties,
498 should_have_fast_elements,
499 has_function_literal);
500 RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate);
501 boilerplate = Handle<JSObject>::cast(raw_boilerplate);
502
503 AllocationSiteCreationContext creation_context(isolate);
504 site = creation_context.EnterNewScope();
505 RETURN_IF_EMPTY_HANDLE(isolate,
506 JSObject::DeepWalk(boilerplate, &creation_context));
507 creation_context.ExitScope(site, boilerplate);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000508
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000509 // Update the functions literal and return the boilerplate.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000510 literals->set(literals_index, *site);
511 } else {
512 site = Handle<AllocationSite>::cast(literal_site);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000513 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
514 isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000517 AllocationSiteUsageContext usage_context(isolate, site, true);
518 usage_context.EnterNewScope();
519 Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context);
520 usage_context.ExitScope(site, boilerplate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000521 RETURN_IF_EMPTY_HANDLE(isolate, copy);
522 return *copy;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000523}
524
525
danno@chromium.orgbee51992013-07-10 14:57:15 +0000526static Handle<AllocationSite> GetLiteralAllocationSite(
527 Isolate* isolate,
528 Handle<FixedArray> literals,
529 int literals_index,
530 Handle<FixedArray> elements) {
531 // Check if boilerplate exists. If not, create it first.
532 Handle<Object> literal_site(literals->get(literals_index), isolate);
533 Handle<AllocationSite> site;
534 if (*literal_site == isolate->heap()->undefined_value()) {
535 ASSERT(*elements != isolate->heap()->empty_fixed_array());
536 Handle<Object> boilerplate =
537 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000538 if (boilerplate.is_null()) return Handle<AllocationSite>::null();
539
540 AllocationSiteCreationContext creation_context(isolate);
541 site = creation_context.EnterNewScope();
542 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
543 &creation_context).is_null()) {
544 return Handle<AllocationSite>::null();
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000545 }
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000546 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
547
danno@chromium.orgbee51992013-07-10 14:57:15 +0000548 literals->set(literals_index, *site);
549 } else {
550 site = Handle<AllocationSite>::cast(literal_site);
551 }
552
553 return site;
554}
555
556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000557RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000560 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000561 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000562 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563
danno@chromium.orgbee51992013-07-10 14:57:15 +0000564 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
565 literals_index, elements);
566 RETURN_IF_EMPTY_HANDLE(isolate, site);
567
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000568 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000569 AllocationSiteUsageContext usage_context(isolate, site, true);
570 usage_context.EnterNewScope();
571 Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context);
572 usage_context.ExitScope(site, boilerplate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000573 RETURN_IF_EMPTY_HANDLE(isolate, copy);
574 return *copy;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575}
576
577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000578RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000581 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000582 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000583 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584
danno@chromium.orgbee51992013-07-10 14:57:15 +0000585 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
586 literals_index, elements);
587 RETURN_IF_EMPTY_HANDLE(isolate, site);
588
589 JSObject* boilerplate = JSObject::cast(site->transition_info());
590 if (boilerplate->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000592 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000593 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000594
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +0000595 if (AllocationSite::GetMode(boilerplate->GetElementsKind()) ==
596 TRACK_ALLOCATION_SITE) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000597 return isolate->heap()->CopyJSObject(boilerplate, *site);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000598 }
599
danno@chromium.orgbee51992013-07-10 14:57:15 +0000600 return isolate->heap()->CopyJSObject(boilerplate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000601}
602
603
604RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000605 HandleScope scope(isolate);
606 ASSERT(args.length() == 1);
607 Handle<Object> name(args[0], isolate);
608 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
609 Symbol* symbol;
610 MaybeObject* maybe = isolate->heap()->AllocateSymbol();
611 if (!maybe->To(&symbol)) return maybe;
612 if (name->IsString()) symbol->set_name(*name);
613 return symbol;
614}
615
616
617RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000618 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000619 ASSERT(args.length() == 1);
620 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
621 return symbol->name();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622}
623
624
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000625RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000626 SealHandleScope shs(isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000627 ASSERT(args.length() == 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000628 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000629 Object* prototype = args[1];
630 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000631 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000632 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
633}
634
635
lrn@chromium.org34e60782011-09-15 07:25:40 +0000636RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000637 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000638 ASSERT(args.length() == 4);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000639 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000640 Object* call_trap = args[1];
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000641 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
642 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000643 Object* prototype = args[3];
644 Object* used_prototype =
645 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
646 return isolate->heap()->AllocateJSFunctionProxy(
647 handler, call_trap, construct_trap, used_prototype);
648}
649
650
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000652 SealHandleScope shs(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000653 ASSERT(args.length() == 1);
654 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000655 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000656}
657
658
lrn@chromium.org34e60782011-09-15 07:25:40 +0000659RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000660 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000661 ASSERT(args.length() == 1);
662 Object* obj = args[0];
663 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
664}
665
666
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000667RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000668 SealHandleScope shs(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000670 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000671 return proxy->handler();
672}
673
674
lrn@chromium.org34e60782011-09-15 07:25:40 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000676 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000677 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000678 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000679 return proxy->call_trap();
680}
681
682
683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000684 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000685 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000686 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000687 return proxy->construct_trap();
688}
689
690
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000691RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000692 HandleScope scope(isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000693 ASSERT(args.length() == 1);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000694 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
695 JSProxy::Fix(proxy);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000696 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000697}
698
699
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000700void Runtime::FreeArrayBuffer(Isolate* isolate,
701 JSArrayBuffer* phantom_array_buffer) {
702 if (phantom_array_buffer->is_external()) return;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000703
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000704 size_t allocated_length = NumberToSize(
705 isolate, phantom_array_buffer->byte_length());
706
707 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
708 -static_cast<intptr_t>(allocated_length));
709 CHECK(V8::ArrayBufferAllocator() != NULL);
danno@chromium.org307dd6e2013-08-06 07:31:48 +0000710 V8::ArrayBufferAllocator()->Free(
711 phantom_array_buffer->backing_store(),
712 allocated_length);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000713}
714
715
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000716void Runtime::SetupArrayBuffer(Isolate* isolate,
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000717 Handle<JSArrayBuffer> array_buffer,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000718 bool is_external,
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000719 void* data,
720 size_t allocated_length) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000721 ASSERT(array_buffer->GetInternalFieldCount() ==
722 v8::ArrayBuffer::kInternalFieldCount);
723 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
724 array_buffer->SetInternalField(i, Smi::FromInt(0));
725 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000726 array_buffer->set_backing_store(data);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000727 array_buffer->set_flag(Smi::FromInt(0));
728 array_buffer->set_is_external(is_external);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000729
730 Handle<Object> byte_length =
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000731 isolate->factory()->NewNumberFromSize(allocated_length);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000732 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
733 array_buffer->set_byte_length(*byte_length);
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000734
735 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
736 isolate->heap()->set_array_buffers_list(*array_buffer);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000737 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000738}
739
740
741bool Runtime::SetupArrayBufferAllocatingData(
742 Isolate* isolate,
743 Handle<JSArrayBuffer> array_buffer,
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000744 size_t allocated_length,
745 bool initialize) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000746 void* data;
ulan@chromium.org837a67e2013-06-11 15:39:48 +0000747 CHECK(V8::ArrayBufferAllocator() != NULL);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000748 if (allocated_length != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000749 if (initialize) {
750 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
751 } else {
752 data =
753 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
754 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000755 if (data == NULL) return false;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000756 } else {
757 data = NULL;
758 }
759
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000760 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000761
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000762 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
763
764 return true;
765}
766
767
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000768RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
769 HandleScope scope(isolate);
770 ASSERT(args.length() == 2);
771 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
772 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
773 size_t allocated_length;
774 if (byteLength->IsSmi()) {
775 allocated_length = Smi::cast(*byteLength)->value();
776 } else {
777 ASSERT(byteLength->IsHeapNumber());
778 double value = HeapNumber::cast(*byteLength)->value();
779
780 ASSERT(value >= 0);
781
782 if (value > std::numeric_limits<size_t>::max()) {
783 return isolate->Throw(
784 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
785 HandleVector<Object>(NULL, 0)));
786 }
787
788 allocated_length = static_cast<size_t>(value);
789 }
790
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000791 if (!Runtime::SetupArrayBufferAllocatingData(isolate,
792 holder, allocated_length)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000793 return isolate->Throw(*isolate->factory()->
794 NewRangeError("invalid_array_buffer_length",
795 HandleVector<Object>(NULL, 0)));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000796 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000797
798 return *holder;
799}
800
801
802RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000803 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000804 ASSERT(args.length() == 1);
805 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
806 return holder->byte_length();
807}
808
809
810RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
811 HandleScope scope(isolate);
812 ASSERT(args.length() == 3);
813 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
814 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
815 CONVERT_DOUBLE_ARG_CHECKED(first, 2);
816 size_t start = static_cast<size_t>(first);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000817 size_t target_length = NumberToSize(isolate, target->byte_length());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000818
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000819 if (target_length == 0) return isolate->heap()->undefined_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000820
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000821 ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000822 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
823 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
824 CopyBytes(target_data, source_data + start, target_length);
825 return isolate->heap()->undefined_value();
826}
827
828
mvstanton@chromium.org63ea3d22013-10-10 09:24:12 +0000829RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) {
830 HandleScope scope(isolate);
831 ASSERT(args.length() == 1);
832 CONVERT_ARG_CHECKED(Object, object, 0);
833 return object->IsJSArrayBufferView()
834 ? isolate->heap()->true_value()
835 : isolate->heap()->false_value();
836}
837
838
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000839enum TypedArrayId {
840 // arrayIds below should be synchromized with typedarray.js natives.
841 ARRAY_ID_UINT8 = 1,
842 ARRAY_ID_INT8 = 2,
843 ARRAY_ID_UINT16 = 3,
844 ARRAY_ID_INT16 = 4,
845 ARRAY_ID_UINT32 = 5,
846 ARRAY_ID_INT32 = 6,
847 ARRAY_ID_FLOAT32 = 7,
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000848 ARRAY_ID_FLOAT64 = 8,
849 ARRAY_ID_UINT8C = 9
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000850};
851
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000852static void ArrayIdToTypeAndSize(
853 int arrayId, ExternalArrayType* array_type, size_t* element_size) {
854 switch (arrayId) {
855 case ARRAY_ID_UINT8:
856 *array_type = kExternalUnsignedByteArray;
857 *element_size = 1;
858 break;
859 case ARRAY_ID_INT8:
860 *array_type = kExternalByteArray;
861 *element_size = 1;
862 break;
863 case ARRAY_ID_UINT16:
864 *array_type = kExternalUnsignedShortArray;
865 *element_size = 2;
866 break;
867 case ARRAY_ID_INT16:
868 *array_type = kExternalShortArray;
869 *element_size = 2;
870 break;
871 case ARRAY_ID_UINT32:
872 *array_type = kExternalUnsignedIntArray;
873 *element_size = 4;
874 break;
875 case ARRAY_ID_INT32:
876 *array_type = kExternalIntArray;
877 *element_size = 4;
878 break;
879 case ARRAY_ID_FLOAT32:
880 *array_type = kExternalFloatArray;
881 *element_size = 4;
882 break;
883 case ARRAY_ID_FLOAT64:
884 *array_type = kExternalDoubleArray;
885 *element_size = 8;
886 break;
887 case ARRAY_ID_UINT8C:
888 *array_type = kExternalPixelArray;
889 *element_size = 1;
890 break;
891 default:
892 UNREACHABLE();
893 }
894}
895
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000896
897RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
898 HandleScope scope(isolate);
899 ASSERT(args.length() == 5);
900 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
901 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
902 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
903 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
904 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
905
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000906 ASSERT(holder->GetInternalFieldCount() ==
907 v8::ArrayBufferView::kInternalFieldCount);
908 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
909 holder->SetInternalField(i, Smi::FromInt(0));
910 }
911
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000912 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
913 size_t element_size = 1; // Bogus initialization.
914 ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000915
916 holder->set_buffer(*buffer);
917 holder->set_byte_offset(*byte_offset_object);
918 holder->set_byte_length(*byte_length_object);
919
920 size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
921 size_t byte_length = NumberToSize(isolate, *byte_length_object);
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000922 ASSERT(byte_length % element_size == 0);
923 size_t length = byte_length / element_size;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000924
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000925 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000926 holder->set_length(*length_obj);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000927 holder->set_weak_next(buffer->weak_first_view());
928 buffer->set_weak_first_view(*holder);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000929
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000930 Handle<ExternalArray> elements =
931 isolate->factory()->NewExternalArray(
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000932 static_cast<int>(length), array_type,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000933 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000934 holder->set_elements(*elements);
935 return isolate->heap()->undefined_value();
936}
937
938
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000939// Initializes a typed array from an array-like object.
940// If an array-like object happens to be a typed array of the same type,
941// initializes backing store using memove.
942//
943// Returns true if backing store was initialized or false otherwise.
944RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
945 HandleScope scope(isolate);
946 ASSERT(args.length() == 4);
947 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
948 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
949 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
950 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
951
952 ASSERT(holder->GetInternalFieldCount() ==
953 v8::ArrayBufferView::kInternalFieldCount);
954 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
955 holder->SetInternalField(i, Smi::FromInt(0));
956 }
957
958 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
959 size_t element_size = 1; // Bogus initialization.
960 ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
961
962 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
963 size_t length = NumberToSize(isolate, *length_obj);
964 size_t byte_length = length * element_size;
965 if (byte_length < length) { // Overflow
966 return isolate->Throw(*isolate->factory()->
967 NewRangeError("invalid_array_buffer_length",
968 HandleVector<Object>(NULL, 0)));
969 }
970
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000971 // NOTE: not initializing backing store.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000972 // We assume that the caller of this function will initialize holder
973 // with the loop
974 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000975 // We assume that the caller of this function is always a typed array
976 // constructor.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000977 // If source is a typed array, this loop will always run to completion,
978 // so we are sure that the backing store will be initialized.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000979 // Otherwise, the indexing operation might throw, so the loop will not
980 // run to completion and the typed array might remain partly initialized.
981 // However we further assume that the caller of this function is a typed array
982 // constructor, and the exception will propagate out of the constructor,
983 // therefore uninitialized memory will not be accessible by a user program.
984 //
985 // TODO(dslomov): revise this once we support subclassing.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000986
987 if (!Runtime::SetupArrayBufferAllocatingData(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000988 isolate, buffer, byte_length, false)) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000989 return isolate->Throw(*isolate->factory()->
990 NewRangeError("invalid_array_buffer_length",
991 HandleVector<Object>(NULL, 0)));
992 }
993
994 holder->set_buffer(*buffer);
995 holder->set_byte_offset(Smi::FromInt(0));
996 Handle<Object> byte_length_obj(
997 isolate->factory()->NewNumberFromSize(byte_length));
998 holder->set_byte_length(*byte_length_obj);
999 holder->set_length(*length_obj);
1000 holder->set_weak_next(buffer->weak_first_view());
1001 buffer->set_weak_first_view(*holder);
1002
1003 Handle<ExternalArray> elements =
1004 isolate->factory()->NewExternalArray(
1005 static_cast<int>(length), array_type,
1006 static_cast<uint8_t*>(buffer->backing_store()));
1007 holder->set_elements(*elements);
1008
1009 if (source->IsJSTypedArray()) {
1010 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1011
1012 if (typed_array->type() == holder->type()) {
1013 uint8_t* backing_store =
1014 static_cast<uint8_t*>(
1015 JSArrayBuffer::cast(typed_array->buffer())->backing_store());
1016 size_t source_byte_offset =
1017 NumberToSize(isolate, typed_array->byte_offset());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001018 memcpy(
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001019 buffer->backing_store(),
1020 backing_store + source_byte_offset,
1021 byte_length);
1022 return *isolate->factory()->true_value();
1023 } else {
1024 return *isolate->factory()->false_value();
1025 }
1026 }
1027
1028 return *isolate->factory()->false_value();
1029}
1030
1031
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001032#define TYPED_ARRAY_GETTER(getter, accessor) \
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001033 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
1034 HandleScope scope(isolate); \
1035 ASSERT(args.length() == 1); \
1036 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
1037 if (!holder->IsJSTypedArray()) \
1038 return isolate->Throw(*isolate->factory()->NewTypeError( \
1039 "not_typed_array", HandleVector<Object>(NULL, 0))); \
1040 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
1041 return typed_array->accessor(); \
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001042 }
1043
1044TYPED_ARRAY_GETTER(Buffer, buffer)
1045TYPED_ARRAY_GETTER(ByteLength, byte_length)
1046TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
1047TYPED_ARRAY_GETTER(Length, length)
1048
1049#undef TYPED_ARRAY_GETTER
1050
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001051// Return codes for Runtime_TypedArraySetFastCases.
1052// Should be synchronized with typedarray.js natives.
1053enum TypedArraySetResultCodes {
1054 // Set from typed array of the same type.
1055 // This is processed by TypedArraySetFastCases
1056 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1057 // Set from typed array of the different type, overlapping in memory.
1058 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1059 // Set from typed array of the different type, non-overlapping.
1060 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1061 // Set from non-typed array.
1062 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1063};
1064
1065
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
1067 HandleScope scope(isolate);
1068 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
1069 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1);
1070 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2);
1071
1072 if (!target_obj->IsJSTypedArray())
1073 return isolate->Throw(*isolate->factory()->NewTypeError(
1074 "not_typed_array", HandleVector<Object>(NULL, 0)));
1075
1076 if (!source_obj->IsJSTypedArray())
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001077 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001078
1079 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1080 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1081 size_t offset = NumberToSize(isolate, *offset_obj);
1082 size_t target_length = NumberToSize(isolate, target->length());
1083 size_t source_length = NumberToSize(isolate, source->length());
1084 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1085 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1086 if (offset > target_length ||
1087 offset + source_length > target_length ||
1088 offset + source_length < offset) // overflow
1089 return isolate->Throw(*isolate->factory()->NewRangeError(
1090 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
1091
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001092 size_t target_offset = NumberToSize(isolate, target->byte_offset());
1093 size_t source_offset = NumberToSize(isolate, source->byte_offset());
1094 uint8_t* target_base =
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001095 static_cast<uint8_t*>(
1096 JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001097 uint8_t* source_base =
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001098 static_cast<uint8_t*>(
1099 JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001100
1101 // Typed arrays of the same type: use memmove.
1102 if (target->type() == source->type()) {
1103 memmove(target_base + offset * target->element_size(),
1104 source_base, source_byte_length);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001105 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001106 }
1107
1108 // Typed arrays of different types over the same backing store
1109 if ((source_base <= target_base &&
1110 source_base + source_byte_length > target_base) ||
1111 (target_base <= source_base &&
1112 target_base + target_byte_length > source_base)) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001113 // We do not support overlapping ArrayBuffers
1114 ASSERT(
1115 JSArrayBuffer::cast(target->buffer())->backing_store() ==
1116 JSArrayBuffer::cast(source->buffer())->backing_store());
1117 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001118 } else { // Non-overlapping typed arrays
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001119 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001120 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001121}
1122
1123
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001124RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
1125 HandleScope scope(isolate);
1126 ASSERT(args.length() == 4);
1127 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1128 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1129 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
1130 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
1131
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001132 ASSERT(holder->GetInternalFieldCount() ==
1133 v8::ArrayBufferView::kInternalFieldCount);
1134 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1135 holder->SetInternalField(i, Smi::FromInt(0));
1136 }
1137
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001138 holder->set_buffer(*buffer);
1139 ASSERT(byte_offset->IsNumber());
1140 ASSERT(
1141 NumberToSize(isolate, buffer->byte_length()) >=
1142 NumberToSize(isolate, *byte_offset)
1143 + NumberToSize(isolate, *byte_length));
1144 holder->set_byte_offset(*byte_offset);
1145 ASSERT(byte_length->IsNumber());
1146 holder->set_byte_length(*byte_length);
1147
1148 holder->set_weak_next(buffer->weak_first_view());
1149 buffer->set_weak_first_view(*holder);
1150
1151 return isolate->heap()->undefined_value();
1152}
1153
1154
1155RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
1156 HandleScope scope(isolate);
1157 ASSERT(args.length() == 1);
1158 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1159 return data_view->buffer();
1160}
1161
1162
1163RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
1164 HandleScope scope(isolate);
1165 ASSERT(args.length() == 1);
1166 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1167 return data_view->byte_offset();
1168}
1169
1170
1171RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
1172 HandleScope scope(isolate);
1173 ASSERT(args.length() == 1);
1174 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1175 return data_view->byte_length();
1176}
1177
1178
1179inline static bool NeedToFlipBytes(bool is_little_endian) {
1180#ifdef V8_TARGET_LITTLE_ENDIAN
1181 return !is_little_endian;
1182#else
1183 return is_little_endian;
1184#endif
1185}
1186
1187
1188template<int n>
1189inline void CopyBytes(uint8_t* target, uint8_t* source) {
1190 for (int i = 0; i < n; i++) {
1191 *(target++) = *(source++);
1192 }
1193}
1194
1195
1196template<int n>
1197inline void FlipBytes(uint8_t* target, uint8_t* source) {
1198 source = source + (n-1);
1199 for (int i = 0; i < n; i++) {
1200 *(target++) = *(source--);
1201 }
1202}
1203
1204
1205template<typename T>
1206inline static bool DataViewGetValue(
1207 Isolate* isolate,
1208 Handle<JSDataView> data_view,
1209 Handle<Object> byte_offset_obj,
1210 bool is_little_endian,
1211 T* result) {
1212 size_t byte_offset = NumberToSize(isolate, *byte_offset_obj);
1213 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1214
1215 size_t data_view_byte_offset =
1216 NumberToSize(isolate, data_view->byte_offset());
1217 size_t data_view_byte_length =
1218 NumberToSize(isolate, data_view->byte_length());
1219 if (byte_offset + sizeof(T) > data_view_byte_length ||
1220 byte_offset + sizeof(T) < byte_offset) { // overflow
1221 return false;
1222 }
1223
1224 union Value {
1225 T data;
1226 uint8_t bytes[sizeof(T)];
1227 };
1228
1229 Value value;
1230 size_t buffer_offset = data_view_byte_offset + byte_offset;
1231 ASSERT(
1232 NumberToSize(isolate, buffer->byte_length())
1233 >= buffer_offset + sizeof(T));
1234 uint8_t* source =
1235 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1236 if (NeedToFlipBytes(is_little_endian)) {
1237 FlipBytes<sizeof(T)>(value.bytes, source);
1238 } else {
1239 CopyBytes<sizeof(T)>(value.bytes, source);
1240 }
1241 *result = value.data;
1242 return true;
1243}
1244
1245
1246template<typename T>
1247static bool DataViewSetValue(
1248 Isolate* isolate,
1249 Handle<JSDataView> data_view,
1250 Handle<Object> byte_offset_obj,
1251 bool is_little_endian,
1252 T data) {
1253 size_t byte_offset = NumberToSize(isolate, *byte_offset_obj);
1254 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1255
1256 size_t data_view_byte_offset =
1257 NumberToSize(isolate, data_view->byte_offset());
1258 size_t data_view_byte_length =
1259 NumberToSize(isolate, data_view->byte_length());
1260 if (byte_offset + sizeof(T) > data_view_byte_length ||
1261 byte_offset + sizeof(T) < byte_offset) { // overflow
1262 return false;
1263 }
1264
1265 union Value {
1266 T data;
1267 uint8_t bytes[sizeof(T)];
1268 };
1269
1270 Value value;
1271 value.data = data;
1272 size_t buffer_offset = data_view_byte_offset + byte_offset;
1273 ASSERT(
1274 NumberToSize(isolate, buffer->byte_length())
1275 >= buffer_offset + sizeof(T));
1276 uint8_t* target =
1277 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1278 if (NeedToFlipBytes(is_little_endian)) {
1279 FlipBytes<sizeof(T)>(target, value.bytes);
1280 } else {
1281 CopyBytes<sizeof(T)>(target, value.bytes);
1282 }
1283 return true;
1284}
1285
1286
1287#define DATA_VIEW_GETTER(TypeName, Type, Converter) \
1288 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \
1289 HandleScope scope(isolate); \
1290 ASSERT(args.length() == 3); \
1291 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1292 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1293 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
1294 Type result; \
1295 if (DataViewGetValue( \
1296 isolate, holder, offset, is_little_endian, &result)) { \
1297 return isolate->heap()->Converter(result); \
1298 } else { \
1299 return isolate->Throw(*isolate->factory()->NewRangeError( \
1300 "invalid_data_view_accessor_offset", \
1301 HandleVector<Object>(NULL, 0))); \
1302 } \
1303 }
1304
1305DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32)
1306DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32)
1307DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32)
1308DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32)
1309DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32)
1310DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32)
1311DATA_VIEW_GETTER(Float32, float, NumberFromDouble)
1312DATA_VIEW_GETTER(Float64, double, NumberFromDouble)
1313
1314#undef DATA_VIEW_GETTER
1315
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001316
1317template <typename T>
1318static T DataViewConvertValue(double value);
1319
1320
1321template <>
1322int8_t DataViewConvertValue<int8_t>(double value) {
1323 return static_cast<int8_t>(DoubleToInt32(value));
1324}
1325
1326
1327template <>
1328int16_t DataViewConvertValue<int16_t>(double value) {
1329 return static_cast<int16_t>(DoubleToInt32(value));
1330}
1331
1332
1333template <>
1334int32_t DataViewConvertValue<int32_t>(double value) {
1335 return DoubleToInt32(value);
1336}
1337
1338
1339template <>
1340uint8_t DataViewConvertValue<uint8_t>(double value) {
1341 return static_cast<uint8_t>(DoubleToUint32(value));
1342}
1343
1344
1345template <>
1346uint16_t DataViewConvertValue<uint16_t>(double value) {
1347 return static_cast<uint16_t>(DoubleToUint32(value));
1348}
1349
1350
1351template <>
1352uint32_t DataViewConvertValue<uint32_t>(double value) {
1353 return DoubleToUint32(value);
1354}
1355
1356
1357template <>
1358float DataViewConvertValue<float>(double value) {
1359 return static_cast<float>(value);
1360}
1361
1362
1363template <>
1364double DataViewConvertValue<double>(double value) {
1365 return value;
1366}
1367
1368
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001369#define DATA_VIEW_SETTER(TypeName, Type) \
1370 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \
1371 HandleScope scope(isolate); \
1372 ASSERT(args.length() == 4); \
1373 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1374 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1375 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
1376 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001377 Type v = DataViewConvertValue<Type>(value->Number()); \
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001378 if (DataViewSetValue( \
1379 isolate, holder, offset, is_little_endian, v)) { \
1380 return isolate->heap()->undefined_value(); \
1381 } else { \
1382 return isolate->Throw(*isolate->factory()->NewRangeError( \
1383 "invalid_data_view_accessor_offset", \
1384 HandleVector<Object>(NULL, 0))); \
1385 } \
1386 }
1387
1388DATA_VIEW_SETTER(Uint8, uint8_t)
1389DATA_VIEW_SETTER(Int8, int8_t)
1390DATA_VIEW_SETTER(Uint16, uint16_t)
1391DATA_VIEW_SETTER(Int16, int16_t)
1392DATA_VIEW_SETTER(Uint32, uint32_t)
1393DATA_VIEW_SETTER(Int32, int32_t)
1394DATA_VIEW_SETTER(Float32, float)
1395DATA_VIEW_SETTER(Float64, double)
1396
1397#undef DATA_VIEW_SETTER
1398
1399
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001400RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
1401 HandleScope scope(isolate);
1402 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001403 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001404 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
1405 holder->set_table(*table);
1406 return *holder;
1407}
1408
1409
1410RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
1411 HandleScope scope(isolate);
1412 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001413 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001414 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001415 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1416 table = ObjectHashSetAdd(table, key);
1417 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001418 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001419}
1420
1421
1422RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
1423 HandleScope scope(isolate);
1424 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001425 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001426 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001427 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1428 return isolate->heap()->ToBoolean(table->Contains(*key));
1429}
1430
1431
1432RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
1433 HandleScope scope(isolate);
1434 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001435 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001436 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001437 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1438 table = ObjectHashSetRemove(table, key);
1439 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001440 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001441}
1442
1443
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001444RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
1445 HandleScope scope(isolate);
1446 ASSERT(args.length() == 1);
1447 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1448 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1449 return Smi::FromInt(table->NumberOfElements());
1450}
1451
1452
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001453RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
1454 HandleScope scope(isolate);
1455 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001456 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001457 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1458 holder->set_table(*table);
1459 return *holder;
1460}
1461
1462
1463RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
1464 HandleScope scope(isolate);
1465 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001466 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001467 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1468 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001469 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001470 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1471}
1472
1473
1474RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) {
1475 HandleScope scope(isolate);
1476 ASSERT(args.length() == 2);
1477 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1478 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1479 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001480 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001481 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1482}
1483
1484
1485RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) {
1486 HandleScope scope(isolate);
1487 ASSERT(args.length() == 2);
1488 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1489 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1490 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001491 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001492 Handle<ObjectHashTable> new_table =
1493 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value());
1494 holder->set_table(*new_table);
1495 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001496}
1497
1498
1499RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
1500 HandleScope scope(isolate);
1501 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001502 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001503 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1504 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001505 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1506 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
1507 holder->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001508 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509}
1510
1511
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001512RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
1513 HandleScope scope(isolate);
1514 ASSERT(args.length() == 1);
1515 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1516 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1517 return Smi::FromInt(table->NumberOfElements());
1518}
1519
1520
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001521static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate,
1522 Handle<JSWeakCollection> weak_collection) {
1523 ASSERT(weak_collection->map()->inobject_properties() == 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001524 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001525 weak_collection->set_table(*table);
1526 weak_collection->set_next(Smi::FromInt(0));
1527 return *weak_collection;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001528}
1529
1530
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001531RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001532 HandleScope scope(isolate);
1533 ASSERT(args.length() == 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001534 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1535 return WeakCollectionInitialize(isolate, weak_collection);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001536}
1537
1538
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001539RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001540 HandleScope scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001541 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001542 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001543 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001544 Handle<ObjectHashTable> table(
1545 ObjectHashTable::cast(weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001546 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001547 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1548}
1549
1550
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001551RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001552 HandleScope scope(isolate);
1553 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001554 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001555 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001556 Handle<ObjectHashTable> table(
1557 ObjectHashTable::cast(weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001558 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001559 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1560}
1561
1562
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001563RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001564 HandleScope scope(isolate);
1565 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001566 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001567 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001568 Handle<ObjectHashTable> table(ObjectHashTable::cast(
1569 weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001570 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001571 Handle<ObjectHashTable> new_table =
1572 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001573 weak_collection->set_table(*new_table);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001574 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001575}
1576
1577
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001578RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001579 HandleScope scope(isolate);
1580 ASSERT(args.length() == 3);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001581 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001582 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001583 Handle<Object> value(args[2], isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001584 Handle<ObjectHashTable> table(
1585 ObjectHashTable::cast(weak_collection->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001586 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001587 weak_collection->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001588 return isolate->heap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001589}
1590
1591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001592RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001593 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 ASSERT(args.length() == 1);
1595 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001596 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 return JSObject::cast(obj)->class_name();
1598}
1599
ager@chromium.org7c537e22008-10-16 08:43:32 +00001600
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001602 HandleScope scope(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001603 ASSERT(args.length() == 1);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001604 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001605 // We don't expect access checks to be needed on JSProxy objects.
1606 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001607 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001608 if (obj->IsAccessCheckNeeded() &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001609 !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj),
1610 isolate->factory()->proto_string(),
1611 v8::ACCESS_GET)) {
1612 isolate->ReportFailedAccessCheck(JSObject::cast(*obj), v8::ACCESS_GET);
danno@chromium.org169691d2013-07-15 08:01:13 +00001613 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001614 return isolate->heap()->undefined_value();
1615 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001616 obj = handle(obj->GetPrototype(isolate), isolate);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001617 } while (obj->IsJSObject() &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001618 JSObject::cast(*obj)->map()->is_hidden_prototype());
1619 return *obj;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001620}
1621
1622
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001623static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
1624 Object* receiver) {
1625 Object* current = receiver->GetPrototype(isolate);
1626 while (current->IsJSObject() &&
1627 JSObject::cast(current)->map()->is_hidden_prototype()) {
1628 current = current->GetPrototype(isolate);
1629 }
1630 return current;
1631}
1632
1633
ulan@chromium.org750145a2013-03-07 15:14:13 +00001634RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001635 HandleScope scope(isolate);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001636 ASSERT(args.length() == 2);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001637 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1638 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001639 if (FLAG_harmony_observation && obj->map()->is_observed()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001640 Handle<Object> old_value(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001641 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001642
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001643 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001644 RETURN_IF_EMPTY_HANDLE(isolate, result);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001645
1646 Handle<Object> new_value(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001647 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001648 if (!new_value->SameValue(*old_value)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001649 JSObject::EnqueueChangeRecord(obj, "prototype",
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001650 isolate->factory()->proto_string(),
1651 old_value);
1652 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001653 return *result;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001654 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001655 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001656 RETURN_IF_EMPTY_HANDLE(isolate, result);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001657 return *result;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001658}
1659
1660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001661RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001662 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663 ASSERT(args.length() == 2);
1664 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1665 Object* O = args[0];
1666 Object* V = args[1];
1667 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001668 Object* prototype = V->GetPrototype(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001669 if (prototype->IsNull()) return isolate->heap()->false_value();
1670 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 V = prototype;
1672 }
1673}
1674
1675
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001676static bool CheckAccessException(Object* callback,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001677 v8::AccessType access_type) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001678 DisallowHeapAllocation no_gc;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001679 if (callback->IsAccessorInfo()) {
1680 AccessorInfo* info = AccessorInfo::cast(callback);
1681 return
1682 (access_type == v8::ACCESS_HAS &&
1683 (info->all_can_read() || info->all_can_write())) ||
1684 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1685 (access_type == v8::ACCESS_SET && info->all_can_write());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001686 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001687 if (callback->IsAccessorPair()) {
1688 AccessorPair* info = AccessorPair::cast(callback);
1689 return
1690 (access_type == v8::ACCESS_HAS &&
1691 (info->all_can_read() || info->all_can_write())) ||
1692 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1693 (access_type == v8::ACCESS_SET && info->all_can_write());
1694 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001695 return false;
1696}
1697
1698
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001699template<class Key>
1700static bool CheckGenericAccess(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001701 Handle<JSObject> receiver,
1702 Handle<JSObject> holder,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001703 Key key,
1704 v8::AccessType access_type,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001705 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001706 Isolate* isolate = receiver->GetIsolate();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001707 for (Handle<JSObject> current = receiver;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001708 true;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001709 current = handle(JSObject::cast(current->GetPrototype()), isolate)) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001710 if (current->IsAccessCheckNeeded() &&
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001711 !(isolate->*mayAccess)(current, key, access_type)) {
1712 return false;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001713 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001714 if (current.is_identical_to(holder)) break;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001715 }
1716 return true;
1717}
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001718
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001719
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001720enum AccessCheckResult {
1721 ACCESS_FORBIDDEN,
1722 ACCESS_ALLOWED,
1723 ACCESS_ABSENT
1724};
1725
1726
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001727static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj,
1728 Handle<Name> name,
1729 v8::AccessType access_type) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001730 uint32_t index;
1731 if (name->AsArrayIndex(&index)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001732 // TODO(1095): we should traverse hidden prototype hierachy as well.
1733 if (CheckGenericAccess(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001734 obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001735 return ACCESS_ALLOWED;
1736 }
1737
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001738 obj->GetIsolate()->ReportFailedAccessCheck(*obj, access_type);
danno@chromium.org169691d2013-07-15 08:01:13 +00001739 return ACCESS_FORBIDDEN;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001740 }
1741
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001742 Isolate* isolate = obj->GetIsolate();
1743 LookupResult lookup(isolate);
1744 obj->LocalLookup(*name, &lookup, true);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001745
1746 if (!lookup.IsProperty()) return ACCESS_ABSENT;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001747 Handle<JSObject> holder(lookup.holder(), isolate);
1748 if (CheckGenericAccess<Handle<Object> >(
1749 obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001750 return ACCESS_ALLOWED;
1751 }
1752
1753 // Access check callback denied the access, but some properties
1754 // can have a special permissions which override callbacks descision
1755 // (currently see v8::AccessControl).
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001756 // API callbacks can have per callback access exceptions.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001757 switch (lookup.type()) {
1758 case CALLBACKS:
1759 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1760 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001761 }
1762 break;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001763 case INTERCEPTOR:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001764 // If the object has an interceptor, try real named properties.
1765 // Overwrite the result to fetch the correct property later.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001766 holder->LookupRealNamedProperty(*name, &lookup);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001767 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1768 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1769 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001770 }
1771 }
1772 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001773 default:
1774 break;
1775 }
1776
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001777 isolate->ReportFailedAccessCheck(*obj, access_type);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001778 return ACCESS_FORBIDDEN;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001779}
1780
1781
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001782// Enumerator used as indices into the array returned from GetOwnProperty
1783enum PropertyDescriptorIndices {
1784 IS_ACCESSOR_INDEX,
1785 VALUE_INDEX,
1786 GETTER_INDEX,
1787 SETTER_INDEX,
1788 WRITABLE_INDEX,
1789 ENUMERABLE_INDEX,
1790 CONFIGURABLE_INDEX,
1791 DESCRIPTOR_SIZE
1792};
1793
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001794
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001795static Handle<Object> GetOwnProperty(Isolate* isolate,
1796 Handle<JSObject> obj,
1797 Handle<Name> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 Heap* heap = isolate->heap();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001799 Factory* factory = isolate->factory();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001800 // Due to some WebKit tests, we want to make sure that we do not log
1801 // more than one access failure here.
danno@chromium.org169691d2013-07-15 08:01:13 +00001802 AccessCheckResult access_check_result =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001803 CheckPropertyAccess(obj, name, v8::ACCESS_HAS);
1804 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
danno@chromium.org169691d2013-07-15 08:01:13 +00001805 switch (access_check_result) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001806 case ACCESS_FORBIDDEN: return factory->false_value();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001807 case ACCESS_ALLOWED: break;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001808 case ACCESS_ABSENT: return factory->undefined_value();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001809 }
1810
1811 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name);
danno@chromium.org169691d2013-07-15 08:01:13 +00001812 if (attrs == ABSENT) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001813 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1814 return factory->undefined_value();
danno@chromium.org169691d2013-07-15 08:01:13 +00001815 }
1816 ASSERT(!isolate->has_scheduled_exception());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001817 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name);
1818 Handle<AccessorPair> accessors(raw_accessors, isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001820 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1821 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001822 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001823
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001824 if (raw_accessors == NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001825 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1826 // GetProperty does access check.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001827 Handle<Object> value = GetProperty(isolate, obj, name);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001828 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001829 elms->set(VALUE_INDEX, *value);
1830 } else {
1831 // Access checks are performed for both accessors separately.
1832 // When they fail, the respective field is not set in the descriptor.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001833 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
1834 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
1835
1836 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001837 ASSERT(!isolate->has_scheduled_exception());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001838 elms->set(GETTER_INDEX, *getter);
danno@chromium.org169691d2013-07-15 08:01:13 +00001839 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001840 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001841 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001842
1843 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001844 ASSERT(!isolate->has_scheduled_exception());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001845 elms->set(SETTER_INDEX, *setter);
danno@chromium.org169691d2013-07-15 08:01:13 +00001846 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001847 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001848 }
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001849 }
1850
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001851 return isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001852}
1853
1854
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001855// Returns an array with the property description:
1856// if args[1] is not a property on args[0]
1857// returns undefined
1858// if args[1] is a data property on args[0]
1859// [false, value, Writeable, Enumerable, Configurable]
1860// if args[1] is an accessor on args[0]
1861// [true, GetFunction, SetFunction, Enumerable, Configurable]
1862RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001863 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001864 ASSERT(args.length() == 2);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001865 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001866 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001867 Handle<Object> result = GetOwnProperty(isolate, obj, name);
1868 RETURN_IF_EMPTY_HANDLE(isolate, result);
1869 return *result;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001870}
1871
1872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001873RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001874 HandleScope scope(isolate);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001875 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001876 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1877 Handle<Object> result = JSObject::PreventExtensions(obj);
1878 RETURN_IF_EMPTY_HANDLE(isolate, result);
1879 return *result;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001880}
1881
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001884 SealHandleScope shs(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001886 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001887 if (obj->IsJSGlobalProxy()) {
1888 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001890 ASSERT(proto->IsJSGlobalObject());
1891 obj = JSObject::cast(proto);
1892 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001893 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001900 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1901 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1902 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001903 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001904 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001905 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906}
1907
1908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001909RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001910 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001912 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001913 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914}
1915
1916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001917RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001918 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 ASSERT(args.length() == 1);
1920 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001921 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001922 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923}
1924
1925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001926RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001927 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001929 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1930 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001931 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1932 InstanceType type = templ->map()->instance_type();
1933 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1934 type == OBJECT_TEMPLATE_INFO_TYPE);
1935 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001936 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001937 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1938 } else {
1939 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1940 }
1941 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942}
1943
1944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001946 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001947 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001948 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001949 Map* old_map = object->map();
1950 bool needs_access_checks = old_map->is_access_check_needed();
1951 if (needs_access_checks) {
1952 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001953 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001954 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001955 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00001956
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001957 new_map->set_is_access_check_needed(false);
1958 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00001959 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001960 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001961}
1962
1963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001964RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001965 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001966 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001967 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001968 Map* old_map = object->map();
1969 if (!old_map->is_access_check_needed()) {
1970 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001971 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001972 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001973 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00001974
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001975 new_map->set_is_access_check_needed(true);
1976 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00001977 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001979}
1980
1981
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001982// Transform getter or setter into something DefineAccessor can handle.
1983static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
1984 Handle<Object> component) {
1985 if (component->IsUndefined()) return isolate->factory()->null_value();
1986 Handle<FunctionTemplateInfo> info =
1987 Handle<FunctionTemplateInfo>::cast(component);
1988 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
1989}
1990
1991
1992RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) {
1993 HandleScope scope(isolate);
1994 ASSERT(args.length() == 6);
1995 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1996 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
1997 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
1998 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
1999 CONVERT_SMI_ARG_CHECKED(attribute, 4);
2000 CONVERT_SMI_ARG_CHECKED(access_control, 5);
2001 JSObject::DefineAccessor(object,
2002 name,
2003 InstantiateAccessorComponent(isolate, getter),
2004 InstantiateAccessorComponent(isolate, setter),
2005 static_cast<PropertyAttributes>(attribute),
2006 static_cast<v8::AccessControl>(access_control));
2007 return isolate->heap()->undefined_value();
2008}
2009
2010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002011static Failure* ThrowRedeclarationError(Isolate* isolate,
2012 const char* type,
2013 Handle<String> name) {
2014 HandleScope scope(isolate);
2015 Handle<Object> type_handle =
2016 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 Handle<Object> args[2] = { type_handle, name };
2018 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
2020 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021}
2022
2023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002024RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002026 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 Handle<GlobalObject> global = Handle<GlobalObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002028 isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029
ager@chromium.org3811b432009-10-28 14:53:37 +00002030 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002031 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002032 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 // Traverse the name/value pairs and set the properties.
2035 int length = pairs->length();
2036 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002037 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002038 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040
2041 // We have to declare a global const property. To capture we only
2042 // assign to it when evaluating the assignment for "const x =
2043 // <expr>" the initial value is the hole.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002044 bool is_var = value->IsUndefined();
2045 bool is_const = value->IsTheHole();
2046 bool is_function = value->IsSharedFunctionInfo();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002047 ASSERT(is_var + is_const + is_function == 1);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002048
2049 if (is_var || is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050 // Lookup the property in the global object, and don't set the
2051 // value of the variable if the property is already there.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002052 // Do the lookup locally only, see ES5 erratum.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002053 LookupResult lookup(isolate);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002054 if (FLAG_es52_globals) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002055 global->LocalLookup(*name, &lookup, true);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002056 } else {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002057 global->Lookup(*name, &lookup);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002058 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002059 if (lookup.IsFound()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002060 // We found an existing property. Unless it was an interceptor
2061 // that claims the property is absent, skip this declaration.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002062 if (!lookup.IsInterceptor()) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002063 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002064 if (attributes != ABSENT) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002065 // Fall-through and introduce the absent property by using
2066 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002068 } else if (is_function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002069 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002070 Handle<SharedFunctionInfo> shared =
2071 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002072 Handle<JSFunction> function =
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002073 isolate->factory()->NewFunctionFromSharedFunctionInfo(
2074 shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 value = function;
2076 }
2077
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002078 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002079 global->LocalLookup(*name, &lookup, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002081 // Compute the property attributes. According to ECMA-262,
2082 // the property must be non-configurable except in eval.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002083 int attr = NONE;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002084 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002085 if (!is_eval) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002086 attr |= DONT_DELETE;
2087 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002088 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002089 if (is_const || (is_native && is_function)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002090 attr |= READ_ONLY;
2091 }
2092
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002093 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
2094
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002095 if (!lookup.IsFound() || is_function) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002096 // If the local property exists, check that we can reconfigure it
2097 // as required for function declarations.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002098 if (lookup.IsFound() && lookup.IsDontDelete()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002099 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002100 lookup.IsPropertyCallbacks()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002101 return ThrowRedeclarationError(isolate, "function", name);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002102 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002103 // If the existing property is not configurable, keep its attributes.
2104 attr = lookup.GetAttributes();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002105 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002106 // Define or redefine own property.
2107 RETURN_IF_EMPTY_HANDLE(isolate,
2108 JSObject::SetLocalPropertyIgnoreAttributes(
2109 global, name, value, static_cast<PropertyAttributes>(attr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002111 // Do a [[Put]] on the existing (own) property.
2112 RETURN_IF_EMPTY_HANDLE(isolate,
2113 JSObject::SetProperty(
2114 global, name, value, static_cast<PropertyAttributes>(attr),
2115 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002116 }
2117 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 ASSERT(!isolate->has_pending_exception());
2120 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002121}
2122
2123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002124RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002125 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002126 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002128 // Declarations are always made in a function or native context. In the
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002129 // case of eval code, the context passed is the context of the caller,
2130 // which may be some nested context and not the declaration context.
2131 RUNTIME_ASSERT(args[0]->IsContext());
2132 Handle<Context> context(Context::cast(args[0])->declaration_context());
2133
ager@chromium.org7c537e22008-10-16 08:43:32 +00002134 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002135 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002136 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002137 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002139 int index;
2140 PropertyAttributes attributes;
2141 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002142 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002143 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002144 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002145
2146 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002147 // The name was declared before; check for conflicting re-declarations.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002148 // Note: this is actually inconsistent with what happens for globals (where
2149 // we silently ignore such declarations).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
2151 // Functions are not read-only.
2152 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
2153 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 }
2156
2157 // Initialize it if necessary.
2158 if (*initial_value != NULL) {
2159 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002160 ASSERT(holder.is_identical_to(context));
2161 if (((attributes & READ_ONLY) == 0) ||
2162 context->get(index)->IsTheHole()) {
2163 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 }
2165 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002166 // Slow case: The property is in the context extension object of a
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002167 // function context or the global object of a native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002168 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002169 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002170 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002171 JSReceiver::SetProperty(object, name, initial_value, mode,
2172 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 }
2174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002177 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002178 // "declared" in the function context's extension context or as a
2179 // property of the the global object.
2180 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002181 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002182 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002183 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002184 // Context extension objects are allocated lazily.
2185 ASSERT(context->IsFunctionContext());
2186 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002189 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002190 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002191
ager@chromium.org7c537e22008-10-16 08:43:32 +00002192 // Declare the property by setting it to the initial value if provided,
2193 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
2194 // constant declarations).
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002195 ASSERT(!JSReceiver::HasLocalProperty(object, name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002196 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002197 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002198 // Declaring a const context slot is a conflicting declaration if
2199 // there is a callback with that name in a prototype. It is
2200 // allowed to introduce const variables in
2201 // JSContextExtensionObjects. They are treated specially in
2202 // SetProperty and no setters are invoked for those since they are
2203 // not real JSObjects.
2204 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002205 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002206 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002207 object->Lookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002208 if (lookup.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002209 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002210 }
2211 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002212 if (object->IsJSGlobalObject()) {
2213 // Define own property on the global object.
2214 RETURN_IF_EMPTY_HANDLE(isolate,
2215 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
2216 } else {
2217 RETURN_IF_EMPTY_HANDLE(isolate,
2218 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
2219 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002220 }
2221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223}
2224
2225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002226RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002227 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002228 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002229 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002230 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002231
2232 // Determine if we need to assign to the variable if it already
2233 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002234 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
2235 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002236
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002237 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002238 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002239 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
2240 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
2241 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242
2243 // According to ECMA-262, section 12.2, page 62, the property must
2244 // not be deletable.
2245 PropertyAttributes attributes = DONT_DELETE;
2246
2247 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002248 // there, there is a property with this name in the prototype chain.
2249 // We follow Safari and Firefox behavior and only set the property
2250 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002251 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002252 // Note that objects can have hidden prototypes, so we need to traverse
2253 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002254 LookupResult lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002255 isolate->context()->global_object()->LocalLookup(*name, &lookup, true);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002256 if (lookup.IsInterceptor()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002257 PropertyAttributes intercepted =
2258 lookup.holder()->GetPropertyAttribute(*name);
2259 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
2260 // Found an interceptor that's not read only.
2261 if (assign) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002262 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2263 Handle<Object> result = JSObject::SetPropertyForResult(
2264 handle(lookup.holder()), &lookup, name, value, attributes,
2265 strict_mode_flag);
2266 RETURN_IF_EMPTY_HANDLE(isolate, result);
2267 return *result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002268 } else {
2269 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002270 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272 }
2273
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002274 if (assign) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002275 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2276 Handle<GlobalObject> global(isolate->context()->global_object());
2277 Handle<Object> result = JSReceiver::SetProperty(
2278 global, name, value, attributes, strict_mode_flag);
2279 RETURN_IF_EMPTY_HANDLE(isolate, result);
2280 return *result;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002281 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
2285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002286RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002287 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002288 // All constants are declared with an initial value. The name
2289 // of the constant is the first argument and the initial value
2290 // is the second.
2291 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002292 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002293 Handle<Object> value = args.at<Object>(1);
2294
2295 // Get the current global object from top.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002296 GlobalObject* global = isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002297
2298 // According to ECMA-262, section 12.2, page 62, the property must
2299 // not be deletable. Since it's a const, it must be READ_ONLY too.
2300 PropertyAttributes attributes =
2301 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2302
2303 // Lookup the property locally in the global object. If it isn't
2304 // there, we add the property and take special precautions to always
2305 // add it as a local property even in case of callbacks in the
2306 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002307 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002308 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309 global->LocalLookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002310 if (!lookup.IsFound()) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002311 HandleScope handle_scope(isolate);
2312 Handle<GlobalObject> global(isolate->context()->global_object());
2313 RETURN_IF_EMPTY_HANDLE(
2314 isolate,
2315 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
2316 attributes));
2317 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002318 }
2319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002321 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002322 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002323 HandleScope handle_scope(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002324 Handle<GlobalObject> global(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002325
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002326 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002327 // property through an interceptor and only do it if it's
2328 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002329 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002330 RETURN_IF_EMPTY_HANDLE(
2331 isolate,
2332 JSReceiver::SetProperty(global, name, value, attributes,
2333 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002334 return *value;
2335 }
2336
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002337 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338 // constant. For now, we determine this by checking if the
2339 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002340 // Strict mode handling not needed (const is disallowed in strict mode).
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002341 if (lookup.IsField()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002342 FixedArray* properties = global->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002343 int index = lookup.GetFieldIndex().field_index();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002344 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002345 properties->set(index, *value);
2346 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002347 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002348 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
2349 !lookup.IsReadOnly()) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002350 HandleScope scope(isolate);
2351 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352 }
2353 } else {
2354 // Ignore re-initialization of constants that have already been
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002355 // assigned a constant value.
2356 ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002357 }
2358
2359 // Use the set value as the result of the operation.
2360 return *value;
2361}
2362
2363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002364RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002366 ASSERT(args.length() == 3);
2367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002368 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002369 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002371 // Initializations are always done in a function or native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 RUNTIME_ASSERT(args[1]->IsContext());
2373 Handle<Context> context(Context::cast(args[1])->declaration_context());
2374
2375 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002376
2377 int index;
2378 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002379 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002380 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002381 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002382 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002383
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002384 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002385 ASSERT(holder->IsContext());
2386 // Property was found in a context. Perform the assignment if we
2387 // found some non-constant or an uninitialized constant.
2388 Handle<Context> context = Handle<Context>::cast(holder);
2389 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
2390 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002391 }
2392 return *value;
2393 }
2394
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002395 // The property could not be found, we introduce it as a property of the
2396 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002397 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002398 Handle<JSObject> global = Handle<JSObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002399 isolate->context()->global_object());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002400 // Strict mode not needed (const disallowed in strict mode).
2401 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002402 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002403 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002404 return *value;
2405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002407 // The property was present in some function's context extension object,
2408 // as a property on the subject of a with, or as a property of the global
2409 // object.
2410 //
2411 // In most situations, eval-introduced consts should still be present in
2412 // the context extension object. However, because declaration and
2413 // initialization are separate, the property might have been deleted
2414 // before we reach the initialization point.
2415 //
2416 // Example:
2417 //
2418 // function f() { eval("delete x; const x;"); }
2419 //
2420 // In that case, the initialization behaves like a normal assignment.
2421 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002422
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002423 if (*object == context->extension()) {
2424 // This is the property that was introduced by the const declaration.
2425 // Set it if it hasn't been set before. NOTE: We cannot use
2426 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002427 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002428 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002429 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002430 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
2431
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002432 if (lookup.IsField()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002433 FixedArray* properties = object->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002434 int index = lookup.GetFieldIndex().field_index();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002435 if (properties->get(index)->IsTheHole()) {
2436 properties->set(index, *value);
2437 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002438 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002439 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002440 JSObject::SetNormalizedProperty(object, &lookup, value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002441 }
2442 } else {
2443 // We should not reach here. Any real, named property should be
2444 // either a field or a dictionary slot.
2445 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002446 }
2447 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002448 // The property was found on some other object. Set it if it is not a
2449 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002450 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002451 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002452 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002453 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002454 JSReceiver::SetProperty(object, name, value, attributes,
2455 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002456 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002457 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002459 return *value;
2460}
2461
2462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002463RUNTIME_FUNCTION(MaybeObject*,
2464 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002465 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002466 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002467 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002468 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002469 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002470 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002471 }
2472 return *object;
2473}
2474
2475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002476RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002477 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002478 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002479 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2480 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002481 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002482 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002483 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002484 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002485 RUNTIME_ASSERT(index >= 0);
2486 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002487 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002488 Handle<Object> result = RegExpImpl::Exec(regexp,
2489 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002490 index,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002491 last_match_info);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002492 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002493 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494}
2495
2496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002497RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002498 SealHandleScope shs(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002499 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002500 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002501 if (elements_count < 0 ||
2502 elements_count > FixedArray::kMaxLength ||
2503 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002504 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002505 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002506 Object* new_object;
2507 { MaybeObject* maybe_new_object =
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002508 isolate->heap()->AllocateFixedArray(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002509 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2510 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002511 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
2513 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002514 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2515 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002516 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002517 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002518 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002519 reinterpret_cast<HeapObject*>(new_object)->
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002520 set_map(isolate->native_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002521 }
2522 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002523 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002524 array->set_elements(elements);
2525 array->set_length(Smi::FromInt(elements_count));
2526 // Write in-object properties after the length of the array.
2527 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
2528 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
2529 return array;
2530}
2531
2532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002533RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002534 HandleScope scope(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002535 DisallowHeapAllocation no_allocation;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002536 ASSERT(args.length() == 5);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002537 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2538 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00002539 // If source is the empty string we set it to "(?:)" instead as
2540 // suggested by ECMA-262, 5th, section 15.10.4.1.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002541 if (source->length() == 0) source = isolate->factory()->query_colon_string();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002542
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002543 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2544 if (!global->IsTrue()) global = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002545
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002546 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2547 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002548
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002549 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2550 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002551
2552 Map* map = regexp->map();
2553 Object* constructor = map->constructor();
2554 if (constructor->IsJSFunction() &&
2555 JSFunction::cast(constructor)->initial_map() == map) {
2556 // If we still have the original map, set in-object properties directly.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002557 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
erikcorry0ad885c2011-11-21 13:51:57 +00002558 // Both true and false are immovable immortal objects so no need for write
2559 // barrier.
2560 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002561 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
erikcorry0ad885c2011-11-21 13:51:57 +00002562 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002563 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
erikcorry0ad885c2011-11-21 13:51:57 +00002564 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002565 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002566 regexp->InObjectPropertyAtPut(
2567 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002568 return *regexp;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002569 }
2570
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002571 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002572 PropertyAttributes final =
2573 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2574 PropertyAttributes writable =
2575 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002576 Handle<Object> zero(Smi::FromInt(0), isolate);
2577 Factory* factory = isolate->factory();
2578 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2579 regexp, factory->source_string(), source, final));
2580 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2581 regexp, factory->global_string(), global, final));
2582 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2583 regexp, factory->ignore_case_string(), ignoreCase, final));
2584 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2585 regexp, factory->multiline_string(), multiline, final));
2586 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2587 regexp, factory->last_index_string(), zero, writable));
2588 return *regexp;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002589}
2590
2591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002592RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002593 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002594 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002595 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002596 // This is necessary to enable fast checks for absence of elements
2597 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002598 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002599 return Smi::FromInt(0);
2600}
2601
2602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002603static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
2604 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002605 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002606 Builtins::Name builtin_name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002607 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002608 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2609 Handle<JSFunction> optimized =
2610 isolate->factory()->NewFunction(key,
2611 JS_OBJECT_TYPE,
2612 JSObject::kHeaderSize,
2613 code,
2614 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002615 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002616 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002617 return optimized;
2618}
2619
2620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002621RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002622 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002623 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002624 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002625
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002626 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2627 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2628 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2629 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2630 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2631 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2632 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002633
2634 return *holder;
2635}
2636
2637
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002638RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002639 SealHandleScope shs(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002640 ASSERT(args.length() == 1);
2641 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2642 if (!callable->IsJSFunction()) {
2643 HandleScope scope(isolate);
2644 bool threw = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002645 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2646 isolate, Handle<JSReceiver>(callable), &threw);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002647 if (threw) return Failure::Exception();
2648 callable = JSFunction::cast(*delegate);
2649 }
2650 JSFunction* function = JSFunction::cast(callable);
2651 SharedFunctionInfo* shared = function->shared();
2652 return isolate->heap()->ToBoolean(shared->is_classic_mode());
2653}
2654
2655
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002656RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002657 SealHandleScope shs(isolate);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002658 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002659 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002660
2661 if (!callable->IsJSFunction()) {
2662 HandleScope scope(isolate);
2663 bool threw = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002664 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2665 isolate, Handle<JSReceiver>(callable), &threw);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002666 if (threw) return Failure::Exception();
2667 callable = JSFunction::cast(*delegate);
2668 }
2669 JSFunction* function = JSFunction::cast(callable);
2670
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002671 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002672 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002673 return isolate->heap()->undefined_value();
2674 }
2675 // Returns undefined for strict or native functions, or
2676 // the associated global receiver for "normal" functions.
2677
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002678 Context* native_context =
2679 function->context()->global_object()->native_context();
2680 return native_context->global_object()->global_receiver();
ager@chromium.org357bf652010-04-12 11:30:10 +00002681}
2682
2683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002684RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002685 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002687 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002688 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002689 Handle<String> pattern = args.at<String>(2);
2690 Handle<String> flags = args.at<String>(3);
2691
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002692 // Get the RegExp function from the context in the literals array.
2693 // This is the RegExp function from the context in which the
2694 // function was created. We do not use the RegExp function from the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002695 // current native context because this might be the RegExp function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002696 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002697 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00002698 Handle<JSFunction>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002699 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700 // Compute the regular expression literal.
2701 bool has_pending_exception;
2702 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002703 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
2704 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707 return Failure::Exception();
2708 }
2709 literals->set(index, *regexp);
2710 return *regexp;
2711}
2712
2713
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002714RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002715 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002716 ASSERT(args.length() == 1);
2717
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002718 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719 return f->shared()->name();
2720}
2721
2722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002723RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002724 SealHandleScope shs(isolate);
ager@chromium.org236ad962008-09-25 09:45:57 +00002725 ASSERT(args.length() == 2);
2726
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002727 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2728 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00002729 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00002731}
2732
2733
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002734RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002735 SealHandleScope shs(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002736 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002737 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002738 return isolate->heap()->ToBoolean(
2739 f->shared()->name_should_print_as_anonymous());
2740}
2741
2742
2743RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002744 SealHandleScope shs(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002745 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002746 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002747 f->shared()->set_name_should_print_as_anonymous(true);
2748 return isolate->heap()->undefined_value();
2749}
2750
2751
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002752RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002753 SealHandleScope shs(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002754 ASSERT(args.length() == 1);
2755 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2756 return isolate->heap()->ToBoolean(f->shared()->is_generator());
2757}
2758
2759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002760RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002761 SealHandleScope shs(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002762 ASSERT(args.length() == 1);
2763
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002764 CONVERT_ARG_CHECKED(JSFunction, f, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002765 f->RemovePrototype();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002766
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002767 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002768}
2769
2770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002771RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002772 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002773 ASSERT(args.length() == 1);
2774
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002775 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002776 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2777 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778
2779 return *GetScriptWrapper(Handle<Script>::cast(script));
2780}
2781
2782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002783RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002784 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785 ASSERT(args.length() == 1);
2786
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002787 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002788 Handle<SharedFunctionInfo> shared(f->shared());
2789 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002790}
2791
2792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002793RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002794 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002795 ASSERT(args.length() == 1);
2796
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002797 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 int pos = fun->shared()->start_position();
2799 return Smi::FromInt(pos);
2800}
2801
2802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002803RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002804 SealHandleScope shs(isolate);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002805 ASSERT(args.length() == 2);
2806
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002807 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002808 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2809
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002810 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2811
2812 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002813 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002814}
2815
2816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002817RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002818 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819 ASSERT(args.length() == 2);
2820
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002821 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2822 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002824 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002825}
2826
2827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002828RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002829 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830 ASSERT(args.length() == 2);
2831
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002832 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2833 CONVERT_SMI_ARG_CHECKED(length, 1);
2834 fun->shared()->set_length(length);
2835 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836}
2837
2838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002839RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002840 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002841 ASSERT(args.length() == 2);
2842
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002843 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2844 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002845 ASSERT(fun->should_have_prototype());
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002846 Accessors::FunctionSetPrototype(fun, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 return args[0]; // return TOS
2848}
2849
2850
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002851RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002852 SealHandleScope shs(isolate);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002853 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002854 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002855
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002856 String* name = isolate->heap()->prototype_string();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002857
2858 if (function->HasFastProperties()) {
2859 // Construct a new field descriptor with updated attributes.
2860 DescriptorArray* instance_desc = function->map()->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002861
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002862 int index = instance_desc->SearchWithCache(name, function->map());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002863 ASSERT(index != DescriptorArray::kNotFound);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002864 PropertyDetails details = instance_desc->GetDetails(index);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002865
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002866 CallbacksDescriptor new_desc(name,
2867 instance_desc->GetValue(index),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002868 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002869
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002870 // Create a new map featuring the new field descriptors array.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002871 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002872 MaybeObject* maybe_map =
2873 function->map()->CopyReplaceDescriptor(
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002874 instance_desc, &new_desc, index, OMIT_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002875 if (!maybe_map->To(&new_map)) return maybe_map;
2876
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002877 function->set_map(new_map);
2878 } else { // Dictionary properties.
2879 // Directly manipulate the property details.
2880 int entry = function->property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002881 ASSERT(entry != NameDictionary::kNotFound);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002882 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2883 PropertyDetails new_details(
2884 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2885 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002886 details.dictionary_index());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002887 function->property_dictionary()->DetailsAtPut(entry, new_details);
2888 }
2889 return function;
2890}
2891
2892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002893RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002894 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002895 ASSERT(args.length() == 1);
2896
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002897 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002898 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002899}
2900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002902RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002903 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002904 ASSERT(args.length() == 1);
2905
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002906 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002907 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002908}
2909
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002911RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002912 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002913 ASSERT(args.length() == 2);
2914
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002915 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002916 Handle<Object> code = args.at<Object>(1);
2917
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002918 if (code->IsNull()) return *target;
2919 RUNTIME_ASSERT(code->IsJSFunction());
2920 Handle<JSFunction> source = Handle<JSFunction>::cast(code);
2921 Handle<SharedFunctionInfo> target_shared(target->shared());
2922 Handle<SharedFunctionInfo> source_shared(source->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002924 if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002925 return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002926 }
2927
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002928 // Mark both, the source and the target, as un-flushable because the
2929 // shared unoptimized code makes them impossible to enqueue in a list.
2930 ASSERT(target_shared->code()->gc_metadata() == NULL);
2931 ASSERT(source_shared->code()->gc_metadata() == NULL);
2932 target_shared->set_dont_flush(true);
2933 source_shared->set_dont_flush(true);
2934
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002935 // Set the code, scope info, formal parameter count, and the length
2936 // of the target shared function info. Set the source code of the
2937 // target function to undefined. SetCode is only used for built-in
2938 // constructors like String, Array, and Object, and some web code
2939 // doesn't like seeing source code for constructors.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002940 target_shared->ReplaceCode(source_shared->code());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002941 target_shared->set_scope_info(source_shared->scope_info());
2942 target_shared->set_length(source_shared->length());
2943 target_shared->set_formal_parameter_count(
2944 source_shared->formal_parameter_count());
2945 target_shared->set_script(isolate->heap()->undefined_value());
2946
2947 // Since we don't store the source we should never optimize this.
2948 target_shared->code()->set_optimizable(false);
2949
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002950 // Set the code of the target function.
2951 target->ReplaceCode(source_shared->code());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002952 ASSERT(target->next_function_link()->IsUndefined());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002953
2954 // Make sure we get a fresh copy of the literal vector to avoid cross
2955 // context contamination.
2956 Handle<Context> context(source->context());
2957 int number_of_literals = source->NumberOfLiterals();
2958 Handle<FixedArray> literals =
2959 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
2960 if (number_of_literals > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002961 literals->set(JSFunction::kLiteralNativeContextIndex,
2962 context->native_context());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002964 target->set_context(*context);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002965 target->set_literals(*literals);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002966
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002967 if (isolate->logger()->is_logging_code_events() ||
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002968 isolate->cpu_profiler()->is_profiling()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002969 isolate->logger()->LogExistingFunction(
2970 source_shared, Handle<Code>(source_shared->code()));
2971 }
2972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002973 return *target;
2974}
2975
2976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002977RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002978 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002979 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002980 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002981 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002982 RUNTIME_ASSERT(num >= 0);
2983 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002984 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002985}
2986
2987
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002988RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002989 SealHandleScope shs(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002990 ASSERT(args.length() == 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002991
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002992 JavaScriptFrameIterator it(isolate);
2993 JavaScriptFrame* frame = it.frame();
danno@chromium.org169691d2013-07-15 08:01:13 +00002994 JSFunction* function = frame->function();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002995 RUNTIME_ASSERT(function->shared()->is_generator());
2996
2997 JSGeneratorObject* generator;
2998 if (frame->IsConstructor()) {
2999 generator = JSGeneratorObject::cast(frame->receiver());
3000 } else {
3001 MaybeObject* maybe_generator =
3002 isolate->heap()->AllocateJSGeneratorObject(function);
3003 if (!maybe_generator->To(&generator)) return maybe_generator;
3004 }
3005 generator->set_function(function);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003006 generator->set_context(Context::cast(frame->context()));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003007 generator->set_receiver(frame->receiver());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003008 generator->set_continuation(0);
3009 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003010 generator->set_stack_handler_index(-1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003011
3012 return generator;
3013}
3014
3015
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003016RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003017 SealHandleScope shs(isolate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003018 ASSERT(args.length() == 1);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003019 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003020
3021 JavaScriptFrameIterator stack_iterator(isolate);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003022 JavaScriptFrame* frame = stack_iterator.frame();
danno@chromium.org169691d2013-07-15 08:01:13 +00003023 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3024 ASSERT_EQ(frame->function(), generator_object->function());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003025
3026 // The caller should have saved the context and continuation already.
3027 ASSERT_EQ(generator_object->context(), Context::cast(frame->context()));
3028 ASSERT_LT(0, generator_object->continuation());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003029
danno@chromium.orgf005df62013-04-30 16:36:45 +00003030 // We expect there to be at least two values on the operand stack: the return
3031 // value of the yield expression, and the argument to this runtime call.
3032 // Neither of those should be saved.
3033 int operands_count = frame->ComputeOperandsCount();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003034 ASSERT_GE(operands_count, 2);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003035 operands_count -= 2;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003036
danno@chromium.orgf005df62013-04-30 16:36:45 +00003037 if (operands_count == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003038 // Although it's semantically harmless to call this function with an
3039 // operands_count of zero, it is also unnecessary.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003040 ASSERT_EQ(generator_object->operand_stack(),
3041 isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003042 ASSERT_EQ(generator_object->stack_handler_index(), -1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003043 // If there are no operands on the stack, there shouldn't be a handler
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003044 // active either.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003045 ASSERT(!frame->HasHandler());
3046 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003047 int stack_handler_index = -1;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003048 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003049 FixedArray* operand_stack;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003050 if (!alloc->To(&operand_stack)) return alloc;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003051 frame->SaveOperandStack(operand_stack, &stack_handler_index);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003052 generator_object->set_operand_stack(operand_stack);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003053 generator_object->set_stack_handler_index(stack_handler_index);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003054 }
3055
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003056 return isolate->heap()->undefined_value();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003057}
3058
3059
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003060// Note that this function is the slow path for resuming generators. It is only
3061// called if the suspended activation had operands on the stack, stack handlers
3062// needing rewinding, or if the resume should throw an exception. The fast path
3063// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003064// inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
3065// called in any case, as it needs to reconstruct the stack frame and make space
3066// for arguments and operands.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003067RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003068 SealHandleScope shs(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003069 ASSERT(args.length() == 3);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003070 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3071 CONVERT_ARG_CHECKED(Object, value, 1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003072 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3073 JavaScriptFrameIterator stack_iterator(isolate);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003074 JavaScriptFrame* frame = stack_iterator.frame();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003075
3076 ASSERT_EQ(frame->function(), generator_object->function());
danno@chromium.org59400602013-08-13 17:09:37 +00003077 ASSERT(frame->function()->is_compiled());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003078
3079 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0);
3080 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0);
3081
3082 Address pc = generator_object->function()->code()->instruction_start();
3083 int offset = generator_object->continuation();
3084 ASSERT(offset > 0);
3085 frame->set_pc(pc + offset);
3086 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3087
danno@chromium.orgf005df62013-04-30 16:36:45 +00003088 FixedArray* operand_stack = generator_object->operand_stack();
3089 int operands_count = operand_stack->length();
3090 if (operands_count != 0) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003091 frame->RestoreOperandStack(operand_stack,
3092 generator_object->stack_handler_index());
danno@chromium.orgf005df62013-04-30 16:36:45 +00003093 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003094 generator_object->set_stack_handler_index(-1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003095 }
3096
3097 JSGeneratorObject::ResumeMode resume_mode =
3098 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3099 switch (resume_mode) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003100 case JSGeneratorObject::NEXT:
danno@chromium.orgf005df62013-04-30 16:36:45 +00003101 return value;
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003102 case JSGeneratorObject::THROW:
danno@chromium.orgf005df62013-04-30 16:36:45 +00003103 return isolate->Throw(value);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003104 }
3105
3106 UNREACHABLE();
3107 return isolate->ThrowIllegalOperation();
3108}
3109
3110
3111RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) {
3112 HandleScope scope(isolate);
3113 ASSERT(args.length() == 1);
3114 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3115 int continuation = generator->continuation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003116 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003117 "generator_finished" : "generator_running";
3118 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3119 Handle<Object> error = isolate->factory()->NewError(message, argv);
3120 return isolate->Throw(*error);
3121}
3122
3123
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003124RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003125 HandleScope scope(isolate);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003126 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003127 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3128 Handle<Object> result = JSObject::Freeze(object);
3129 RETURN_IF_EMPTY_HANDLE(isolate, result);
3130 return *result;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003131}
3132
3133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003134MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
3135 Object* char_code) {
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00003136 if (char_code->IsNumber()) {
3137 return isolate->heap()->LookupSingleCharacterStringFromCode(
3138 NumberToUint32(char_code) & 0xffff);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003139 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003140 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003141}
3142
3143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003144RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003145 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 ASSERT(args.length() == 2);
3147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003148 CONVERT_ARG_CHECKED(String, subject, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003149 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003150
3151 // Flatten the string. If someone wants to get a char at an index
3152 // in a cons string, it is likely that more indices will be
3153 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003154 Object* flat;
3155 { MaybeObject* maybe_flat = subject->TryFlatten();
3156 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
3157 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003158 subject = String::cast(flat);
3159
3160 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003161 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003162 }
3163
3164 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003165}
3166
3167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003168RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003169 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003170 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003171 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172}
3173
lrn@chromium.org25156de2010-04-06 13:10:27 +00003174
3175class FixedArrayBuilder {
3176 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003177 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3178 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003179 length_(0),
3180 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 // Require a non-zero initial size. Ensures that doubling the size to
3182 // extend the array will work.
3183 ASSERT(initial_capacity > 0);
3184 }
3185
3186 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3187 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003188 length_(0),
3189 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 // Require a non-zero initial size. Ensures that doubling the size to
3191 // extend the array will work.
3192 ASSERT(backing_store->length() > 0);
3193 }
3194
3195 bool HasCapacity(int elements) {
3196 int length = array_->length();
3197 int required_length = length_ + elements;
3198 return (length >= required_length);
3199 }
3200
3201 void EnsureCapacity(int elements) {
3202 int length = array_->length();
3203 int required_length = length_ + elements;
3204 if (length < required_length) {
3205 int new_length = length;
3206 do {
3207 new_length *= 2;
3208 } while (new_length < required_length);
3209 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 array_->CopyTo(0, *extended_array, 0, length_);
3212 array_ = extended_array;
3213 }
3214 }
3215
3216 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003217 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 ASSERT(length_ < capacity());
3219 array_->set(length_, value);
3220 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003221 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222 }
3223
3224 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003225 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003226 ASSERT(length_ < capacity());
3227 array_->set(length_, value);
3228 length_++;
3229 }
3230
3231 Handle<FixedArray> array() {
3232 return array_;
3233 }
3234
3235 int length() {
3236 return length_;
3237 }
3238
3239 int capacity() {
3240 return array_->length();
3241 }
3242
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003244 Factory* factory = target_array->GetIsolate()->factory();
3245 factory->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003246 target_array->set_length(Smi::FromInt(length_));
3247 return target_array;
3248 }
3249
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003250
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 private:
3252 Handle<FixedArray> array_;
3253 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003254 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003255};
3256
3257
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003258// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259const int kStringBuilderConcatHelperLengthBits = 11;
3260const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261
3262template <typename schar>
3263static inline void StringBuilderConcatHelper(String*,
3264 schar*,
3265 FixedArray*,
3266 int);
3267
lrn@chromium.org25156de2010-04-06 13:10:27 +00003268typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3269 StringBuilderSubstringLength;
3270typedef BitField<int,
3271 kStringBuilderConcatHelperLengthBits,
3272 kStringBuilderConcatHelperPositionBits>
3273 StringBuilderSubstringPosition;
3274
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003275
3276class ReplacementStringBuilder {
3277 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 ReplacementStringBuilder(Heap* heap,
3279 Handle<String> subject,
3280 int estimated_part_count)
3281 : heap_(heap),
3282 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00003283 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003284 character_count_(0),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003285 is_ascii_(subject->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003286 // Require a non-zero initial size. Ensures that doubling the size to
3287 // extend the array will work.
3288 ASSERT(estimated_part_count > 0);
3289 }
3290
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3292 int from,
3293 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003294 ASSERT(from >= 0);
3295 int length = to - from;
3296 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003297 if (StringBuilderSubstringLength::is_valid(length) &&
3298 StringBuilderSubstringPosition::is_valid(from)) {
3299 int encoded_slice = StringBuilderSubstringLength::encode(length) |
3300 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003301 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003302 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003303 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00003304 builder->Add(Smi::FromInt(-length));
3305 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003306 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 }
3308
3309
3310 void EnsureCapacity(int elements) {
3311 array_builder_.EnsureCapacity(elements);
3312 }
3313
3314
3315 void AddSubjectSlice(int from, int to) {
3316 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003317 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003318 }
3319
3320
3321 void AddString(Handle<String> string) {
3322 int length = string->length();
3323 ASSERT(length > 0);
3324 AddElement(*string);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003325 if (!string->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003326 is_ascii_ = false;
3327 }
3328 IncrementCharacterCount(length);
3329 }
3330
3331
3332 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003333 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003334 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003335 }
3336
3337 Handle<String> joined_string;
3338 if (is_ascii_) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003339 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003340 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003341 uint8_t* char_buffer = seq->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003342 StringBuilderConcatHelper(*subject_,
3343 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003344 *array_builder_.array(),
3345 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003346 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003347 } else {
3348 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00003349 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003350 DisallowHeapAllocation no_gc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003351 uc16* char_buffer = seq->GetChars();
3352 StringBuilderConcatHelper(*subject_,
3353 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354 *array_builder_.array(),
3355 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003356 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 }
3358 return joined_string;
3359 }
3360
3361
3362 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003363 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003364 V8::FatalProcessOutOfMemory("String.replace result too large.");
3365 }
3366 character_count_ += by;
3367 }
3368
lrn@chromium.org25156de2010-04-06 13:10:27 +00003369 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003370 Handle<SeqOneByteString> NewRawOneByteString(int length) {
3371 return heap_->isolate()->factory()->NewRawOneByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003372 }
3373
3374
ager@chromium.org04921a82011-06-27 13:21:41 +00003375 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
3376 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003377 }
3378
3379
3380 void AddElement(Object* element) {
3381 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003382 ASSERT(array_builder_.capacity() > array_builder_.length());
3383 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003384 }
3385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003386 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003387 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003388 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003389 int character_count_;
3390 bool is_ascii_;
3391};
3392
3393
3394class CompiledReplacement {
3395 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003396 explicit CompiledReplacement(Zone* zone)
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003397 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003398
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003399 // Return whether the replacement is simple.
3400 bool Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003401 int capture_count,
3402 int subject_length);
3403
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003404 // Use Apply only if Compile returned false.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003405 void Apply(ReplacementStringBuilder* builder,
3406 int match_from,
3407 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003408 int32_t* match);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003409
3410 // Number of distinct parts of the replacement pattern.
3411 int parts() {
3412 return parts_.length();
3413 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003414
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003415 Zone* zone() const { return zone_; }
3416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003417 private:
3418 enum PartType {
3419 SUBJECT_PREFIX = 1,
3420 SUBJECT_SUFFIX,
3421 SUBJECT_CAPTURE,
3422 REPLACEMENT_SUBSTRING,
3423 REPLACEMENT_STRING,
3424
3425 NUMBER_OF_PART_TYPES
3426 };
3427
3428 struct ReplacementPart {
3429 static inline ReplacementPart SubjectMatch() {
3430 return ReplacementPart(SUBJECT_CAPTURE, 0);
3431 }
3432 static inline ReplacementPart SubjectCapture(int capture_index) {
3433 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3434 }
3435 static inline ReplacementPart SubjectPrefix() {
3436 return ReplacementPart(SUBJECT_PREFIX, 0);
3437 }
3438 static inline ReplacementPart SubjectSuffix(int subject_length) {
3439 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3440 }
3441 static inline ReplacementPart ReplacementString() {
3442 return ReplacementPart(REPLACEMENT_STRING, 0);
3443 }
3444 static inline ReplacementPart ReplacementSubString(int from, int to) {
3445 ASSERT(from >= 0);
3446 ASSERT(to > from);
3447 return ReplacementPart(-from, to);
3448 }
3449
3450 // If tag <= 0 then it is the negation of a start index of a substring of
3451 // the replacement pattern, otherwise it's a value from PartType.
3452 ReplacementPart(int tag, int data)
3453 : tag(tag), data(data) {
3454 // Must be non-positive or a PartType value.
3455 ASSERT(tag < NUMBER_OF_PART_TYPES);
3456 }
3457 // Either a value of PartType or a non-positive number that is
3458 // the negation of an index into the replacement string.
3459 int tag;
3460 // The data value's interpretation depends on the value of tag:
3461 // tag == SUBJECT_PREFIX ||
3462 // tag == SUBJECT_SUFFIX: data is unused.
3463 // tag == SUBJECT_CAPTURE: data is the number of the capture.
3464 // tag == REPLACEMENT_SUBSTRING ||
3465 // tag == REPLACEMENT_STRING: data is index into array of substrings
3466 // of the replacement string.
3467 // tag <= 0: Temporary representation of the substring of the replacement
3468 // string ranging over -tag .. data.
3469 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3470 // substring objects.
3471 int data;
3472 };
3473
3474 template<typename Char>
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003475 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3476 Vector<Char> characters,
3477 int capture_count,
3478 int subject_length,
3479 Zone* zone) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003480 int length = characters.length();
3481 int last = 0;
3482 for (int i = 0; i < length; i++) {
3483 Char c = characters[i];
3484 if (c == '$') {
3485 int next_index = i + 1;
3486 if (next_index == length) { // No next character!
3487 break;
3488 }
3489 Char c2 = characters[next_index];
3490 switch (c2) {
3491 case '$':
3492 if (i > last) {
3493 // There is a substring before. Include the first "$".
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003494 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3495 zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003496 last = next_index + 1; // Continue after the second "$".
3497 } else {
3498 // Let the next substring start with the second "$".
3499 last = next_index;
3500 }
3501 i = next_index;
3502 break;
3503 case '`':
3504 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003505 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003506 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003507 parts->Add(ReplacementPart::SubjectPrefix(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003508 i = next_index;
3509 last = i + 1;
3510 break;
3511 case '\'':
3512 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003513 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003514 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003515 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003516 i = next_index;
3517 last = i + 1;
3518 break;
3519 case '&':
3520 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003521 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003522 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003523 parts->Add(ReplacementPart::SubjectMatch(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003524 i = next_index;
3525 last = i + 1;
3526 break;
3527 case '0':
3528 case '1':
3529 case '2':
3530 case '3':
3531 case '4':
3532 case '5':
3533 case '6':
3534 case '7':
3535 case '8':
3536 case '9': {
3537 int capture_ref = c2 - '0';
3538 if (capture_ref > capture_count) {
3539 i = next_index;
3540 continue;
3541 }
3542 int second_digit_index = next_index + 1;
3543 if (second_digit_index < length) {
3544 // Peek ahead to see if we have two digits.
3545 Char c3 = characters[second_digit_index];
3546 if ('0' <= c3 && c3 <= '9') { // Double digits.
3547 int double_digit_ref = capture_ref * 10 + c3 - '0';
3548 if (double_digit_ref <= capture_count) {
3549 next_index = second_digit_index;
3550 capture_ref = double_digit_ref;
3551 }
3552 }
3553 }
3554 if (capture_ref > 0) {
3555 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003556 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003557 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003558 ASSERT(capture_ref <= capture_count);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003559 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003560 last = next_index + 1;
3561 }
3562 i = next_index;
3563 break;
3564 }
3565 default:
3566 i = next_index;
3567 break;
3568 }
3569 }
3570 }
3571 if (length > last) {
3572 if (last == 0) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003573 // Replacement is simple. Do not use Apply to do the replacement.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003574 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003575 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003576 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003577 }
3578 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003579 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003580 }
3581
3582 ZoneList<ReplacementPart> parts_;
3583 ZoneList<Handle<String> > replacement_substrings_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003584 Zone* zone_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003585};
3586
3587
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003588bool CompiledReplacement::Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003589 int capture_count,
3590 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003591 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003592 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003593 String::FlatContent content = replacement->GetFlatContent();
3594 ASSERT(content.IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003595 bool simple = false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003596 if (content.IsAscii()) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003597 simple = ParseReplacementPattern(&parts_,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003598 content.ToOneByteVector(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003599 capture_count,
3600 subject_length,
3601 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003602 } else {
3603 ASSERT(content.IsTwoByte());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003604 simple = ParseReplacementPattern(&parts_,
3605 content.ToUC16Vector(),
3606 capture_count,
3607 subject_length,
3608 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003609 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003610 if (simple) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003611 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003614 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003615 int substring_index = 0;
3616 for (int i = 0, n = parts_.length(); i < n; i++) {
3617 int tag = parts_[i].tag;
3618 if (tag <= 0) { // A replacement string slice.
3619 int from = -tag;
3620 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 replacement_substrings_.Add(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003622 isolate->factory()->NewSubString(replacement, from, to), zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003623 parts_[i].tag = REPLACEMENT_SUBSTRING;
3624 parts_[i].data = substring_index;
3625 substring_index++;
3626 } else if (tag == REPLACEMENT_STRING) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003627 replacement_substrings_.Add(replacement, zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003628 parts_[i].data = substring_index;
3629 substring_index++;
3630 }
3631 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003632 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003633}
3634
3635
3636void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3637 int match_from,
3638 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003639 int32_t* match) {
3640 ASSERT_LT(0, parts_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003641 for (int i = 0, n = parts_.length(); i < n; i++) {
3642 ReplacementPart part = parts_[i];
3643 switch (part.tag) {
3644 case SUBJECT_PREFIX:
3645 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3646 break;
3647 case SUBJECT_SUFFIX: {
3648 int subject_length = part.data;
3649 if (match_to < subject_length) {
3650 builder->AddSubjectSlice(match_to, subject_length);
3651 }
3652 break;
3653 }
3654 case SUBJECT_CAPTURE: {
3655 int capture = part.data;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003656 int from = match[capture * 2];
3657 int to = match[capture * 2 + 1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003658 if (from >= 0 && to > from) {
3659 builder->AddSubjectSlice(from, to);
3660 }
3661 break;
3662 }
3663 case REPLACEMENT_SUBSTRING:
3664 case REPLACEMENT_STRING:
3665 builder->AddString(replacement_substrings_[part.data]);
3666 break;
3667 default:
3668 UNREACHABLE();
3669 }
3670 }
3671}
3672
3673
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003674void FindAsciiStringIndices(Vector<const uint8_t> subject,
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003675 char pattern,
3676 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003677 unsigned int limit,
3678 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003679 ASSERT(limit > 0);
3680 // Collect indices of pattern in subject using memchr.
3681 // Stop after finding at most limit values.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003682 const uint8_t* subject_start = subject.start();
3683 const uint8_t* subject_end = subject_start + subject.length();
3684 const uint8_t* pos = subject_start;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003685 while (limit > 0) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003686 pos = reinterpret_cast<const uint8_t*>(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003687 memchr(pos, pattern, subject_end - pos));
3688 if (pos == NULL) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003689 indices->Add(static_cast<int>(pos - subject_start), zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003690 pos++;
3691 limit--;
3692 }
3693}
3694
3695
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003696void FindTwoByteStringIndices(const Vector<const uc16> subject,
3697 uc16 pattern,
3698 ZoneList<int>* indices,
3699 unsigned int limit,
3700 Zone* zone) {
3701 ASSERT(limit > 0);
3702 const uc16* subject_start = subject.start();
3703 const uc16* subject_end = subject_start + subject.length();
3704 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3705 if (*pos == pattern) {
3706 indices->Add(static_cast<int>(pos - subject_start), zone);
3707 limit--;
3708 }
3709 }
3710}
3711
3712
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003713template <typename SubjectChar, typename PatternChar>
3714void FindStringIndices(Isolate* isolate,
3715 Vector<const SubjectChar> subject,
3716 Vector<const PatternChar> pattern,
3717 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003718 unsigned int limit,
3719 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003720 ASSERT(limit > 0);
3721 // Collect indices of pattern in subject.
3722 // Stop after finding at most limit values.
3723 int pattern_length = pattern.length();
3724 int index = 0;
3725 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3726 while (limit > 0) {
3727 index = search.Search(subject, index);
3728 if (index < 0) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003729 indices->Add(index, zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003730 index += pattern_length;
3731 limit--;
3732 }
3733}
3734
3735
3736void FindStringIndicesDispatch(Isolate* isolate,
3737 String* subject,
3738 String* pattern,
3739 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003740 unsigned int limit,
3741 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003742 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003743 DisallowHeapAllocation no_gc;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003744 String::FlatContent subject_content = subject->GetFlatContent();
3745 String::FlatContent pattern_content = pattern->GetFlatContent();
3746 ASSERT(subject_content.IsFlat());
3747 ASSERT(pattern_content.IsFlat());
3748 if (subject_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003749 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003750 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003751 Vector<const uint8_t> pattern_vector =
3752 pattern_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003753 if (pattern_vector.length() == 1) {
3754 FindAsciiStringIndices(subject_vector,
3755 pattern_vector[0],
3756 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003757 limit,
3758 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003759 } else {
3760 FindStringIndices(isolate,
3761 subject_vector,
3762 pattern_vector,
3763 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003764 limit,
3765 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003766 }
3767 } else {
3768 FindStringIndices(isolate,
3769 subject_vector,
3770 pattern_content.ToUC16Vector(),
3771 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003772 limit,
3773 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003774 }
3775 } else {
3776 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003777 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003778 Vector<const uint8_t> pattern_vector =
3779 pattern_content.ToOneByteVector();
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003780 if (pattern_vector.length() == 1) {
3781 FindTwoByteStringIndices(subject_vector,
3782 pattern_vector[0],
3783 indices,
3784 limit,
3785 zone);
3786 } else {
3787 FindStringIndices(isolate,
3788 subject_vector,
3789 pattern_vector,
3790 indices,
3791 limit,
3792 zone);
3793 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003794 } else {
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003795 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3796 if (pattern_vector.length() == 1) {
3797 FindTwoByteStringIndices(subject_vector,
3798 pattern_vector[0],
3799 indices,
3800 limit,
3801 zone);
3802 } else {
3803 FindStringIndices(isolate,
3804 subject_vector,
3805 pattern_vector,
3806 indices,
3807 limit,
3808 zone);
3809 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003810 }
3811 }
3812 }
3813}
3814
3815
3816template<typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003817MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003818 Isolate* isolate,
3819 Handle<String> subject,
3820 Handle<JSRegExp> pattern_regexp,
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003821 Handle<String> replacement,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003822 Handle<JSArray> last_match_info) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003823 ASSERT(subject->IsFlat());
3824 ASSERT(replacement->IsFlat());
3825
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003826 ZoneScope zone_scope(isolate->runtime_zone());
3827 ZoneList<int> indices(8, zone_scope.zone());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003828 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
3829 String* pattern =
3830 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
3831 int subject_len = subject->length();
3832 int pattern_len = pattern->length();
3833 int replacement_len = replacement->length();
3834
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003835 FindStringIndicesDispatch(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003836 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003837
3838 int matches = indices.length();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003839 if (matches == 0) return *subject;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003840
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003841 // Detect integer overflow.
3842 int64_t result_len_64 =
3843 (static_cast<int64_t>(replacement_len) -
3844 static_cast<int64_t>(pattern_len)) *
3845 static_cast<int64_t>(matches) +
3846 static_cast<int64_t>(subject_len);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003847 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003848 int result_len = static_cast<int>(result_len_64);
3849
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003850 int subject_pos = 0;
3851 int result_pos = 0;
3852
3853 Handle<ResultSeqString> result;
3854 if (ResultSeqString::kHasAsciiEncoding) {
3855 result = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003856 isolate->factory()->NewRawOneByteString(result_len));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003857 } else {
3858 result = Handle<ResultSeqString>::cast(
3859 isolate->factory()->NewRawTwoByteString(result_len));
3860 }
3861
3862 for (int i = 0; i < matches; i++) {
3863 // Copy non-matched subject content.
3864 if (subject_pos < indices.at(i)) {
3865 String::WriteToFlat(*subject,
3866 result->GetChars() + result_pos,
3867 subject_pos,
3868 indices.at(i));
3869 result_pos += indices.at(i) - subject_pos;
3870 }
3871
3872 // Replace match.
3873 if (replacement_len > 0) {
3874 String::WriteToFlat(*replacement,
3875 result->GetChars() + result_pos,
3876 0,
3877 replacement_len);
3878 result_pos += replacement_len;
3879 }
3880
3881 subject_pos = indices.at(i) + pattern_len;
3882 }
3883 // Add remaining subject content at the end.
3884 if (subject_pos < subject_len) {
3885 String::WriteToFlat(*subject,
3886 result->GetChars() + result_pos,
3887 subject_pos,
3888 subject_len);
3889 }
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003890
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003891 int32_t match_indices[] = { indices.at(matches - 1),
3892 indices.at(matches - 1) + pattern_len };
3893 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003894
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003895 return *result;
3896}
3897
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003898
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003899MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003900 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003901 Handle<String> subject,
3902 Handle<JSRegExp> regexp,
3903 Handle<String> replacement,
3904 Handle<JSArray> last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003905 ASSERT(subject->IsFlat());
3906 ASSERT(replacement->IsFlat());
3907
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003908 int capture_count = regexp->CaptureCount();
3909 int subject_length = subject->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003910
3911 // CompiledReplacement uses zone allocation.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003912 ZoneScope zone_scope(isolate->runtime_zone());
3913 CompiledReplacement compiled_replacement(zone_scope.zone());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003914 bool simple_replace = compiled_replacement.Compile(replacement,
3915 capture_count,
3916 subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003917
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003918 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003919 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003920 if (subject->HasOnlyOneByteChars() &&
3921 replacement->HasOnlyOneByteChars()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003922 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003923 isolate, subject, regexp, replacement, last_match_info);
3924 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003925 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003926 isolate, subject, regexp, replacement, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003927 }
3928 }
3929
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003930 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003931 if (global_cache.HasException()) return Failure::Exception();
3932
3933 int32_t* current_match = global_cache.FetchNext();
3934 if (current_match == NULL) {
3935 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003936 return *subject;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003937 }
3938
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003939 // Guessing the number of parts that the final result string is built
3940 // from. Global regexps can match any number of times, so we guess
3941 // conservatively.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003942 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003943 ReplacementStringBuilder builder(isolate->heap(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003944 subject,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003946
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003947 // Number of parts added by compiled replacement plus preceeding
3948 // string and possibly suffix after last match. It is possible for
3949 // all components to use two elements when encoded as two smis.
3950 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003951
3952 int prev = 0;
3953
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003954 do {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003955 builder.EnsureCapacity(parts_added_per_loop);
3956
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003957 int start = current_match[0];
3958 int end = current_match[1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003959
3960 if (prev < start) {
3961 builder.AddSubjectSlice(prev, start);
3962 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00003963
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003964 if (simple_replace) {
3965 builder.AddString(replacement);
3966 } else {
3967 compiled_replacement.Apply(&builder,
3968 start,
3969 end,
3970 current_match);
3971 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003972 prev = end;
3973
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003974 current_match = global_cache.FetchNext();
3975 } while (current_match != NULL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003976
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003977 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003978
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003979 if (prev < subject_length) {
3980 builder.EnsureCapacity(2);
3981 builder.AddSubjectSlice(prev, subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003982 }
3983
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003984 RegExpImpl::SetLastMatchInfo(last_match_info,
3985 subject,
3986 capture_count,
3987 global_cache.LastSuccessfulMatch());
3988
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003989 return *(builder.ToString());
3990}
3991
3992
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003993template <typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003994MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003995 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003996 Handle<String> subject,
3997 Handle<JSRegExp> regexp,
3998 Handle<JSArray> last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003999 ASSERT(subject->IsFlat());
4000
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004001 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004002 if (regexp->TypeTag() == JSRegExp::ATOM) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004003 Handle<String> empty_string = isolate->factory()->empty_string();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004004 if (subject->IsOneByteRepresentation()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004005 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4006 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004007 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004008 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4009 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004010 }
4011 }
4012
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004013 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004014 if (global_cache.HasException()) return Failure::Exception();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004015
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004016 int32_t* current_match = global_cache.FetchNext();
4017 if (current_match == NULL) {
4018 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004019 return *subject;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004020 }
4021
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004022 int start = current_match[0];
4023 int end = current_match[1];
4024 int capture_count = regexp->CaptureCount();
4025 int subject_length = subject->length();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004026
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004027 int new_length = subject_length - (end - start);
4028 if (new_length == 0) return isolate->heap()->empty_string();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004029
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004030 Handle<ResultSeqString> answer;
4031 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 answer = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004033 isolate->factory()->NewRawOneByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004034 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 answer = Handle<ResultSeqString>::cast(
4036 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004037 }
4038
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004039 int prev = 0;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004040 int position = 0;
4041
4042 do {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004043 start = current_match[0];
4044 end = current_match[1];
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004045 if (prev < start) {
4046 // Add substring subject[prev;start] to answer string.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004047 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004048 position += start - prev;
4049 }
4050 prev = end;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004051
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004052 current_match = global_cache.FetchNext();
4053 } while (current_match != NULL);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004054
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004055 if (global_cache.HasException()) return Failure::Exception();
4056
4057 RegExpImpl::SetLastMatchInfo(last_match_info,
4058 subject,
4059 capture_count,
4060 global_cache.LastSuccessfulMatch());
4061
4062 if (prev < subject_length) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004063 // Add substring subject[prev;length] to answer string.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004064 String::WriteToFlat(
4065 *subject, answer->GetChars() + position, prev, subject_length);
4066 position += subject_length - prev;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004067 }
4068
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004069 if (position == 0) return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004070
4071 // Shorten string and fill
4072 int string_size = ResultSeqString::SizeFor(position);
4073 int allocated_string_size = ResultSeqString::SizeFor(new_length);
4074 int delta = allocated_string_size - string_size;
4075
4076 answer->set_length(position);
4077 if (delta == 0) return *answer;
4078
4079 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004082 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004084
4085 return *answer;
4086}
4087
4088
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004089RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004090 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004091 ASSERT(args.length() == 4);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004092
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004093 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4094 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4095 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4096 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004097
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004098 ASSERT(regexp->GetFlags().is_global());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004099
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004100 if (!subject->IsFlat()) subject = FlattenGetString(subject);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004101
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004102 if (replacement->length() == 0) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004103 if (subject->HasOnlyOneByteChars()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004104 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004105 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004106 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004107 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004108 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004109 }
4110 }
4111
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004112 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
4113
4114 return StringReplaceGlobalRegExpWithString(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004115 isolate, subject, regexp, replacement, last_match_info);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004116}
4117
4118
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004119Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
4120 Handle<String> subject,
4121 Handle<String> search,
4122 Handle<String> replace,
4123 bool* found,
4124 int recursion_limit) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004125 if (recursion_limit == 0) return Handle<String>::null();
4126 if (subject->IsConsString()) {
4127 ConsString* cons = ConsString::cast(*subject);
4128 Handle<String> first = Handle<String>(cons->first());
4129 Handle<String> second = Handle<String>(cons->second());
4130 Handle<String> new_first =
4131 StringReplaceOneCharWithString(isolate,
4132 first,
4133 search,
4134 replace,
4135 found,
4136 recursion_limit - 1);
4137 if (*found) return isolate->factory()->NewConsString(new_first, second);
4138 if (new_first.is_null()) return new_first;
4139
4140 Handle<String> new_second =
4141 StringReplaceOneCharWithString(isolate,
4142 second,
4143 search,
4144 replace,
4145 found,
4146 recursion_limit - 1);
4147 if (*found) return isolate->factory()->NewConsString(first, new_second);
4148 if (new_second.is_null()) return new_second;
4149
4150 return subject;
4151 } else {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004152 int index = Runtime::StringMatch(isolate, subject, search, 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004153 if (index == -1) return subject;
4154 *found = true;
4155 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4156 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
4157 Handle<String> second =
4158 isolate->factory()->NewSubString(subject, index + 1, subject->length());
4159 return isolate->factory()->NewConsString(cons1, second);
4160 }
4161}
4162
4163
4164RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004165 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004166 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004167 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4168 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4169 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004170
4171 // If the cons string tree is too deep, we simply abort the recursion and
4172 // retry with a flattened subject string.
4173 const int kRecursionLimit = 0x1000;
4174 bool found = false;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004175 Handle<String> result = StringReplaceOneCharWithString(isolate,
4176 subject,
4177 search,
4178 replace,
4179 &found,
4180 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004181 if (!result.is_null()) return *result;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004182 return *StringReplaceOneCharWithString(isolate,
4183 FlattenGetString(subject),
4184 search,
4185 replace,
4186 &found,
4187 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004188}
4189
4190
ager@chromium.org7c537e22008-10-16 08:43:32 +00004191// Perform string match of pattern on subject, starting at start index.
4192// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004193// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004194int Runtime::StringMatch(Isolate* isolate,
4195 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00004196 Handle<String> pat,
4197 int start_index) {
4198 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004199 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004200
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004201 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004202 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004204 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004205 if (start_index + pattern_length > subject_length) return -1;
4206
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004207 if (!sub->IsFlat()) FlattenString(sub);
4208 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00004209
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004210 DisallowHeapAllocation no_gc; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00004211 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004212 String::FlatContent seq_sub = sub->GetFlatContent();
4213 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00004214
ager@chromium.org7c537e22008-10-16 08:43:32 +00004215 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004216 if (seq_pat.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004217 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004218 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004219 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004220 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004221 pat_vector,
4222 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00004223 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004224 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004225 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226 pat_vector,
4227 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00004228 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004229 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4230 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004232 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004233 pat_vector,
4234 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004236 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004237 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004238 pat_vector,
4239 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004240}
4241
4242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004244 HandleScope scope(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004245 ASSERT(args.length() == 3);
4246
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004247 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4248 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004249
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004250 Object* index = args[2];
4251 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004252 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004253
ager@chromium.org870a0b62008-11-04 11:43:05 +00004254 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255 int position =
4256 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004257 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004258}
4259
4260
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004261template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004262static int StringMatchBackwards(Vector<const schar> subject,
4263 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004264 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004265 int pattern_length = pattern.length();
4266 ASSERT(pattern_length >= 1);
4267 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004268
4269 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004270 for (int i = 0; i < pattern_length; i++) {
4271 uc16 c = pattern[i];
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004272 if (c > String::kMaxOneByteCharCode) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004273 return -1;
4274 }
4275 }
4276 }
4277
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004278 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004279 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004280 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004281 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004282 while (j < pattern_length) {
4283 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004284 break;
4285 }
4286 j++;
4287 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004288 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004289 return i;
4290 }
4291 }
4292 return -1;
4293}
4294
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004296RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004297 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004298 ASSERT(args.length() == 3);
4299
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004300 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4301 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004303 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004305 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004307 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004308 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004309
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004310 if (start_index + pat_length > sub_length) {
4311 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004313
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004314 if (pat_length == 0) {
4315 return Smi::FromInt(start_index);
4316 }
4317
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004318 if (!sub->IsFlat()) FlattenString(sub);
4319 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004320
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004321 int position = -1;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004322 DisallowHeapAllocation no_gc; // ensure vectors stay valid
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004323
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004324 String::FlatContent sub_content = sub->GetFlatContent();
4325 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004326
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004327 if (pat_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004328 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004329 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004330 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004331 pat_vector,
4332 start_index);
4333 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004334 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004335 pat_vector,
4336 start_index);
4337 }
4338 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004339 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4340 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004341 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004342 pat_vector,
4343 start_index);
4344 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004345 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004346 pat_vector,
4347 start_index);
4348 }
4349 }
4350
4351 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352}
4353
4354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004355RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004356 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004357 ASSERT(args.length() == 2);
4358
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004359 CONVERT_ARG_CHECKED(String, str1, 0);
4360 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361
4362 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004363 int str1_length = str1->length();
4364 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365
4366 // Decide trivial cases without flattening.
4367 if (str1_length == 0) {
4368 if (str2_length == 0) return Smi::FromInt(0); // Equal.
4369 return Smi::FromInt(-str2_length);
4370 } else {
4371 if (str2_length == 0) return Smi::FromInt(str1_length);
4372 }
4373
4374 int end = str1_length < str2_length ? str1_length : str2_length;
4375
4376 // No need to flatten if we are going to find the answer on the first
4377 // character. At this point we know there is at least one character
4378 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004379 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380 if (d != 0) return Smi::FromInt(d);
4381
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004382 str1->TryFlatten();
4383 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00004385 ConsStringIteratorOp* op1 =
4386 isolate->runtime_state()->string_locale_compare_it1();
4387 ConsStringIteratorOp* op2 =
4388 isolate->runtime_state()->string_locale_compare_it2();
4389 // TODO(dcarney) Can do array compares here more efficiently.
4390 StringCharacterStream stream1(str1, op1);
4391 StringCharacterStream stream2(str2, op2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392
4393 for (int i = 0; i < end; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00004394 uint16_t char1 = stream1.GetNext();
4395 uint16_t char2 = stream2.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 if (char1 != char2) return Smi::FromInt(char1 - char2);
4397 }
4398
4399 return Smi::FromInt(str1_length - str2_length);
4400}
4401
4402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004403RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004404 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004405 ASSERT(args.length() == 3);
4406
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004407 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004408 int start, end;
4409 // We have a fast integer-only case here to avoid a conversion to double in
4410 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004411 if (args[1]->IsSmi() && args[2]->IsSmi()) {
4412 CONVERT_SMI_ARG_CHECKED(from_number, 1);
4413 CONVERT_SMI_ARG_CHECKED(to_number, 2);
4414 start = from_number;
4415 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004416 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004417 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4418 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004419 start = FastD2IChecked(from_number);
4420 end = FastD2IChecked(to_number);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 RUNTIME_ASSERT(end >= start);
4423 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004424 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 isolate->counters()->sub_string_runtime()->Increment();
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004426 if (end - start == 1) {
4427 return isolate->heap()->LookupSingleCharacterStringFromCode(
4428 value->Get(start));
4429 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004430 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431}
4432
4433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004434RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004435 HandleScope handles(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00004436 ASSERT_EQ(3, args.length());
4437
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004438 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4439 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4440 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00004441
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004442 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4443 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.org41826e72009-03-30 13:30:57 +00004444
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004445 int capture_count = regexp->CaptureCount();
ager@chromium.org41826e72009-03-30 13:30:57 +00004446
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00004447 ZoneScope zone_scope(isolate->runtime_zone());
4448 ZoneList<int> offsets(8, zone_scope.zone());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004449
4450 while (true) {
4451 int32_t* match = global_cache.FetchNext();
4452 if (match == NULL) break;
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00004453 offsets.Add(match[0], zone_scope.zone()); // start
4454 offsets.Add(match[1], zone_scope.zone()); // end
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004455 }
4456
4457 if (global_cache.HasException()) return Failure::Exception();
4458
4459 if (offsets.length() == 0) {
4460 // Not a single match.
4461 return isolate->heap()->null_value();
4462 }
4463
4464 RegExpImpl::SetLastMatchInfo(regexp_info,
4465 subject,
4466 capture_count,
4467 global_cache.LastSuccessfulMatch());
4468
ager@chromium.org41826e72009-03-30 13:30:57 +00004469 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004470 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004471 Handle<String> substring =
4472 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
ager@chromium.org04921a82011-06-27 13:21:41 +00004473 elements->set(0, *substring);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004474 for (int i = 1; i < matches; i++) {
4475 HandleScope temp_scope(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00004476 int from = offsets.at(i * 2);
4477 int to = offsets.at(i * 2 + 1);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004478 Handle<String> substring =
4479 isolate->factory()->NewProperSubString(subject, from, to);
ager@chromium.org04921a82011-06-27 13:21:41 +00004480 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00004481 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00004483 result->set_length(Smi::FromInt(matches));
4484 return *result;
4485}
4486
4487
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004488// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4489// separate last match info. See comment on that function.
4490template<bool has_capture>
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004491static MaybeObject* SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004493 Handle<String> subject,
4494 Handle<JSRegExp> regexp,
4495 Handle<JSArray> last_match_array,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004496 Handle<JSArray> result_array) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004497 ASSERT(subject->IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004498 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004499
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004500 int capture_count = regexp->CaptureCount();
4501 int subject_length = subject->length();
4502
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004503 static const int kMinLengthToCache = 0x1000;
4504
4505 if (subject_length > kMinLengthToCache) {
4506 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4507 isolate->heap(),
4508 *subject,
4509 regexp->data(),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004510 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004511 if (*cached_answer != Smi::FromInt(0)) {
4512 Handle<FixedArray> cached_fixed_array =
4513 Handle<FixedArray>(FixedArray::cast(*cached_answer));
4514 // The cache FixedArray is a COW-array and can therefore be reused.
4515 isolate->factory()->SetContent(result_array, cached_fixed_array);
4516 // The actual length of the result array is stored in the last element of
4517 // the backing store (the backing FixedArray may have a larger capacity).
4518 Object* cached_fixed_array_last_element =
4519 cached_fixed_array->get(cached_fixed_array->length() - 1);
4520 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4521 result_array->set_length(js_array_length);
4522 RegExpImpl::SetLastMatchInfo(
4523 last_match_array, subject, capture_count, NULL);
4524 return *result_array;
4525 }
4526 }
4527
4528 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4529 if (global_cache.HasException()) return Failure::Exception();
4530
4531 Handle<FixedArray> result_elements;
4532 if (result_array->HasFastObjectElements()) {
4533 result_elements =
4534 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4535 }
4536 if (result_elements.is_null() || result_elements->length() < 16) {
4537 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4538 }
4539
4540 FixedArrayBuilder builder(result_elements);
4541
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004542 // Position to search from.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004543 int match_start = -1;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004544 int match_end = 0;
4545 bool first = true;
4546
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004547 // Two smis before and after the match, for very long strings.
4548 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004549
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004550 while (true) {
4551 int32_t* current_match = global_cache.FetchNext();
4552 if (current_match == NULL) break;
4553 match_start = current_match[0];
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004554 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004555 if (match_end < match_start) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004556 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004557 match_end,
4558 match_start);
4559 }
4560 match_end = current_match[1];
4561 {
4562 // Avoid accumulating new handles inside loop.
4563 HandleScope temp_scope(isolate);
4564 Handle<String> match;
4565 if (!first) {
4566 match = isolate->factory()->NewProperSubString(subject,
4567 match_start,
4568 match_end);
4569 } else {
4570 match = isolate->factory()->NewSubString(subject,
4571 match_start,
4572 match_end);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004573 first = false;
4574 }
4575
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004576 if (has_capture) {
4577 // Arguments array to replace function is match, captures, index and
4578 // subject, i.e., 3 + capture count in total.
4579 Handle<FixedArray> elements =
4580 isolate->factory()->NewFixedArray(3 + capture_count);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004581
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004582 elements->set(0, *match);
4583 for (int i = 1; i <= capture_count; i++) {
4584 int start = current_match[i * 2];
4585 if (start >= 0) {
4586 int end = current_match[i * 2 + 1];
4587 ASSERT(start <= end);
4588 Handle<String> substring =
4589 isolate->factory()->NewSubString(subject, start, end);
4590 elements->set(i, *substring);
4591 } else {
4592 ASSERT(current_match[i * 2 + 1] < 0);
4593 elements->set(i, isolate->heap()->undefined_value());
4594 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004595 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004596 elements->set(capture_count + 1, Smi::FromInt(match_start));
4597 elements->set(capture_count + 2, *subject);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004598 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004599 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004600 builder.Add(*match);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004601 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004602 }
4603 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004604
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004605 if (global_cache.HasException()) return Failure::Exception();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004606
4607 if (match_start >= 0) {
4608 // Finished matching, with at least one match.
4609 if (match_end < subject_length) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004610 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004611 match_end,
4612 subject_length);
4613 }
4614
4615 RegExpImpl::SetLastMatchInfo(
4616 last_match_array, subject, capture_count, NULL);
4617
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004618 if (subject_length > kMinLengthToCache) {
4619 // Store the length of the result array into the last element of the
4620 // backing FixedArray.
4621 builder.EnsureCapacity(1);
4622 Handle<FixedArray> fixed_array = builder.array();
4623 fixed_array->set(fixed_array->length() - 1,
4624 Smi::FromInt(builder.length()));
4625 // Cache the result and turn the FixedArray into a COW array.
4626 RegExpResultsCache::Enter(isolate->heap(),
4627 *subject,
4628 regexp->data(),
4629 *fixed_array,
4630 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4631 }
4632 return *builder.ToJSArray(result_array);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004633 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004634 return isolate->heap()->null_value(); // No matches at all.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004635 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004636}
4637
4638
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004639// This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4640// lastMatchInfoOverride to maintain the last match info, so we don't need to
4641// set any other last match array info.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004642RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004643 HandleScope handles(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004644 ASSERT(args.length() == 4);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004645
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004646 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004647 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004648 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4649 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4650 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004651
lrn@chromium.org25156de2010-04-06 13:10:27 +00004652 ASSERT(regexp->GetFlags().is_global());
lrn@chromium.org25156de2010-04-06 13:10:27 +00004653
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004654 if (regexp->CaptureCount() == 0) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004655 return SearchRegExpMultiple<false>(
4656 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004657 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004658 return SearchRegExpMultiple<true>(
4659 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004660 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00004661}
4662
4663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004664RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004665 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004667 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004668 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004670 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004671 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004672 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004673 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004674 // Character array used for conversion.
4675 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return isolate->heap()->
4677 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004678 }
4679 }
4680
4681 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004682 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004683 if (std::isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004684 return *isolate->factory()->nan_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004686 if (std::isinf(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 if (value < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004688 return *isolate->factory()->minus_infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004690 return *isolate->factory()->infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004693 MaybeObject* result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004694 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 DeleteArray(str);
4696 return result;
4697}
4698
4699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004700RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004701 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 ASSERT(args.length() == 2);
4703
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004704 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004705 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004706 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 RUNTIME_ASSERT(f >= 0);
4708 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004710 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713}
4714
4715
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004716RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004717 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 ASSERT(args.length() == 2);
4719
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004720 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004721 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004722 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723 RUNTIME_ASSERT(f >= -1 && f <= 20);
4724 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004725 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004726 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004728 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729}
4730
4731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004733 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734 ASSERT(args.length() == 2);
4735
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004736 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004737 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004738 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 RUNTIME_ASSERT(f >= 1 && f <= 21);
4740 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004741 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004742 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004743 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004744 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745}
4746
4747
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004748RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) {
4749 HandleScope shs(isolate);
4750 ASSERT(args.length() == 1);
4751
4752 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4753 if (Smi::IsValid(number)) {
4754 return isolate->heap()->true_value();
4755 } else {
4756 return isolate->heap()->false_value();
4757 }
4758}
4759
4760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761// Returns a single character string where first character equals
4762// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004763static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004764 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004765 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004766 return LookupSingleCharacterStringFromCode(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004767 string->GetIsolate(),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004768 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004770 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771}
4772
4773
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004774MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate,
4775 Handle<Object> object,
4776 uint32_t index) {
4777 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4778 GetElementOrCharAt(isolate, object, index));
4779}
4780
4781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004782MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4783 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004784 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 // Handle [] indexing on Strings
4786 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004787 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4788 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789 }
4790
4791 // Handle [] indexing on String objects
4792 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004793 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4794 Handle<Object> result =
4795 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4796 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 }
4798
4799 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004800 return object->GetPrototype(isolate)->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 }
4802
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004803 return object->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804}
4805
4806
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004807MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
4808 Handle<JSReceiver> object,
4809 Handle<Object> key) {
4810 HandleScope scope(isolate);
4811
4812 // Check if the given key is an array index.
4813 uint32_t index;
4814 if (key->ToArrayIndex(&index)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004815 return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004816 }
4817
4818 // Convert the key to a name - possibly by calling back into JavaScript.
4819 Handle<Name> name;
4820 if (key->IsName()) {
4821 name = Handle<Name>::cast(key);
4822 } else {
4823 bool has_pending_exception = false;
4824 Handle<Object> converted =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00004825 Execution::ToString(isolate, key, &has_pending_exception);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004826 if (has_pending_exception) return Failure::Exception();
4827 name = Handle<Name>::cast(converted);
4828 }
4829
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004830 return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004831}
4832
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00004833MaybeObject* Runtime::GetObjectPropertyOrFail(
4834 Isolate* isolate,
4835 Handle<Object> object,
4836 Handle<Object> key) {
4837 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4838 GetObjectProperty(isolate, object, key));
4839}
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004840
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4842 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004843 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004844 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004847 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004849 isolate->factory()->NewTypeError("non_object_property_load",
4850 HandleVector(args, 2));
4851 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 }
4853
4854 // Check if the given key is an array index.
4855 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004856 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 }
4859
ulan@chromium.org750145a2013-03-07 15:14:13 +00004860 // Convert the key to a name - possibly by calling back into JavaScript.
4861 Handle<Name> name;
4862 if (key->IsName()) {
4863 name = Handle<Name>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 bool has_pending_exception = false;
4866 Handle<Object> converted =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00004867 Execution::ToString(isolate, key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868 if (has_pending_exception) return Failure::Exception();
ulan@chromium.org750145a2013-03-07 15:14:13 +00004869 name = Handle<Name>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 }
4871
ager@chromium.org32912102009-01-16 10:38:43 +00004872 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 // the element if so.
4874 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004877 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 }
4879}
4880
4881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004882RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004883 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884 ASSERT(args.length() == 2);
4885
4886 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004887 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890}
4891
4892
ulan@chromium.org750145a2013-03-07 15:14:13 +00004893// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004894RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004895 SealHandleScope shs(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004896 ASSERT(args.length() == 2);
4897
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004898 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004899 // itself.
4900 //
4901 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004902 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004903 // global proxy object never has properties. This is the case
4904 // because the global proxy object forwards everything to its hidden
4905 // prototype including local lookups.
4906 //
4907 // Additionally, we need to make sure that we do not cache results
4908 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004909 if (args[0]->IsJSObject()) {
4910 if (!args[0]->IsJSGlobalProxy() &&
4911 !args[0]->IsAccessCheckNeeded() &&
ulan@chromium.org750145a2013-03-07 15:14:13 +00004912 args[1]->IsName()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004913 JSObject* receiver = JSObject::cast(args[0]);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004914 Name* key = Name::cast(args[1]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004915 if (receiver->HasFastProperties()) {
4916 // Attempt to use lookup cache.
4917 Map* receiver_map = receiver->map();
4918 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4919 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4920 if (offset != -1) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004921 // Doubles are not cached, so raw read the value.
4922 Object* value = receiver->RawFastPropertyAt(offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004923 return value->IsTheHole()
4924 ? isolate->heap()->undefined_value()
4925 : value;
4926 }
4927 // Lookup cache miss. Perform lookup and update the cache if
4928 // appropriate.
4929 LookupResult result(isolate);
4930 receiver->LocalLookup(key, &result);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00004931 if (result.IsField()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004932 int offset = result.GetFieldIndex().field_index();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004933 // Do not track double fields in the keyed lookup cache. Reading
4934 // double values requires boxing.
4935 if (!FLAG_track_double_fields ||
4936 !result.representation().IsDouble()) {
4937 keyed_lookup_cache->Update(receiver_map, key, offset);
4938 }
4939 return receiver->FastPropertyAt(result.representation(), offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004940 }
4941 } else {
4942 // Attempt dictionary lookup.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004943 NameDictionary* dictionary = receiver->property_dictionary();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004944 int entry = dictionary->FindEntry(key);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004945 if ((entry != NameDictionary::kNotFound) &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004946 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4947 Object* value = dictionary->ValueAt(entry);
4948 if (!receiver->IsGlobalObject()) return value;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004949 value = PropertyCell::cast(value)->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004950 if (!value->IsTheHole()) return value;
4951 // If value is the hole do the general lookup.
4952 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004953 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004954 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004955 // JSObject without a name key. If the key is a Smi, check for a
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004956 // definite out-of-bounds access to elements, which is a strong indicator
4957 // that subsequent accesses will also call the runtime. Proactively
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004958 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004959 // doubles for those future calls in the case that the elements would
4960 // become FAST_DOUBLE_ELEMENTS.
4961 Handle<JSObject> js_object(args.at<JSObject>(0));
4962 ElementsKind elements_kind = js_object->GetElementsKind();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004963 if (IsFastDoubleElementsKind(elements_kind)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004964 FixedArrayBase* elements = js_object->elements();
4965 if (args.at<Smi>(1)->value() >= elements->length()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004966 if (IsFastHoleyElementsKind(elements_kind)) {
4967 elements_kind = FAST_HOLEY_ELEMENTS;
4968 } else {
4969 elements_kind = FAST_ELEMENTS;
4970 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004971 MaybeObject* maybe_object = TransitionElements(js_object,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004972 elements_kind,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004973 isolate);
4974 if (maybe_object->IsFailure()) return maybe_object;
4975 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004976 } else {
4977 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
4978 !IsFastElementsKind(elements_kind));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004979 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004980 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004981 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4982 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004983 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004984 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004985 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004986 if (index >= 0 && index < str->length()) {
4987 Handle<Object> result = GetCharAt(str, index);
4988 return *result;
4989 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004990 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004991
4992 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004993 return Runtime::GetObjectProperty(isolate,
4994 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004995 args.at<Object>(1));
4996}
4997
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004998
4999static bool IsValidAccessor(Handle<Object> obj) {
5000 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
5001}
5002
5003
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005004// Implements part of 8.12.9 DefineOwnProperty.
5005// There are 3 cases that lead here:
5006// Step 4b - define a new accessor property.
5007// Steps 9c & 12 - replace an existing data property with an accessor property.
5008// Step 12 - update an existing accessor property with an accessor or generic
5009// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005010RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005011 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005012 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005013 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005014 RUNTIME_ASSERT(!obj->IsNull());
ulan@chromium.org750145a2013-03-07 15:14:13 +00005015 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005016 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
5017 RUNTIME_ASSERT(IsValidAccessor(getter));
5018 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
5019 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005020 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00005021 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00005022 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005023
danno@chromium.org88aa0582012-03-23 15:11:57 +00005024 bool fast = obj->HasFastProperties();
5025 JSObject::DefineAccessor(obj, name, getter, setter, attr);
danno@chromium.org169691d2013-07-15 08:01:13 +00005026 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005027 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005028 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00005029}
5030
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00005031
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005032// Implements part of 8.12.9 DefineOwnProperty.
5033// There are 3 cases that lead here:
5034// Step 4a - define a new data property.
5035// Steps 9b & 12 - replace an existing accessor property with a data property.
5036// Step 12 - update an existing data property with a data or generic
5037// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005038RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005040 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005041 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005042 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005043 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005044 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00005045 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00005046 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5047
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005048 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00005049 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00005050
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005051 // Special case for callback properties.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005052 if (result.IsPropertyCallbacks()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005053 Object* callback = result.GetCallbackObject();
5054 // To be compatible with Safari we do not change the value on API objects
5055 // in Object.defineProperty(). Firefox disagrees here, and actually changes
5056 // the value.
5057 if (callback->IsAccessorInfo()) {
5058 return isolate->heap()->undefined_value();
5059 }
5060 // Avoid redefining foreign callback as data property, just use the stored
5061 // setter to update the value instead.
5062 // TODO(mstarzinger): So far this only works if property attributes don't
5063 // change, this should be fixed once we cleanup the underlying code.
5064 if (callback->IsForeign() && result.GetAttributes() == attr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005065 Handle<Object> result_object =
5066 JSObject::SetPropertyWithCallback(js_object,
5067 handle(callback, isolate),
5068 name,
5069 obj_value,
5070 handle(result.holder()),
5071 kStrictMode);
5072 RETURN_IF_EMPTY_HANDLE(isolate, result_object);
5073 return *result_object;
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005074 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00005075 }
5076
ager@chromium.org5c838252010-02-19 08:53:10 +00005077 // Take special care when attributes are different and there is already
5078 // a property. For simplicity we normalize the property which enables us
5079 // to not worry about changing the instance_descriptor and creating a new
5080 // map. The current version of SetObjectProperty does not handle attributes
5081 // correctly in the case where a property is a field and is reset with
5082 // new attributes.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005083 if (result.IsFound() &&
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005084 (attr != result.GetAttributes() || result.IsPropertyCallbacks())) {
ager@chromium.org5c838252010-02-19 08:53:10 +00005085 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005086 if (js_object->IsJSGlobalProxy()) {
5087 // Since the result is a property, the prototype will exist so
5088 // we don't have to check for null.
5089 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005090 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005091 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00005092 // Use IgnoreAttributes version since a readonly property may be
5093 // overridden and SetProperty does not allow this.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005094 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5095 js_object, name, obj_value, attr);
5096 RETURN_IF_EMPTY_HANDLE(isolate, result);
5097 return *result;
ager@chromium.org5c838252010-02-19 08:53:10 +00005098 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00005099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100 return Runtime::ForceSetObjectProperty(isolate,
5101 js_object,
5102 name,
5103 obj_value,
5104 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00005105}
5106
5107
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005108// Return property without being observable by accessors or interceptors.
5109RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005110 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005111 ASSERT(args.length() == 2);
5112 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005113 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005114 LookupResult lookup(isolate);
5115 object->LookupRealNamedProperty(*key, &lookup);
5116 if (!lookup.IsFound()) return isolate->heap()->undefined_value();
5117 switch (lookup.type()) {
5118 case NORMAL:
5119 return lookup.holder()->GetNormalizedProperty(&lookup);
5120 case FIELD:
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005121 return lookup.holder()->FastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005122 lookup.representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005123 lookup.GetFieldIndex().field_index());
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00005124 case CONSTANT:
5125 return lookup.GetConstant();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005126 case CALLBACKS:
5127 case HANDLER:
5128 case INTERCEPTOR:
5129 case TRANSITION:
5130 return isolate->heap()->undefined_value();
5131 case NONEXISTENT:
5132 UNREACHABLE();
5133 }
5134 return isolate->heap()->undefined_value();
5135}
5136
5137
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00005138MaybeObject* Runtime::SetObjectPropertyOrFail(
5139 Isolate* isolate,
5140 Handle<Object> object,
5141 Handle<Object> key,
5142 Handle<Object> value,
5143 PropertyAttributes attr,
5144 StrictModeFlag strict_mode) {
5145 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
5146 SetObjectProperty(isolate, object, key, value, attr, strict_mode));
5147}
5148
5149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005150MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
5151 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005152 Handle<Object> key,
5153 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005154 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005155 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005156 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005157 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005159 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005160 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005162 isolate->factory()->NewTypeError("non_object_property_store",
5163 HandleVector(args, 2));
5164 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005165 }
5166
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005167 if (object->IsJSProxy()) {
5168 bool has_pending_exception = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005169 Handle<Object> name_object = key->IsSymbol()
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005170 ? key : Execution::ToString(isolate, key, &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005171 if (has_pending_exception) return Failure::Exception();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005172 Handle<Name> name = Handle<Name>::cast(name_object);
5173 Handle<Object> result = JSReceiver::SetProperty(
5174 Handle<JSProxy>::cast(object), name, value, attr, strict_mode);
5175 RETURN_IF_EMPTY_HANDLE(isolate, result);
5176 return *result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005177 }
5178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179 // If the object isn't a JavaScript object, we ignore the store.
5180 if (!object->IsJSObject()) return *value;
5181
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005182 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
5183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184 // Check if the given key is an array index.
5185 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005186 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5188 // of a string using [] notation. We need to support this too in
5189 // JavaScript.
5190 // In the case of a String object we just need to redirect the assignment to
5191 // the underlying string if the index is in range. Since the underlying
5192 // string does nothing with the assignment then we can ignore such
5193 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005194 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005198 js_object->ValidateElements();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005199 if (js_object->HasExternalArrayElements()) {
5200 if (!value->IsNumber() && !value->IsUndefined()) {
5201 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005202 Handle<Object> number =
5203 Execution::ToNumber(isolate, value, &has_exception);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005204 if (has_exception) return Failure::Exception();
5205 value = number;
5206 }
5207 }
5208 MaybeObject* result = js_object->SetElement(
5209 index, *value, attr, strict_mode, true, set_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005210 js_object->ValidateElements();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005211 if (result->IsFailure()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 return *value;
5213 }
5214
ulan@chromium.org750145a2013-03-07 15:14:13 +00005215 if (key->IsName()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005216 Handle<Name> name = Handle<Name>::cast(key);
5217 if (name->AsArrayIndex(&index)) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005218 if (js_object->HasExternalArrayElements()) {
5219 if (!value->IsNumber() && !value->IsUndefined()) {
5220 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005221 Handle<Object> number =
5222 Execution::ToNumber(isolate, value, &has_exception);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005223 if (has_exception) return Failure::Exception();
5224 value = number;
5225 }
5226 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005227 MaybeObject* result = js_object->SetElement(
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005228 index, *value, attr, strict_mode, true, set_mode);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005229 if (result->IsFailure()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005231 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005232 Handle<Object> result =
5233 JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5234 RETURN_IF_EMPTY_HANDLE(isolate, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236 return *value;
5237 }
5238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005241 Handle<Object> converted =
5242 Execution::ToString(isolate, key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 if (has_pending_exception) return Failure::Exception();
5244 Handle<String> name = Handle<String>::cast(converted);
5245
5246 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005247 return js_object->SetElement(
5248 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005250 Handle<Object> result =
5251 JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
5252 RETURN_IF_EMPTY_HANDLE(isolate, result);
5253 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 }
5255}
5256
5257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
5259 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 Handle<Object> key,
5261 Handle<Object> value,
5262 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005264
5265 // Check if the given key is an array index.
5266 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005267 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005268 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5269 // of a string using [] notation. We need to support this too in
5270 // JavaScript.
5271 // In the case of a String object we just need to redirect the assignment to
5272 // the underlying string if the index is in range. Since the underlying
5273 // string does nothing with the assignment then we can ignore such
5274 // assignments.
5275 if (js_object->IsStringObjectWithCharacterAt(index)) {
5276 return *value;
5277 }
5278
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005279 return js_object->SetElement(
5280 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005281 }
5282
ulan@chromium.org750145a2013-03-07 15:14:13 +00005283 if (key->IsName()) {
5284 Handle<Name> name = Handle<Name>::cast(key);
5285 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005286 return js_object->SetElement(
5287 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005288 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005289 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005290 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5291 js_object, name, value, attr);
5292 RETURN_IF_EMPTY_HANDLE(isolate, result);
5293 return *result;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005294 }
5295 }
5296
5297 // Call-back into JavaScript to convert the key to a string.
5298 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005299 Handle<Object> converted =
5300 Execution::ToString(isolate, key, &has_pending_exception);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005301 if (has_pending_exception) return Failure::Exception();
5302 Handle<String> name = Handle<String>::cast(converted);
5303
5304 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005305 return js_object->SetElement(
5306 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005307 } else {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005308 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5309 js_object, name, value, attr);
5310 RETURN_IF_EMPTY_HANDLE(isolate, result);
5311 return *result;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005312 }
5313}
5314
5315
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005316MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
5317 Handle<JSReceiver> receiver,
5318 Handle<Object> key,
5319 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005321
5322 // Check if the given key is an array index.
5323 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005324 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00005325 // In Firefox/SpiderMonkey, Safari and Opera you can access the
5326 // characters of a string using [] notation. In the case of a
5327 // String object we just need to redirect the deletion to the
5328 // underlying string if the index is in range. Since the
5329 // underlying string does nothing with the deletion, we can ignore
5330 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00005331 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005332 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00005333 }
5334
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005335 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode);
5336 RETURN_IF_EMPTY_HANDLE(isolate, result);
5337 return *result;
ager@chromium.orge2902be2009-06-08 12:21:35 +00005338 }
5339
ulan@chromium.org750145a2013-03-07 15:14:13 +00005340 Handle<Name> name;
5341 if (key->IsName()) {
5342 name = Handle<Name>::cast(key);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005343 } else {
5344 // Call-back into JavaScript to convert the key to a string.
5345 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005346 Handle<Object> converted = Execution::ToString(
5347 isolate, key, &has_pending_exception);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005348 if (has_pending_exception) return Failure::Exception();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005349 name = Handle<String>::cast(converted);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005350 }
5351
ulan@chromium.org750145a2013-03-07 15:14:13 +00005352 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005353 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode);
5354 RETURN_IF_EMPTY_HANDLE(isolate, result);
5355 return *result;
ager@chromium.orge2902be2009-06-08 12:21:35 +00005356}
5357
5358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005359RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005360 SealHandleScope shs(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005361 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005362
5363 Handle<Object> object = args.at<Object>(0);
5364 Handle<Object> key = args.at<Object>(1);
5365 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005366 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005367 RUNTIME_ASSERT(
5368 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005370 PropertyAttributes attributes =
5371 static_cast<PropertyAttributes>(unchecked_attributes);
5372
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005373 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005374 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005375 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005376 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005377 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 return Runtime::SetObjectProperty(isolate,
5380 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005381 key,
5382 value,
5383 attributes,
5384 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385}
5386
5387
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005388RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) {
5389 HandleScope scope(isolate);
5390 RUNTIME_ASSERT(args.length() == 2);
5391 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
5392 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
5393 JSObject::TransitionElementsKind(array, map->elements_kind());
5394 return *array;
5395}
5396
5397
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005398// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005399// This is used to decide if we should transform null and undefined
5400// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005401RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005402 SealHandleScope shs(isolate);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005403 RUNTIME_ASSERT(args.length() == 1);
5404
5405 Handle<Object> object = args.at<Object>(0);
5406
5407 if (object->IsJSFunction()) {
5408 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005409 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005410 }
5411 return isolate->heap()->undefined_value();
5412}
5413
5414
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005415RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005416 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005417 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005418 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005419 CONVERT_SMI_ARG_CHECKED(store_index, 1);
5420 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005421 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005422 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005423
danno@chromium.orgbee51992013-07-10 14:57:15 +00005424 Object* raw_literal_cell = literals->get(literal_index);
5425 JSArray* boilerplate = NULL;
5426 if (raw_literal_cell->IsAllocationSite()) {
5427 AllocationSite* site = AllocationSite::cast(raw_literal_cell);
5428 boilerplate = JSArray::cast(site->transition_info());
5429 } else {
5430 boilerplate = JSArray::cast(raw_literal_cell);
5431 }
5432 Handle<JSArray> boilerplate_object(boilerplate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005433 ElementsKind elements_kind = object->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005434 ASSERT(IsFastElementsKind(elements_kind));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005435 // Smis should never trigger transitions.
5436 ASSERT(!value->IsSmi());
5437
5438 if (value->IsNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005439 ASSERT(IsFastSmiElementsKind(elements_kind));
5440 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5441 ? FAST_HOLEY_DOUBLE_ELEMENTS
5442 : FAST_DOUBLE_ELEMENTS;
5443 if (IsMoreGeneralElementsKindTransition(
5444 boilerplate_object->GetElementsKind(),
5445 transitioned_kind)) {
5446 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005447 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005448 JSObject::TransitionElementsKind(object, transitioned_kind);
5449 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005450 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005451 HeapNumber* number = HeapNumber::cast(*value);
5452 double_array->set(store_index, number->Number());
5453 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005454 ASSERT(IsFastSmiElementsKind(elements_kind) ||
5455 IsFastDoubleElementsKind(elements_kind));
5456 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5457 ? FAST_HOLEY_ELEMENTS
5458 : FAST_ELEMENTS;
5459 JSObject::TransitionElementsKind(object, transitioned_kind);
5460 if (IsMoreGeneralElementsKindTransition(
5461 boilerplate_object->GetElementsKind(),
5462 transitioned_kind)) {
5463 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005464 }
5465 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005466 object_array->set(store_index, *value);
5467 }
5468 return *object;
5469}
5470
5471
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005472// Check whether debugger and is about to step into the callback that is passed
5473// to a built-in function such as Array.forEach.
5474RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005475 SealHandleScope shs(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005476#ifdef ENABLE_DEBUGGER_SUPPORT
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005477 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
5478 return isolate->heap()->false_value();
5479 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005480 CONVERT_ARG_CHECKED(Object, callback, 0);
5481 // We do not step into the callback if it's a builtin or not even a function.
5482 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
5483 return isolate->heap()->false_value();
5484 }
5485 return isolate->heap()->true_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005486#else
5487 return isolate->heap()->false_value();
5488#endif // ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005489}
5490
5491
5492// Set one shot breakpoints for the callback function that is passed to a
5493// built-in function such as Array.forEach to enable stepping into the callback.
5494RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005495 SealHandleScope shs(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005496#ifdef ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005497 Debug* debug = isolate->debug();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005498 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005499 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005500 HandleScope scope(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005501 // When leaving the callback, step out has been activated, but not performed
5502 // if we do not leave the builtin. To be able to step into the callback
5503 // again, we need to clear the step out at this point.
5504 debug->ClearStepOut();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005505 debug->FloodWithOneShot(callback);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005506#endif // ENABLE_DEBUGGER_SUPPORT
5507 return isolate->heap()->undefined_value();
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005508}
5509
5510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511// Set a local property, even if it is READ_ONLY. If the property does not
5512// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005513RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005514 HandleScope scope(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005515 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005516 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5517 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5518 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005519 // Compute attributes.
5520 PropertyAttributes attributes = NONE;
5521 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005522 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005523 // Only attribute bits should be set.
5524 RUNTIME_ASSERT(
5525 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5526 attributes = static_cast<PropertyAttributes>(unchecked_value);
5527 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005528 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5529 object, name, value, attributes);
5530 RETURN_IF_EMPTY_HANDLE(isolate, result);
5531 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532}
5533
5534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005535RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005536 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005537 ASSERT(args.length() == 3);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005538 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5539 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005540 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005541 JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode)
5542 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
5543 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode);
5544 RETURN_IF_EMPTY_HANDLE(isolate, result);
5545 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546}
5547
5548
danno@chromium.org169691d2013-07-15 08:01:13 +00005549static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate,
5550 Handle<JSObject> object,
5551 Handle<Name> key) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005552 if (JSReceiver::HasLocalProperty(object, key)) {
5553 return isolate->heap()->true_value();
5554 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005555 // Handle hidden prototypes. If there's a hidden prototype above this thing
5556 // then we have to check it for properties, because they are supposed to
5557 // look like they are on this object.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005558 Handle<Object> proto(object->GetPrototype(), isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +00005559 if (proto->IsJSObject() &&
5560 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005561 return HasLocalPropertyImplementation(isolate,
5562 Handle<JSObject>::cast(proto),
5563 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00005564 }
danno@chromium.org169691d2013-07-15 08:01:13 +00005565 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005566 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00005567}
5568
5569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005570RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005571 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 ASSERT(args.length() == 2);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005573 CONVERT_ARG_CHECKED(Name, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005575 uint32_t index;
5576 const bool key_is_array_index = key->AsArrayIndex(&index);
5577
ager@chromium.org9085a012009-05-11 19:22:57 +00005578 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00005580 if (obj->IsJSObject()) {
5581 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005582 // Fast case: either the key is a real named property or it is not
5583 // an array index and there are no interceptors or hidden
5584 // prototypes.
danno@chromium.org169691d2013-07-15 08:01:13 +00005585 if (object->HasRealNamedProperty(isolate, key)) {
5586 ASSERT(!isolate->has_scheduled_exception());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005587 return isolate->heap()->true_value();
danno@chromium.org169691d2013-07-15 08:01:13 +00005588 } else {
5589 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5590 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005591 Map* map = object->map();
5592 if (!key_is_array_index &&
5593 !map->has_named_interceptor() &&
5594 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
5595 return isolate->heap()->false_value();
5596 }
5597 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 HandleScope scope(isolate);
5599 return HasLocalPropertyImplementation(isolate,
5600 Handle<JSObject>(object),
ulan@chromium.org750145a2013-03-07 15:14:13 +00005601 Handle<Name>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005602 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005604 String* string = String::cast(obj);
5605 if (index < static_cast<uint32_t>(string->length())) {
5606 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 }
5608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005609 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610}
5611
5612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005613RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615 ASSERT(args.length() == 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005616 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5617 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005618
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005619 bool result = JSReceiver::HasProperty(receiver, key);
danno@chromium.org169691d2013-07-15 08:01:13 +00005620 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005621 if (isolate->has_pending_exception()) return Failure::Exception();
5622 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623}
5624
5625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005626RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005627 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005628 ASSERT(args.length() == 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005629 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005630 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005631
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005632 bool result = JSReceiver::HasElement(receiver, index);
danno@chromium.org169691d2013-07-15 08:01:13 +00005633 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005634 if (isolate->has_pending_exception()) return Failure::Exception();
5635 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005636}
5637
5638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005640 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005641 ASSERT(args.length() == 2);
5642
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005643 CONVERT_ARG_CHECKED(JSObject, object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005644 CONVERT_ARG_CHECKED(Name, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005645
ager@chromium.org870a0b62008-11-04 11:43:05 +00005646 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
danno@chromium.org169691d2013-07-15 08:01:13 +00005647 if (att == ABSENT || (att & DONT_ENUM) != 0) {
5648 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5649 return isolate->heap()->false_value();
5650 }
5651 ASSERT(!isolate->has_scheduled_exception());
5652 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005653}
5654
5655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005656RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005657 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005659 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005660 bool threw = false;
5661 Handle<JSArray> result = GetKeysFor(object, &threw);
5662 if (threw) return Failure::Exception();
5663 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664}
5665
5666
5667// Returns either a FixedArray as Runtime_GetPropertyNames,
5668// or, if the given object has an enum cache that contains
5669// all enumerable properties of the object and its prototypes
5670// have none, the map of the object. This is used to speed up
5671// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005673 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674 ASSERT(args.length() == 1);
5675
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005676 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677
5678 if (raw_object->IsSimpleEnum()) return raw_object->map();
5679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005680 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005681 Handle<JSReceiver> object(raw_object);
5682 bool threw = false;
5683 Handle<FixedArray> content =
5684 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
5685 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686
5687 // Test again, since cache may have been built by preceding call.
5688 if (object->IsSimpleEnum()) return object->map();
5689
5690 return *content;
5691}
5692
5693
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005694// Find the length of the prototype chain that is to to handled as one. If a
5695// prototype object is hidden it is to be viewed as part of the the object it
5696// is prototype for.
5697static int LocalPrototypeChainLength(JSObject* obj) {
5698 int count = 1;
5699 Object* proto = obj->GetPrototype();
5700 while (proto->IsJSObject() &&
5701 JSObject::cast(proto)->map()->is_hidden_prototype()) {
5702 count++;
5703 proto = JSObject::cast(proto)->GetPrototype();
5704 }
5705 return count;
5706}
5707
5708
5709// Return the names of the local named properties.
5710// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005712 HandleScope scope(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005713 ASSERT(args.length() == 2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005714 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005715 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005716 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005717 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005718 CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1);
5719 PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005720
5721 // Skip the global proxy as it has no properties and always delegates to the
5722 // real global object.
5723 if (obj->IsJSGlobalProxy()) {
5724 // Only collect names if access is permitted.
5725 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005726 !isolate->MayNamedAccess(*obj,
5727 isolate->heap()->undefined_value(),
5728 v8::ACCESS_KEYS)) {
5729 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005730 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005731 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005732 }
5733 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5734 }
5735
5736 // Find the number of objects making up this.
5737 int length = LocalPrototypeChainLength(*obj);
5738
5739 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005740 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005741 int total_property_count = 0;
5742 Handle<JSObject> jsproto = obj;
5743 for (int i = 0; i < length; i++) {
5744 // Only collect names if access is permitted.
5745 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746 !isolate->MayNamedAccess(*jsproto,
5747 isolate->heap()->undefined_value(),
5748 v8::ACCESS_KEYS)) {
5749 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005750 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005751 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005752 }
5753 int n;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005754 n = jsproto->NumberOfLocalProperties(filter);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005755 local_property_count[i] = n;
5756 total_property_count += n;
5757 if (i < length - 1) {
5758 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5759 }
5760 }
5761
5762 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005763 Handle<FixedArray> names =
5764 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005765
5766 // Get the property names.
5767 jsproto = obj;
5768 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005769 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005770 for (int i = 0; i < length; i++) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005771 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005772 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005773 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005774 proto_with_hidden_properties++;
5775 }
5776 if (i < length - 1) {
5777 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5778 }
5779 }
5780
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005781 // Filter out name of hidden properties object.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005782 if (proto_with_hidden_properties > 0) {
5783 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005785 names->length() - proto_with_hidden_properties);
5786 int dest_pos = 0;
5787 for (int i = 0; i < total_property_count; i++) {
5788 Object* name = old_names->get(i);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005789 if (name == isolate->heap()->hidden_string()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005790 continue;
5791 }
5792 names->set(dest_pos++, name);
5793 }
5794 }
5795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005796 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005797}
5798
5799
5800// Return the names of the local indexed properties.
5801// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005802RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005803 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005804 ASSERT(args.length() == 1);
5805 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005807 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005808 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005809
5810 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005811 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005812 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005814}
5815
5816
5817// Return information on whether an object has a named or indexed interceptor.
5818// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005819RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005821 ASSERT(args.length() == 1);
5822 if (!args[0]->IsJSObject()) {
5823 return Smi::FromInt(0);
5824 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005825 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005826
5827 int result = 0;
5828 if (obj->HasNamedInterceptor()) result |= 2;
5829 if (obj->HasIndexedInterceptor()) result |= 1;
5830
5831 return Smi::FromInt(result);
5832}
5833
5834
5835// Return property names from named interceptor.
5836// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005837RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005839 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005840 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005841
5842 if (obj->HasNamedInterceptor()) {
5843 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5844 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5845 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005846 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005847}
5848
5849
5850// Return element names from indexed interceptor.
5851// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005852RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005854 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005855 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005856
5857 if (obj->HasIndexedInterceptor()) {
5858 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5859 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5860 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005861 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005862}
5863
5864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005865RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005866 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005867 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005868 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005869 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005870
5871 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005872 // Do access checks before going to the global object.
5873 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005875 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005876 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005877 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005879 }
5880
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005881 Handle<Object> proto(object->GetPrototype(), isolate);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005882 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005883 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005884 object = Handle<JSObject>::cast(proto);
5885 }
5886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005887 bool threw = false;
5888 Handle<FixedArray> contents =
5889 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5890 if (threw) return Failure::Exception();
5891
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005892 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5893 // property array and since the result is mutable we have to create
5894 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005895 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005896 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005897 for (int i = 0; i < length; i++) {
5898 Object* entry = contents->get(i);
5899 if (entry->IsString()) {
5900 copy->set(i, entry);
5901 } else {
5902 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005903 HandleScope scope(isolate);
5904 Handle<Object> entry_handle(entry, isolate);
5905 Handle<Object> entry_str =
5906 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005907 copy->set(i, *entry_str);
5908 }
5909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005911}
5912
5913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005914RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005915 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 ASSERT(args.length() == 1);
5917
5918 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005919 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 it.AdvanceToArgumentsFrame();
5921 JavaScriptFrame* frame = it.frame();
5922
5923 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005924 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925
5926 // Try to convert the key to an index. If successful and within
5927 // index return the the argument from the frame.
5928 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005929 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 return frame->GetParameter(index);
5931 }
5932
ulan@chromium.org750145a2013-03-07 15:14:13 +00005933 if (args[0]->IsSymbol()) {
5934 // Lookup in the initial Object.prototype object.
5935 return isolate->initial_object_prototype()->GetProperty(
5936 Symbol::cast(args[0]));
5937 }
5938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 bool exception = false;
5942 Handle<Object> converted =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005943 Execution::ToString(isolate, args.at<Object>(0), &exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944 if (exception) return Failure::Exception();
5945 Handle<String> key = Handle<String>::cast(converted);
5946
5947 // Try to convert the string key into an array index.
5948 if (key->AsArrayIndex(&index)) {
5949 if (index < n) {
5950 return frame->GetParameter(index);
5951 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00005952 return isolate->initial_object_prototype()->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 }
5954 }
5955
5956 // Handle special arguments properties.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005957 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
5958 if (key->Equals(isolate->heap()->callee_string())) {
danno@chromium.org169691d2013-07-15 08:01:13 +00005959 JSFunction* function = frame->function();
5960 if (!function->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005961 return isolate->Throw(*isolate->factory()->NewTypeError(
5962 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5963 }
5964 return function;
5965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966
5967 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969}
5970
5971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005972RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005973 HandleScope scope(isolate);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005974 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005975 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5976 if (object->IsJSObject() && !object->IsGlobalObject()) {
5977 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
5978 }
5979 return *object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005980}
5981
5982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005983RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005984 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985 ASSERT(args.length() == 1);
5986
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00005987 return isolate->heap()->ToBoolean(args[0]->BooleanValue());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988}
5989
5990
5991// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5992// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005993RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005994 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995
5996 Object* obj = args[0];
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005997 if (obj->IsNumber()) return isolate->heap()->number_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 HeapObject* heap_obj = HeapObject::cast(obj);
5999
6000 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006001 if (heap_obj->map()->is_undetectable()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006002 return isolate->heap()->undefined_string();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004
6005 InstanceType instance_type = heap_obj->map()->instance_type();
6006 if (instance_type < FIRST_NONSTRING_TYPE) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006007 return isolate->heap()->string_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 }
6009
6010 switch (instance_type) {
6011 case ODDBALL_TYPE:
6012 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006013 return isolate->heap()->boolean_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 }
6015 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006016 return FLAG_harmony_typeof
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006017 ? isolate->heap()->null_string()
6018 : isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 }
6020 ASSERT(heap_obj->IsUndefined());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006021 return isolate->heap()->undefined_string();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006022 case SYMBOL_TYPE:
6023 return isolate->heap()->symbol_string();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006024 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00006025 case JS_FUNCTION_PROXY_TYPE:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006026 return isolate->heap()->function_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 default:
6028 // For any kind of object not handled above, the spec rule for
6029 // host objects gives that it is okay to return "object"
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006030 return isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 }
6032}
6033
6034
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006035static bool AreDigits(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006036 for (int i = from; i < to; i++) {
6037 if (s[i] < '0' || s[i] > '9') return false;
6038 }
6039
6040 return true;
6041}
6042
6043
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006044static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006045 ASSERT(to - from < 10); // Overflow is not possible.
6046 ASSERT(from < to);
6047 int d = s[from] - '0';
6048
6049 for (int i = from + 1; i < to; i++) {
6050 d = 10 * d + (s[i] - '0');
6051 }
6052
6053 return d;
6054}
6055
6056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006057RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006058 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006060 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006062
6063 // Fast case: short integer or some sorts of junk values.
6064 int len = subject->length();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006065 if (subject->IsSeqOneByteString()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006066 if (len == 0) return Smi::FromInt(0);
6067
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006068 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006069 bool minus = (data[0] == '-');
6070 int start_pos = (minus ? 1 : 0);
6071
6072 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006073 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006074 } else if (data[start_pos] > '9') {
6075 // Fast check for a junk value. A valid string may start from a
6076 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
6077 // the 'I' character ('Infinity'). All of that have codes not greater than
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00006078 // '9' except 'I' and &nbsp;.
6079 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006080 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006081 }
6082 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6083 // The maximal/minimal smi has 10 digits. If the string has less digits we
6084 // know it will fit into the smi-data type.
6085 int d = ParseDecimalInteger(data, start_pos, len);
6086 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006087 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006088 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006089 } else if (!subject->HasHashCode() &&
6090 len <= String::kMaxArrayIndexSize &&
6091 (len == 1 || data[0] != '0')) {
6092 // String hash is not calculated yet but all the data are present.
6093 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006094 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006095#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006096 subject->Hash(); // Force hash calculation.
6097 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6098 static_cast<int>(hash));
6099#endif
6100 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00006101 }
6102 return Smi::FromInt(d);
6103 }
6104 }
6105
6106 // Slower case.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006107 int flags = ALLOW_HEX;
6108 if (FLAG_harmony_numeric_literals) {
6109 // The current spec draft has not updated "ToNumber Applied to the String
6110 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6111 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6112 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006113 return isolate->heap()->NumberFromDouble(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006114 StringToDouble(isolate->unicode_cache(), subject, flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115}
6116
6117
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006118RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006119 SealHandleScope shs(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006120 CONVERT_SMI_ARG_CHECKED(length, 0);
6121 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6122 if (length == 0) return isolate->heap()->empty_string();
6123 if (is_one_byte) {
6124 return isolate->heap()->AllocateRawOneByteString(length);
6125 } else {
6126 return isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006128}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006131RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006132 HandleScope scope(isolate);
6133 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006134 CONVERT_SMI_ARG_CHECKED(new_length, 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006135 return *SeqString::Truncate(string, new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006136}
6137
6138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006139RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006140 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006141 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006142 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6143 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006144 ASSERT(string->IsFlat());
6145 Handle<String> result = string->IsOneByteRepresentationUnderneath()
6146 ? URIEscape::Escape<uint8_t>(isolate, source)
6147 : URIEscape::Escape<uc16>(isolate, source);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006148 if (result.is_null()) return Failure::OutOfMemoryException(0x12);
6149 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006150}
6151
6152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006153RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006154 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006155 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006156 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6157 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006158 ASSERT(string->IsFlat());
6159 return string->IsOneByteRepresentationUnderneath()
6160 ? *URIUnescape::Unescape<uint8_t>(isolate, source)
6161 : *URIUnescape::Unescape<uc16>(isolate, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162}
6163
6164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006165RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006166 HandleScope scope(isolate);
6167 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006168 ASSERT(args.length() == 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006169 return BasicJsonStringifier::StringifyString(isolate, string);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006170}
6171
6172
danno@chromium.org72204d52012-10-31 10:02:10 +00006173RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
danno@chromium.org72204d52012-10-31 10:02:10 +00006174 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006175 ASSERT(args.length() == 1);
danno@chromium.org72204d52012-10-31 10:02:10 +00006176 BasicJsonStringifier stringifier(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006177 return stringifier.Stringify(Handle<Object>(args[0], isolate));
danno@chromium.org72204d52012-10-31 10:02:10 +00006178}
6179
6180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006181RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006182 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006184 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006185 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188
lrn@chromium.org25156de2010-04-06 13:10:27 +00006189 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006190 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192}
6193
6194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006195RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006196 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006197 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198
6199 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006200 double value = StringToDouble(isolate->unicode_cache(),
6201 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006202
6203 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006204 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205}
6206
6207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006211 String* s,
6212 int length,
6213 int input_string_length,
6214 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006215 // We try this twice, once with the assumption that the result is no longer
6216 // than the input and, if that assumption breaks, again with the exact
6217 // length. This may not be pretty, but it is nicer than what was here before
6218 // and I hereby claim my vaffel-is.
6219 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 // Allocate the resulting string.
6221 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006222 // NOTE: This assumes that the upper/lower case of an ASCII
6223 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 // might break in the future if we implement more context and locale
6225 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006226 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006227 { MaybeObject* maybe_o = s->IsOneByteRepresentation()
6228 ? isolate->heap()->AllocateRawOneByteString(length)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006230 if (!maybe_o->ToObject(&o)) return maybe_o;
6231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232 String* result = String::cast(o);
6233 bool has_changed_character = false;
6234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235 // Convert all characters to upper case, assuming that they will fit
6236 // in the buffer
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006237 Access<ConsStringIteratorOp> op(
6238 isolate->runtime_state()->string_iterator());
6239 StringCharacterStream stream(s, op.value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006240 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 // We can assume that the string is not empty
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006242 uc32 current = stream.GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006243 for (int i = 0; i < length;) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006244 bool has_next = stream.HasMore();
6245 uc32 next = has_next ? stream.GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246 int char_length = mapping->get(current, next, chars);
6247 if (char_length == 0) {
6248 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006249 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250 i++;
6251 } else if (char_length == 1) {
6252 // Common case: converting the letter resulted in one character.
6253 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006254 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006255 has_changed_character = true;
6256 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006257 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 // We've assumed that the result would be as long as the
6259 // input but here is a character that converts to several
6260 // characters. No matter, we calculate the exact length
6261 // of the result and try the whole thing again.
6262 //
6263 // Note that this leaves room for optimization. We could just
6264 // memcpy what we already have to the result string. Also,
6265 // the result string is the last object allocated we could
6266 // "realloc" it and probably, in the vast majority of cases,
6267 // extend the existing string to be able to hold the full
6268 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006269 int next_length = 0;
6270 if (has_next) {
6271 next_length = mapping->get(next, 0, chars);
6272 if (next_length == 0) next_length = 1;
6273 }
6274 int current_length = i + char_length + next_length;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006275 while (stream.HasMore()) {
6276 current = stream.GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006277 // NOTE: we use 0 as the next character here because, while
6278 // the next character may affect what a character converts to,
6279 // it does not in any case affect the length of what it convert
6280 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281 int char_length = mapping->get(current, 0, chars);
6282 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006283 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006284 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006285 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006286 return Failure::OutOfMemoryException(0x13);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006287 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006289 // Try again with the real length.
6290 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291 } else {
6292 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006293 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 i++;
6295 }
6296 has_changed_character = true;
6297 }
6298 current = next;
6299 }
6300 if (has_changed_character) {
6301 return result;
6302 } else {
6303 // If we didn't actually change anything in doing the conversion
6304 // we simple return the result and let the converted string
6305 // become garbage; there is no reason to keep two identical strings
6306 // alive.
6307 return s;
6308 }
6309}
6310
6311
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006312namespace {
6313
lrn@chromium.org303ada72010-10-27 09:33:13 +00006314static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006315static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006316
6317// Given a word and two range boundaries returns a word with high bit
6318// set in every byte iff the corresponding input byte was strictly in
6319// the range (m, n). All the other bits in the result are cleared.
6320// This function is only useful when it can be inlined and the
6321// boundaries are statically known.
6322// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006323// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006324static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006325 // Use strict inequalities since in edge cases the function could be
6326 // further simplified.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006327 ASSERT(0 < m && m < n);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006328 // Has high bit set in every w byte less than n.
6329 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6330 // Has high bit set in every w byte greater than m.
6331 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6332 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6333}
6334
6335
6336enum AsciiCaseConversion {
6337 ASCII_TO_LOWER,
6338 ASCII_TO_UPPER
6339};
6340
6341
6342template <AsciiCaseConversion dir>
6343struct FastAsciiConverter {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006344 static bool Convert(char* dst, char* src, int length, bool* changed_out) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006345#ifdef DEBUG
6346 char* saved_dst = dst;
6347 char* saved_src = src;
6348#endif
6349 // We rely on the distance between upper and lower case letters
6350 // being a known power of 2.
6351 ASSERT('a' - 'A' == (1 << 5));
6352 // Boundaries for the range of input characters than require conversion.
6353 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6354 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6355 bool changed = false;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006356 uintptr_t or_acc = 0;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006357 char* const limit = src + length;
6358#ifdef V8_HOST_CAN_READ_UNALIGNED
6359 // Process the prefix of the input that requires no conversion one
6360 // (machine) word at a time.
6361 while (src <= limit - sizeof(uintptr_t)) {
6362 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006363 or_acc |= w;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006364 if (AsciiRangeMask(w, lo, hi) != 0) {
6365 changed = true;
6366 break;
6367 }
6368 *reinterpret_cast<uintptr_t*>(dst) = w;
6369 src += sizeof(uintptr_t);
6370 dst += sizeof(uintptr_t);
6371 }
6372 // Process the remainder of the input performing conversion when
6373 // required one word at a time.
6374 while (src <= limit - sizeof(uintptr_t)) {
6375 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006376 or_acc |= w;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006377 uintptr_t m = AsciiRangeMask(w, lo, hi);
6378 // The mask has high (7th) bit set in every byte that needs
6379 // conversion and we know that the distance between cases is
6380 // 1 << 5.
6381 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6382 src += sizeof(uintptr_t);
6383 dst += sizeof(uintptr_t);
6384 }
6385#endif
6386 // Process the last few bytes of the input (or the whole input if
6387 // unaligned access is not supported).
6388 while (src < limit) {
6389 char c = *src;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006390 or_acc |= c;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006391 if (lo < c && c < hi) {
6392 c ^= (1 << 5);
6393 changed = true;
6394 }
6395 *dst = c;
6396 ++src;
6397 ++dst;
6398 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006399 if ((or_acc & kAsciiMask) != 0) {
6400 return false;
6401 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006402#ifdef DEBUG
6403 CheckConvert(saved_dst, saved_src, length, changed);
6404#endif
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006405 *changed_out = changed;
6406 return true;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006407 }
6408
6409#ifdef DEBUG
6410 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6411 bool expected_changed = false;
6412 for (int i = 0; i < length; i++) {
6413 if (dst[i] == src[i]) continue;
6414 expected_changed = true;
6415 if (dir == ASCII_TO_LOWER) {
6416 ASSERT('A' <= src[i] && src[i] <= 'Z');
6417 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6418 } else {
6419 ASSERT(dir == ASCII_TO_UPPER);
6420 ASSERT('a' <= src[i] && src[i] <= 'z');
6421 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6422 }
6423 }
6424 ASSERT(expected_changed == changed);
6425 }
6426#endif
6427};
6428
6429
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006430struct ToLowerTraits {
6431 typedef unibrow::ToLowercase UnibrowConverter;
6432
lrn@chromium.org303ada72010-10-27 09:33:13 +00006433 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434};
6435
6436
6437struct ToUpperTraits {
6438 typedef unibrow::ToUppercase UnibrowConverter;
6439
lrn@chromium.org303ada72010-10-27 09:33:13 +00006440 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006441};
6442
6443} // namespace
6444
6445
6446template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006447MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006448 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006450 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006451 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006452 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006453 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006454
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006455 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006456 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006457 if (length == 0) return s;
6458
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006459 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006460 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006461 // NOTE: This assumes that the upper/lower case of an ASCII
6462 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006463 // might break in the future if we implement more context and locale
6464 // dependent upper/lower conversions.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006465 if (s->IsSeqOneByteString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006466 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006467 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006468 if (!maybe_o->ToObject(&o)) return maybe_o;
6469 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006470 SeqOneByteString* result = SeqOneByteString::cast(o);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006471 bool has_changed_character;
6472 bool is_ascii = ConvertTraits::AsciiConverter::Convert(
6473 reinterpret_cast<char*>(result->GetChars()),
6474 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
6475 length,
6476 &has_changed_character);
6477 // If not ASCII, we discard the result and take the 2 byte path.
6478 if (is_ascii) {
6479 return has_changed_character ? result : s;
6480 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006481 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006482
lrn@chromium.org303ada72010-10-27 09:33:13 +00006483 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 { MaybeObject* maybe_answer =
6485 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006486 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6487 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006488 if (answer->IsSmi()) {
6489 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006490 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 ConvertCaseHelper(isolate,
6492 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006493 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6494 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006495 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006496 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006497}
6498
6499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006500RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return ConvertCase<ToLowerTraits>(
6502 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return ConvertCase<ToUpperTraits>(
6508 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509}
6510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006512static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006513 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006514}
6515
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006517RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006518 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006519 ASSERT(args.length() == 3);
6520
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006521 CONVERT_ARG_CHECKED(String, s, 0);
6522 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6523 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006525 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006526 int length = s->length();
6527
6528 int left = 0;
6529 if (trimLeft) {
6530 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6531 left++;
6532 }
6533 }
6534
6535 int right = length;
6536 if (trimRight) {
6537 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6538 right--;
6539 }
6540 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006541 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006542}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006545RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006546 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006547 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006548 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6549 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006550 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6551
6552 int subject_length = subject->length();
6553 int pattern_length = pattern->length();
6554 RUNTIME_ASSERT(pattern_length > 0);
6555
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006556 if (limit == 0xffffffffu) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006557 Handle<Object> cached_answer(
6558 RegExpResultsCache::Lookup(isolate->heap(),
6559 *subject,
6560 *pattern,
6561 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6562 isolate);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006563 if (*cached_answer != Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006564 // The cache FixedArray is a COW-array and can therefore be reused.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006565 Handle<JSArray> result =
6566 isolate->factory()->NewJSArrayWithElements(
6567 Handle<FixedArray>::cast(cached_answer));
6568 return *result;
6569 }
6570 }
6571
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006572 // The limit can be very large (0xffffffffu), but since the pattern
6573 // isn't empty, we can never create more parts than ~half the length
6574 // of the subject.
6575
6576 if (!subject->IsFlat()) FlattenString(subject);
6577
6578 static const int kMaxInitialListCapacity = 16;
6579
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006580 ZoneScope zone_scope(isolate->runtime_zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006581
6582 // Find (up to limit) indices of separator and end-of-string in subject
6583 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006584 ZoneList<int> indices(initial_capacity, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006585 if (!pattern->IsFlat()) FlattenString(pattern);
6586
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006587 FindStringIndicesDispatch(isolate, *subject, *pattern,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006588 &indices, limit, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006589
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006590 if (static_cast<uint32_t>(indices.length()) < limit) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006591 indices.Add(subject_length, zone_scope.zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006592 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006593
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006594 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006595
6596 // Create JSArray of substrings separated by separator.
6597 int part_count = indices.length();
6598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006600 JSObject::EnsureCanContainHeapObjectElements(result);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006601 result->set_length(Smi::FromInt(part_count));
6602
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006603 ASSERT(result->HasFastObjectElements());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006604
6605 if (part_count == 1 && indices.at(0) == subject_length) {
6606 FixedArray::cast(result->elements())->set(0, *subject);
6607 return *result;
6608 }
6609
6610 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6611 int part_start = 0;
6612 for (int i = 0; i < part_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00006613 HandleScope local_loop_handle(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006614 int part_end = indices.at(i);
6615 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006616 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006617 elements->set(i, *substring);
6618 part_start = part_end + pattern_length;
6619 }
6620
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006621 if (limit == 0xffffffffu) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006622 if (result->HasFastObjectElements()) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006623 RegExpResultsCache::Enter(isolate->heap(),
6624 *subject,
6625 *pattern,
6626 *elements,
6627 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006628 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006629 }
6630
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006631 return *result;
6632}
6633
6634
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006635// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006636// one-char strings in the cache. Gives up on the first char that is
6637// not in the cache and fills the remainder with smi zeros. Returns
6638// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639static int CopyCachedAsciiCharsToArray(Heap* heap,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006640 const uint8_t* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006641 FixedArray* elements,
6642 int length) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006643 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006644 FixedArray* ascii_cache = heap->single_character_string_cache();
6645 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006646 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006647 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006648 for (i = 0; i < length; ++i) {
6649 Object* value = ascii_cache->get(chars[i]);
6650 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006651 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006652 }
6653 if (i < length) {
6654 ASSERT(Smi::FromInt(0) == 0);
6655 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6656 }
6657#ifdef DEBUG
6658 for (int j = 0; j < length; ++j) {
6659 Object* element = elements->get(j);
6660 ASSERT(element == Smi::FromInt(0) ||
6661 (element->IsString() && String::cast(element)->LooksValid()));
6662 }
6663#endif
6664 return i;
6665}
6666
6667
6668// Converts a String to JSArray.
6669// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006670RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006672 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006673 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006674 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006675
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006676 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006677 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006678
6679 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006680 int position = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006681 if (s->IsFlat() && s->IsOneByteRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006682 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006683 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006684 { MaybeObject* maybe_obj =
6685 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006686 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6687 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006689 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006690 String::FlatContent content = s->GetFlatContent();
6691 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006692 Vector<const uint8_t> chars = content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006693 // Note, this will initialize all elements (not only the prefix)
6694 // to prevent GC from seeing partially initialized array.
6695 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6696 chars.start(),
6697 *elements,
6698 length);
6699 } else {
6700 MemsetPointer(elements->data_start(),
6701 isolate->heap()->undefined_value(),
6702 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006703 }
6704 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006706 }
6707 for (int i = position; i < length; ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006708 Handle<Object> str =
6709 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006710 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006711 }
6712
6713#ifdef DEBUG
6714 for (int i = 0; i < length; ++i) {
6715 ASSERT(String::cast(elements->get(i))->length() == 1);
6716 }
6717#endif
6718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006720}
6721
6722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006723RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006724 SealHandleScope shs(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006725 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006726 CONVERT_ARG_CHECKED(String, value, 0);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006727 return value->ToObject(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006728}
6729
6730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006732 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006734 return char_length == 0;
6735}
6736
6737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006738RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006739 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 ASSERT(args.length() == 1);
6741
6742 Object* number = args[0];
6743 RUNTIME_ASSERT(number->IsNumber());
6744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006746}
6747
6748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006749RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006750 SealHandleScope shs(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00006751 ASSERT(args.length() == 1);
6752
6753 Object* number = args[0];
6754 RUNTIME_ASSERT(number->IsNumber());
6755
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006756 return isolate->heap()->NumberToString(
6757 number, false, isolate->heap()->GetPretenureMode());
ager@chromium.org357bf652010-04-12 11:30:10 +00006758}
6759
6760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006761RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006762 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 ASSERT(args.length() == 1);
6764
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006765 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006766
6767 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6768 if (number > 0 && number <= Smi::kMaxValue) {
6769 return Smi::FromInt(static_cast<int>(number));
6770 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772}
6773
6774
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006775// ES6 draft 9.1.11
6776RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006777 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006778 ASSERT(args.length() == 1);
6779
6780 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6781
6782 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6783 if (number > 0 && number <= Smi::kMaxValue) {
6784 return Smi::FromInt(static_cast<int>(number));
6785 }
6786 if (number <= 0) {
6787 return Smi::FromInt(0);
6788 }
6789 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6790}
6791
6792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006793RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006794 SealHandleScope shs(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006795 ASSERT(args.length() == 1);
6796
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006797 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006798
6799 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6800 if (number > 0 && number <= Smi::kMaxValue) {
6801 return Smi::FromInt(static_cast<int>(number));
6802 }
6803
6804 double double_value = DoubleToInteger(number);
6805 // Map both -0 and +0 to +0.
6806 if (double_value == 0) double_value = 0;
6807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006809}
6810
6811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006812RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006813 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 ASSERT(args.length() == 1);
6815
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006816 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818}
6819
6820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006821RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006822 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 ASSERT(args.length() == 1);
6824
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006825 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006826
6827 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6828 if (number > 0 && number <= Smi::kMaxValue) {
6829 return Smi::FromInt(static_cast<int>(number));
6830 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006832}
6833
6834
ager@chromium.org870a0b62008-11-04 11:43:05 +00006835// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6836// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006837RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006838 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006839 ASSERT(args.length() == 1);
6840
6841 Object* obj = args[0];
6842 if (obj->IsSmi()) {
6843 return obj;
6844 }
6845 if (obj->IsHeapNumber()) {
6846 double value = HeapNumber::cast(obj)->value();
6847 int int_value = FastD2I(value);
6848 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6849 return Smi::FromInt(int_value);
6850 }
6851 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006852 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006853}
6854
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006856RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006857 SealHandleScope shs(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006858 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006859 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006860}
6861
6862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006863RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006864 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865 ASSERT(args.length() == 2);
6866
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006867 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6868 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006869 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870}
6871
6872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006873RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006874 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006875 ASSERT(args.length() == 2);
6876
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006877 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6878 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880}
6881
6882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006883RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006884 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 ASSERT(args.length() == 2);
6886
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006887 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6888 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006889 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890}
6891
6892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006893RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006894 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895 ASSERT(args.length() == 1);
6896
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006897 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006898 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899}
6900
6901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006902RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006903 SealHandleScope shs(isolate);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006904 ASSERT(args.length() == 0);
6905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006906 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006907}
6908
6909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006910RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006911 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912 ASSERT(args.length() == 2);
6913
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006914 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6915 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917}
6918
6919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006920RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006921 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006922 ASSERT(args.length() == 2);
6923
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006924 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6925 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006926
ager@chromium.org3811b432009-10-28 14:53:37 +00006927 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006928 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006929 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930}
6931
6932
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006933RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006934 SealHandleScope shs(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006935 ASSERT(args.length() == 2);
6936
6937 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6938 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6939 return isolate->heap()->NumberFromInt32(x * y);
6940}
6941
6942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006943RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006944 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006946 CONVERT_ARG_CHECKED(String, str1, 0);
6947 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006948 isolate->counters()->string_add_runtime()->Increment();
6949 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950}
6951
6952
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006953template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006954static inline void StringBuilderConcatHelper(String* special,
6955 sinkchar* sink,
6956 FixedArray* fixed_array,
6957 int array_length) {
6958 int position = 0;
6959 for (int i = 0; i < array_length; i++) {
6960 Object* element = fixed_array->get(i);
6961 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006962 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006963 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006964 int pos;
6965 int len;
6966 if (encoded_slice > 0) {
6967 // Position and length encoded in one smi.
6968 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6969 len = StringBuilderSubstringLength::decode(encoded_slice);
6970 } else {
6971 // Position and length encoded in two smis.
6972 Object* obj = fixed_array->get(++i);
6973 ASSERT(obj->IsSmi());
6974 pos = Smi::cast(obj)->value();
6975 len = -encoded_slice;
6976 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006977 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006978 sink + position,
6979 pos,
6980 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006981 position += len;
6982 } else {
6983 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006984 int element_length = string->length();
6985 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006986 position += element_length;
6987 }
6988 }
6989}
6990
6991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006992RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006993 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006994 ASSERT(args.length() == 3);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006995 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006996 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006997 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006998 return Failure::OutOfMemoryException(0x14);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006999 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007000 int array_length = args.smi_at(1);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007001 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007002
7003 // This assumption is used by the slice encoding in one or two smis.
7004 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7005
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007006 JSObject::EnsureCanContainHeapObjectElements(array);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007007
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007008 int special_length = special->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007009 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007010 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 }
7012 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007013 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016
7017 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 } else if (array_length == 1) {
7020 Object* first = fixed_array->get(0);
7021 if (first->IsString()) return first;
7022 }
7023
danno@chromium.orgf005df62013-04-30 16:36:45 +00007024 bool one_byte = special->HasOnlyOneByteChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025 int position = 0;
7026 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007027 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028 Object* elt = fixed_array->get(i);
7029 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007030 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007031 int smi_value = Smi::cast(elt)->value();
7032 int pos;
7033 int len;
7034 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007035 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007036 pos = StringBuilderSubstringPosition::decode(smi_value);
7037 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007038 } else {
7039 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007040 len = -smi_value;
7041 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007042 i++;
7043 if (i >= array_length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007044 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007045 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007046 Object* next_smi = fixed_array->get(i);
7047 if (!next_smi->IsSmi()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007048 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007049 }
7050 pos = Smi::cast(next_smi)->value();
7051 if (pos < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007052 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007055 ASSERT(pos >= 0);
7056 ASSERT(len >= 0);
7057 if (pos > special_length || len > special_length - pos) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007058 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007059 }
7060 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 } else if (elt->IsString()) {
7062 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007063 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007064 increment = element_length;
danno@chromium.orgf005df62013-04-30 16:36:45 +00007065 if (one_byte && !element->HasOnlyOneByteChars()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007066 one_byte = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007069 ASSERT(!elt->IsTheHole());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007070 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007072 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007074 return Failure::OutOfMemoryException(0x15);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00007075 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007076 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077 }
7078
7079 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007081
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007082 if (one_byte) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007083 { MaybeObject* maybe_object =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007084 isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007085 if (!maybe_object->ToObject(&object)) return maybe_object;
7086 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007087 SeqOneByteString* answer = SeqOneByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007088 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007089 answer->GetChars(),
7090 fixed_array,
7091 array_length);
7092 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007094 { MaybeObject* maybe_object =
7095 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007096 if (!maybe_object->ToObject(&object)) return maybe_object;
7097 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007098 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007099 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007100 answer->GetChars(),
7101 fixed_array,
7102 array_length);
7103 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105}
7106
7107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007108RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007109 SealHandleScope shs(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007110 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007111 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007112 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007113 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007114 return Failure::OutOfMemoryException(0x16);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007115 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007116 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007117 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007118
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007119 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007120 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007121 }
7122 FixedArray* fixed_array = FixedArray::cast(array->elements());
7123 if (fixed_array->length() < array_length) {
7124 array_length = fixed_array->length();
7125 }
7126
7127 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007129 } else if (array_length == 1) {
7130 Object* first = fixed_array->get(0);
7131 if (first->IsString()) return first;
7132 }
7133
7134 int separator_length = separator->length();
7135 int max_nof_separators =
7136 (String::kMaxLength + separator_length - 1) / separator_length;
7137 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007138 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007139 return Failure::OutOfMemoryException(0x17);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007140 }
7141 int length = (array_length - 1) * separator_length;
7142 for (int i = 0; i < array_length; i++) {
7143 Object* element_obj = fixed_array->get(i);
7144 if (!element_obj->IsString()) {
7145 // TODO(1161): handle this case.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007146 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007147 }
7148 String* element = String::cast(element_obj);
7149 int increment = element->length();
7150 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007152 return Failure::OutOfMemoryException(0x18);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007153 }
7154 length += increment;
7155 }
7156
7157 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007158 { MaybeObject* maybe_object =
7159 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007160 if (!maybe_object->ToObject(&object)) return maybe_object;
7161 }
7162 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7163
7164 uc16* sink = answer->GetChars();
7165#ifdef DEBUG
7166 uc16* end = sink + length;
7167#endif
7168
7169 String* first = String::cast(fixed_array->get(0));
7170 int first_length = first->length();
7171 String::WriteToFlat(first, sink, 0, first_length);
7172 sink += first_length;
7173
7174 for (int i = 1; i < array_length; i++) {
7175 ASSERT(sink + separator_length <= end);
7176 String::WriteToFlat(separator, sink, 0, separator_length);
7177 sink += separator_length;
7178
7179 String* element = String::cast(fixed_array->get(i));
7180 int element_length = element->length();
7181 ASSERT(sink + element_length <= end);
7182 String::WriteToFlat(element, sink, 0, element_length);
7183 sink += element_length;
7184 }
7185 ASSERT(sink == end);
7186
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007187 // Use %_FastAsciiArrayJoin instead.
7188 ASSERT(!answer->IsOneByteRepresentation());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007189 return answer;
7190}
7191
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007192template <typename Char>
7193static void JoinSparseArrayWithSeparator(FixedArray* elements,
7194 int elements_length,
7195 uint32_t array_length,
7196 String* separator,
7197 Vector<Char> buffer) {
7198 int previous_separator_position = 0;
7199 int separator_length = separator->length();
7200 int cursor = 0;
7201 for (int i = 0; i < elements_length; i += 2) {
7202 int position = NumberToInt32(elements->get(i));
7203 String* string = String::cast(elements->get(i + 1));
7204 int string_length = string->length();
7205 if (string->length() > 0) {
7206 while (previous_separator_position < position) {
7207 String::WriteToFlat<Char>(separator, &buffer[cursor],
7208 0, separator_length);
7209 cursor += separator_length;
7210 previous_separator_position++;
7211 }
7212 String::WriteToFlat<Char>(string, &buffer[cursor],
7213 0, string_length);
7214 cursor += string->length();
7215 }
7216 }
7217 if (separator_length > 0) {
7218 // Array length must be representable as a signed 32-bit number,
7219 // otherwise the total string length would have been too large.
7220 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7221 int last_array_index = static_cast<int>(array_length - 1);
7222 while (previous_separator_position < last_array_index) {
7223 String::WriteToFlat<Char>(separator, &buffer[cursor],
7224 0, separator_length);
7225 cursor += separator_length;
7226 previous_separator_position++;
7227 }
7228 }
7229 ASSERT(cursor <= buffer.length());
7230}
7231
7232
7233RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007234 SealHandleScope shs(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007235 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007236 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007237 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007238 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007239 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007240 // elements_array is fast-mode JSarray of alternating positions
7241 // (increasing order) and strings.
7242 // array_length is length of original array (used to add separators);
7243 // separator is string to put between elements. Assumed to be non-empty.
7244
7245 // Find total length of join result.
7246 int string_length = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007247 bool is_ascii = separator->IsOneByteRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007248 int max_string_length;
7249 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007250 max_string_length = SeqOneByteString::kMaxLength;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007251 } else {
7252 max_string_length = SeqTwoByteString::kMaxLength;
7253 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007254 bool overflow = false;
7255 CONVERT_NUMBER_CHECKED(int, elements_length,
7256 Int32, elements_array->length());
7257 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7258 FixedArray* elements = FixedArray::cast(elements_array->elements());
7259 for (int i = 0; i < elements_length; i += 2) {
7260 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007261 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7262 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007263 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007264 if (is_ascii && !string->IsOneByteRepresentation()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007265 is_ascii = false;
7266 max_string_length = SeqTwoByteString::kMaxLength;
7267 }
7268 if (length > max_string_length ||
7269 max_string_length - length < string_length) {
7270 overflow = true;
7271 break;
7272 }
7273 string_length += length;
7274 }
7275 int separator_length = separator->length();
7276 if (!overflow && separator_length > 0) {
7277 if (array_length <= 0x7fffffffu) {
7278 int separator_count = static_cast<int>(array_length) - 1;
7279 int remaining_length = max_string_length - string_length;
7280 if ((remaining_length / separator_length) >= separator_count) {
7281 string_length += separator_length * (array_length - 1);
7282 } else {
7283 // Not room for the separators within the maximal string length.
7284 overflow = true;
7285 }
7286 } else {
7287 // Nonempty separator and at least 2^31-1 separators necessary
7288 // means that the string is too large to create.
7289 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7290 overflow = true;
7291 }
7292 }
7293 if (overflow) {
7294 // Throw OutOfMemory exception for creating too large a string.
7295 V8::FatalProcessOutOfMemory("Array join result too large.");
7296 }
7297
7298 if (is_ascii) {
7299 MaybeObject* result_allocation =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007300 isolate->heap()->AllocateRawOneByteString(string_length);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007301 if (result_allocation->IsFailure()) return result_allocation;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007302 SeqOneByteString* result_string =
7303 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007304 JoinSparseArrayWithSeparator<uint8_t>(elements,
7305 elements_length,
7306 array_length,
7307 separator,
7308 Vector<uint8_t>(
7309 result_string->GetChars(),
7310 string_length));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007311 return result_string;
7312 } else {
7313 MaybeObject* result_allocation =
7314 isolate->heap()->AllocateRawTwoByteString(string_length);
7315 if (result_allocation->IsFailure()) return result_allocation;
7316 SeqTwoByteString* result_string =
7317 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7318 JoinSparseArrayWithSeparator<uc16>(elements,
7319 elements_length,
7320 array_length,
7321 separator,
7322 Vector<uc16>(result_string->GetChars(),
7323 string_length));
7324 return result_string;
7325 }
7326}
7327
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007329RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007330 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331 ASSERT(args.length() == 2);
7332
7333 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7334 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336}
7337
7338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007339RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007340 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 ASSERT(args.length() == 2);
7342
7343 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7344 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346}
7347
7348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007349RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007350 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 ASSERT(args.length() == 2);
7352
7353 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7354 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356}
7357
7358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007359RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007360 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 ASSERT(args.length() == 2);
7362
7363 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7364 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366}
7367
7368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007369RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007370 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 ASSERT(args.length() == 2);
7372
7373 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7374 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007375 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376}
7377
7378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007379RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007380 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 ASSERT(args.length() == 2);
7382
7383 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7384 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386}
7387
7388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007389RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007390 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391 ASSERT(args.length() == 2);
7392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007393 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7394 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007395 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7396 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 if (x == y) return Smi::FromInt(EQUAL);
7398 Object* result;
7399 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7400 result = Smi::FromInt(EQUAL);
7401 } else {
7402 result = Smi::FromInt(NOT_EQUAL);
7403 }
7404 return result;
7405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007409 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410 ASSERT(args.length() == 2);
7411
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007412 CONVERT_ARG_CHECKED(String, x, 0);
7413 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007415 bool not_equal = !x->Equals(y);
7416 // This is slightly convoluted because the value that signifies
7417 // equality is 0 and inequality is 1 so we have to negate the result
7418 // from String::Equals.
7419 ASSERT(not_equal == 0 || not_equal == 1);
7420 STATIC_CHECK(EQUAL == 0);
7421 STATIC_CHECK(NOT_EQUAL == 1);
7422 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423}
7424
7425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007427 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428 ASSERT(args.length() == 3);
7429
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007430 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7431 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007432 if (std::isnan(x) || std::isnan(y)) return args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433 if (x == y) return Smi::FromInt(EQUAL);
7434 if (isless(x, y)) return Smi::FromInt(LESS);
7435 return Smi::FromInt(GREATER);
7436}
7437
7438
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007439// Compare two Smis as if they were converted to strings and then
7440// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007441RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007442 SealHandleScope shs(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007443 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007444 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7445 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007446
7447 // If the integers are equal so are the string representations.
7448 if (x_value == y_value) return Smi::FromInt(EQUAL);
7449
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007450 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007451 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007452 if (x_value == 0 || y_value == 0)
7453 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007454
ager@chromium.org32912102009-01-16 10:38:43 +00007455 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007456 // smallest because the char code of '-' is less than the char code
7457 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007458
7459 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7460 // architectures using 32-bit Smis.
7461 uint32_t x_scaled = x_value;
7462 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007463 if (x_value < 0 || y_value < 0) {
7464 if (y_value >= 0) return Smi::FromInt(LESS);
7465 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007466 x_scaled = -x_value;
7467 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007468 }
7469
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007470 static const uint32_t kPowersOf10[] = {
7471 1, 10, 100, 1000, 10*1000, 100*1000,
7472 1000*1000, 10*1000*1000, 100*1000*1000,
7473 1000*1000*1000
7474 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007475
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007476 // If the integers have the same number of decimal digits they can be
7477 // compared directly as the numeric order is the same as the
7478 // lexicographic order. If one integer has fewer digits, it is scaled
7479 // by some power of 10 to have the same number of digits as the longer
7480 // integer. If the scaled integers are equal it means the shorter
7481 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007482
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007483 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7484 int x_log2 = IntegerLog2(x_scaled);
7485 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7486 x_log10 -= x_scaled < kPowersOf10[x_log10];
7487
7488 int y_log2 = IntegerLog2(y_scaled);
7489 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7490 y_log10 -= y_scaled < kPowersOf10[y_log10];
7491
7492 int tie = EQUAL;
7493
7494 if (x_log10 < y_log10) {
7495 // X has fewer digits. We would like to simply scale up X but that
7496 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7497 // be scaled up to 9_000_000_000. So we scale up by the next
7498 // smallest power and scale down Y to drop one digit. It is OK to
7499 // drop one digit from the longer integer since the final digit is
7500 // past the length of the shorter integer.
7501 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7502 y_scaled /= 10;
7503 tie = LESS;
7504 } else if (y_log10 < x_log10) {
7505 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7506 x_scaled /= 10;
7507 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007508 }
7509
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007510 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7511 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7512 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007513}
7514
7515
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007516static Object* StringCharacterStreamCompare(RuntimeState* state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007517 String* x,
7518 String* y) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007519 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
7520 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
7521 while (stream_x.HasMore() && stream_y.HasMore()) {
7522 int d = stream_x.GetNext() - stream_y.GetNext();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007523 if (d < 0) return Smi::FromInt(LESS);
7524 else if (d > 0) return Smi::FromInt(GREATER);
7525 }
7526
7527 // x is (non-trivial) prefix of y:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007528 if (stream_y.HasMore()) return Smi::FromInt(LESS);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007529 // y is prefix of x:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007530 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007531}
7532
7533
7534static Object* FlatStringCompare(String* x, String* y) {
7535 ASSERT(x->IsFlat());
7536 ASSERT(y->IsFlat());
7537 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7538 int prefix_length = x->length();
7539 if (y->length() < prefix_length) {
7540 prefix_length = y->length();
7541 equal_prefix_result = Smi::FromInt(GREATER);
7542 } else if (y->length() > prefix_length) {
7543 equal_prefix_result = Smi::FromInt(LESS);
7544 }
7545 int r;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007546 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007547 String::FlatContent x_content = x->GetFlatContent();
7548 String::FlatContent y_content = y->GetFlatContent();
7549 if (x_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007550 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007551 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007552 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007553 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007554 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007555 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007556 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7557 }
7558 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007559 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7560 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007561 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007562 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7563 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007564 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007565 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7566 }
7567 }
7568 Object* result;
7569 if (r == 0) {
7570 result = equal_prefix_result;
7571 } else {
7572 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7573 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007574 ASSERT(result ==
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007575 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007576 return result;
7577}
7578
7579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007580RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007581 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007582 ASSERT(args.length() == 2);
7583
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007584 CONVERT_ARG_CHECKED(String, x, 0);
7585 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007587 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007588
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589 // A few fast case tests before we flatten.
7590 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007591 if (y->length() == 0) {
7592 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007594 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007595 return Smi::FromInt(LESS);
7596 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007597
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007598 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007599 if (d < 0) return Smi::FromInt(LESS);
7600 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007601
lrn@chromium.org303ada72010-10-27 09:33:13 +00007602 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007603 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007604 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7605 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007606 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007607 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007609
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007610 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007611 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007612}
7613
7614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007615RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007616 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007617 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007621 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007622}
7623
7624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007625RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007626 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007627 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007628 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007629
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007630 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007631 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007632}
7633
7634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007635RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007636 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007638 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007641 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007642}
7643
7644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007645static const double kPiDividedBy4 = 0.78539816339744830962;
7646
7647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007648RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007649 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007650 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007651 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007653 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7654 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007655 double result;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007656 if (std::isinf(x) && std::isinf(y)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007657 // Make sure that the result in case of two infinite arguments
7658 // is a multiple of Pi / 4. The sign of the result is determined
7659 // by the first argument (x) and the sign of the second argument
7660 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007661 int multiplier = (x < 0) ? -1 : 1;
7662 if (y < 0) multiplier *= 3;
7663 result = multiplier * kPiDividedBy4;
7664 } else {
7665 result = atan2(x, y);
7666 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668}
7669
7670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007671RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007672 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007673 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007674 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007675
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007676 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678}
7679
7680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007681RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007682 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007683 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007684 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007686 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007687 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007688}
7689
7690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007691RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007692 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007693 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007695
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007696 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00007697 lazily_initialize_fast_exp();
7698 return isolate->heap()->NumberFromDouble(fast_exp(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699}
7700
7701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007702RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007703 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007704 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007706
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007707 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007708 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709}
7710
7711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007712RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007713 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007717 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007719}
7720
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00007721
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007722// Slow version of Math.pow. We check for fast paths for special cases.
7723// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007724RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007725 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007726 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007727 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007729 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007730
7731 // If the second argument is a smi, it is much faster to call the
7732 // custom powi() function than the generic pow().
7733 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007734 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007735 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007736 }
7737
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007738 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00007739 double result = power_helper(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007740 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007741 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742}
7743
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00007744
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007745// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007746// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007747RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007748 SealHandleScope shs(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007749 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007750 isolate->counters()->math_pow()->Increment();
7751
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007752 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7753 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007754 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007755 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007756 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007757 double result = power_double_double(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007758 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007759 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007760 }
7761}
7762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007765 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007767 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007768
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007769 if (!args[0]->IsHeapNumber()) {
7770 // Must be smi. Return the argument unchanged for all the other types
7771 // to make fuzz-natives test happy.
7772 return args[0];
7773 }
7774
7775 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7776
7777 double value = number->value();
7778 int exponent = number->get_exponent();
7779 int sign = number->get_sign();
7780
danno@chromium.org160a7b02011-04-18 15:51:38 +00007781 if (exponent < -1) {
7782 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7783 if (sign) return isolate->heap()->minus_zero_value();
7784 return Smi::FromInt(0);
7785 }
7786
7787 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7788 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007789 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007790 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007791 return Smi::FromInt(static_cast<int>(value + 0.5));
7792 }
7793
7794 // If the magnitude is big enough, there's no place for fraction part. If we
7795 // try to add 0.5 to this number, 1.0 will be added instead.
7796 if (exponent >= 52) {
7797 return number;
7798 }
7799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007800 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007801
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007802 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007803 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007804}
7805
7806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007807RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007808 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007809 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007810 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007811
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007812 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814}
7815
7816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007817RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007818 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007819 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007820 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007822 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007823 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007824}
7825
7826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007827RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007828 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007829 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007830 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007831
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007832 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007833 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834}
7835
7836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007837RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007838 SealHandleScope shs(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007839 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007840
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007841 CONVERT_SMI_ARG_CHECKED(year, 0);
7842 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007843
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007844 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007845}
7846
7847
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007848RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7849 HandleScope scope(isolate);
7850 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007851
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007852 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7853 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7854 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007855
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007856 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007857
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007858 Object* value = NULL;
7859 bool is_value_nan = false;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007860 if (std::isnan(time)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007861 value = isolate->heap()->nan_value();
7862 is_value_nan = true;
7863 } else if (!is_utc &&
7864 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7865 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7866 value = isolate->heap()->nan_value();
7867 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007868 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007869 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7870 if (time < -DateCache::kMaxTimeInMs ||
7871 time > DateCache::kMaxTimeInMs) {
7872 value = isolate->heap()->nan_value();
7873 is_value_nan = true;
7874 } else {
7875 MaybeObject* maybe_result =
7876 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7877 if (!maybe_result->ToObject(&value)) return maybe_result;
7878 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007879 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007880 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007881 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007882}
7883
7884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007885RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007886 HandleScope scope(isolate);
7887 ASSERT(args.length() == 3);
7888
7889 Handle<JSFunction> callee = args.at<JSFunction>(0);
7890 Object** parameters = reinterpret_cast<Object**>(args[1]);
7891 const int argument_count = Smi::cast(args[2])->value();
7892
7893 Handle<JSObject> result =
7894 isolate->factory()->NewArgumentsObject(callee, argument_count);
7895 // Allocate the elements if needed.
7896 int parameter_count = callee->shared()->formal_parameter_count();
7897 if (argument_count > 0) {
7898 if (parameter_count > 0) {
7899 int mapped_count = Min(argument_count, parameter_count);
7900 Handle<FixedArray> parameter_map =
7901 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7902 parameter_map->set_map(
7903 isolate->heap()->non_strict_arguments_elements_map());
7904
7905 Handle<Map> old_map(result->map());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007906 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007907 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007908
7909 result->set_map(*new_map);
7910 result->set_elements(*parameter_map);
7911
7912 // Store the context and the arguments array at the beginning of the
7913 // parameter map.
7914 Handle<Context> context(isolate->context());
7915 Handle<FixedArray> arguments =
7916 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7917 parameter_map->set(0, *context);
7918 parameter_map->set(1, *arguments);
7919
7920 // Loop over the actual parameters backwards.
7921 int index = argument_count - 1;
7922 while (index >= mapped_count) {
7923 // These go directly in the arguments array and have no
7924 // corresponding slot in the parameter map.
7925 arguments->set(index, *(parameters - index - 1));
7926 --index;
7927 }
7928
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007929 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007930 while (index >= 0) {
7931 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007932 Handle<String> name(scope_info->ParameterName(index));
7933 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007934 bool duplicate = false;
7935 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007936 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007937 duplicate = true;
7938 break;
7939 }
7940 }
7941
7942 if (duplicate) {
7943 // This goes directly in the arguments array with a hole in the
7944 // parameter map.
7945 arguments->set(index, *(parameters - index - 1));
7946 parameter_map->set_the_hole(index + 2);
7947 } else {
7948 // The context index goes in the parameter map with a hole in the
7949 // arguments array.
7950 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007951 for (int j = 0; j < context_local_count; ++j) {
7952 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007953 context_index = j;
7954 break;
7955 }
7956 }
7957 ASSERT(context_index >= 0);
7958 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007959 parameter_map->set(index + 2, Smi::FromInt(
7960 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007961 }
7962
7963 --index;
7964 }
7965 } else {
7966 // If there is no aliasing, the arguments object elements are not
7967 // special in any way.
7968 Handle<FixedArray> elements =
7969 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7970 result->set_elements(*elements);
7971 for (int i = 0; i < argument_count; ++i) {
7972 elements->set(i, *(parameters - i - 1));
7973 }
7974 }
7975 }
7976 return *result;
7977}
7978
7979
7980RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007981 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007982 ASSERT(args.length() == 3);
7983
7984 JSFunction* callee = JSFunction::cast(args[0]);
7985 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007986 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007987
lrn@chromium.org303ada72010-10-27 09:33:13 +00007988 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007989 { MaybeObject* maybe_result =
7990 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007991 if (!maybe_result->ToObject(&result)) return maybe_result;
7992 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007993 // Allocate the elements if needed.
7994 if (length > 0) {
7995 // Allocate the fixed array.
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00007996 FixedArray* array;
7997 { MaybeObject* maybe_obj =
7998 isolate->heap()->AllocateUninitializedFixedArray(length);
7999 if (!maybe_obj->To(&array)) return maybe_obj;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008000 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008001
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008002 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008003 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008004 for (int i = 0; i < length; i++) {
8005 array->set(i, *--parameters, mode);
8006 }
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00008007 JSObject::cast(result)->set_elements(array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008008 }
8009 return result;
8010}
8011
8012
verwaest@chromium.org662436e2013-08-28 08:41:27 +00008013RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) {
8014 HandleScope scope(isolate);
8015 ASSERT(args.length() == 1);
8016 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8017 Handle<Context> context(isolate->context());
8018 PretenureFlag pretenure_flag = NOT_TENURED;
8019 Handle<JSFunction> result =
8020 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8021 context,
8022 pretenure_flag);
8023 return *result;
8024}
8025
8026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008027RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008028 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008029 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008030 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8031 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8032 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033
whesse@chromium.org7b260152011-06-20 15:33:18 +00008034 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008035 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008036 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008038 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8039 context,
8040 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 return *result;
8042}
8043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008044
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008045// Find the arguments of the JavaScript function invocation that called
8046// into C++ code. Collect these in a newly allocated array of handles (possibly
8047// prefixed by a number of empty handles).
8048static SmartArrayPointer<Handle<Object> > GetCallerArguments(
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008049 Isolate* isolate,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008050 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008051 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008052 // Find frame containing arguments passed to the caller.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008053 JavaScriptFrameIterator it(isolate);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008054 JavaScriptFrame* frame = it.frame();
8055 List<JSFunction*> functions(2);
8056 frame->GetFunctions(&functions);
8057 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008058 int inlined_jsframe_index = functions.length() - 1;
8059 JSFunction* inlined_function = functions[inlined_jsframe_index];
8060 Vector<SlotRef> args_slots =
8061 SlotRef::ComputeSlotMappingForArguments(
8062 frame,
8063 inlined_jsframe_index,
8064 inlined_function->shared()->formal_parameter_count());
8065
8066 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008068 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008069 SmartArrayPointer<Handle<Object> > param_data(
8070 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008071 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008072 Handle<Object> val = args_slots[i].GetValue(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008073 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008074 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008075
8076 args_slots.Dispose();
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078 return param_data;
8079 } else {
8080 it.AdvanceToArgumentsFrame();
8081 frame = it.frame();
8082 int args_count = frame->ComputeParametersCount();
8083
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008084 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008085 SmartArrayPointer<Handle<Object> > param_data(
8086 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008087 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008088 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008089 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008090 }
8091 return param_data;
8092 }
8093}
8094
8095
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008096RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8097 HandleScope scope(isolate);
8098 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008099 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008100 RUNTIME_ASSERT(args[3]->IsNumber());
8101 Handle<Object> bindee = args.at<Object>(1);
8102
8103 // TODO(lrn): Create bound function in C++ code from premade shared info.
8104 bound_function->shared()->set_bound(true);
8105 // Get all arguments of calling function (Function.prototype.bind).
8106 int argc = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008107 SmartArrayPointer<Handle<Object> > arguments =
8108 GetCallerArguments(isolate, 0, &argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008109 // Don't count the this-arg.
8110 if (argc > 0) {
8111 ASSERT(*arguments[0] == args[2]);
8112 argc--;
8113 } else {
8114 ASSERT(args[2]->IsUndefined());
8115 }
8116 // Initialize array of bindings (function, this, and any existing arguments
8117 // if the function was already bound).
8118 Handle<FixedArray> new_bindings;
8119 int i;
8120 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8121 Handle<FixedArray> old_bindings(
8122 JSFunction::cast(*bindee)->function_bindings());
8123 new_bindings =
8124 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008125 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8126 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008127 i = 0;
8128 for (int n = old_bindings->length(); i < n; i++) {
8129 new_bindings->set(i, old_bindings->get(i));
8130 }
8131 } else {
8132 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8133 new_bindings = isolate->factory()->NewFixedArray(array_size);
8134 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8135 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8136 i = 2;
8137 }
8138 // Copy arguments, skipping the first which is "this_arg".
8139 for (int j = 0; j < argc; j++, i++) {
8140 new_bindings->set(i, *arguments[j + 1]);
8141 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008142 new_bindings->set_map_no_write_barrier(
8143 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008144 bound_function->set_function_bindings(*new_bindings);
8145
8146 // Update length.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008147 Handle<String> length_string = isolate->factory()->length_string();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008148 Handle<Object> new_length(args.at<Object>(3));
8149 PropertyAttributes attr =
8150 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008151 ForceSetProperty(bound_function, length_string, new_length, attr);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008152 return *bound_function;
8153}
8154
8155
8156RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8157 HandleScope handles(isolate);
8158 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008159 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008160 if (callable->IsJSFunction()) {
8161 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8162 if (function->shared()->bound()) {
8163 Handle<FixedArray> bindings(function->function_bindings());
8164 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8165 return *isolate->factory()->NewJSArrayWithElements(bindings);
8166 }
8167 }
8168 return isolate->heap()->undefined_value();
8169}
8170
8171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008172RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008173 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008174 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008175 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008176 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008177 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008178
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008179 // The argument is a bound function. Extract its bound arguments
8180 // and callable.
8181 Handle<FixedArray> bound_args =
8182 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8183 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8184 Handle<Object> bound_function(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008185 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8186 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008187 ASSERT(!bound_function->IsJSFunction() ||
8188 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008190 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008191 SmartArrayPointer<Handle<Object> > param_data =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008192 GetCallerArguments(isolate, bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008193 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008194 param_data[i] = Handle<Object>(bound_args->get(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008195 JSFunction::kBoundArgumentsStartIndex + i), isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008196 }
8197
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008198 if (!bound_function->IsJSFunction()) {
8199 bool exception_thrown;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008200 bound_function = Execution::TryGetConstructorDelegate(isolate,
8201 bound_function,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008202 &exception_thrown);
8203 if (exception_thrown) return Failure::Exception();
8204 }
8205 ASSERT(bound_function->IsJSFunction());
8206
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008207 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008208 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008209 Execution::New(Handle<JSFunction>::cast(bound_function),
8210 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008211 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008212 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008213 }
8214 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008215 return *result;
8216}
8217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008219RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008221 ASSERT(args.length() == 1);
8222
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008223 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008225 // If the constructor isn't a proper function we throw a type error.
8226 if (!constructor->IsJSFunction()) {
8227 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8228 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008229 isolate->factory()->NewTypeError("not_constructor", arguments);
8230 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008231 }
8232
8233 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008234
8235 // If function should not have prototype, construction is not allowed. In this
8236 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008237 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008238 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8239 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 isolate->factory()->NewTypeError("not_constructor", arguments);
8241 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008242 }
8243
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008244#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008245 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008246 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008247 if (debug->StepInActive()) {
8248 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008249 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008250#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 if (function->has_initial_map()) {
8253 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254 // The 'Function' function ignores the receiver object when
8255 // called using 'new' and creates a new JSFunction object that
8256 // is returned. The receiver object is only used for error
8257 // reporting if an error occurs when constructing the new
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00008258 // JSFunction. Factory::NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008259 // allocate JSFunctions since it does not properly initialize
8260 // the shared part of the function. Since the receiver is
8261 // ignored anyway, we use the global object as the receiver
8262 // instead of a new JSFunction object. This way, errors are
8263 // reported the same way whether or not 'Function' is called
8264 // using 'new'.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008265 return isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 }
8268
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008269 // The function should be compiled for the optimization hints to be
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008270 // available.
8271 JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008272
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008273 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008274 if (!function->has_initial_map() &&
8275 shared->IsInobjectSlackTrackingInProgress()) {
8276 // The tracking is already in progress for another function. We can only
8277 // track one initial_map at a time, so we force the completion before the
8278 // function is called as a constructor for the first time.
8279 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008280 }
8281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8283 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 isolate->counters()->constructed_objects()->Increment();
8286 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008287
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008288 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008289}
8290
8291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008292RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008294 ASSERT(args.length() == 1);
8295
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008296 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008297 function->shared()->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008300}
8301
8302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008303RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008304 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 ASSERT(args.length() == 1);
8306
8307 Handle<JSFunction> function = args.at<JSFunction>(0);
8308#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008309 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008311 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008312 PrintF("]\n");
8313 }
8314#endif
8315
lrn@chromium.org34e60782011-09-15 07:25:40 +00008316 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008318 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 return Failure::Exception();
8320 }
8321
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008322 // All done. Return the compiled code.
8323 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 return function->code();
8325}
8326
8327
ulan@chromium.org750145a2013-03-07 15:14:13 +00008328bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00008329 // If the function is not compiled ignore the lazy
8330 // recompilation. This can happen if the debugger is activated and
8331 // the function is returned to the not compiled state.
ulan@chromium.org750145a2013-03-07 15:14:13 +00008332 if (!function->shared()->is_compiled()) return false;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008333
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008334 // If the function is not optimizable or debugger is active continue using the
8335 // code from the full compiler.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008336 if (!FLAG_crankshaft ||
ulan@chromium.org750145a2013-03-07 15:14:13 +00008337 function->shared()->optimization_disabled() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008338 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008339 if (FLAG_trace_opt) {
8340 PrintF("[failed to optimize ");
8341 function->PrintName();
8342 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
ulan@chromium.org750145a2013-03-07 15:14:13 +00008343 function->shared()->optimization_disabled() ? "F" : "T",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008344 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008345 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00008346 return false;
8347 }
8348 return true;
8349}
8350
8351
8352RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
8353 HandleScope scope(isolate);
8354 ASSERT(args.length() == 1);
8355 Handle<JSFunction> function = args.at<JSFunction>(0);
8356
8357 if (!AllowOptimization(isolate, function)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 function->ReplaceCode(function->shared()->code());
8359 return function->code();
8360 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008361 function->shared()->code()->set_profiler_ticks(0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008362 if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008363 return function->code();
8364 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008365 if (FLAG_trace_opt) {
8366 PrintF("[failed to optimize ");
8367 function->PrintName();
8368 PrintF(": optimized compilation failed]\n");
8369 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008370 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008371 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008372}
8373
8374
rossberg@chromium.org92597162013-08-23 13:28:00 +00008375RUNTIME_FUNCTION(MaybeObject*, Runtime_ConcurrentRecompile) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008376 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008377 ASSERT(args.length() == 1);
8378 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008379 if (!AllowOptimization(isolate, function)) {
8380 function->ReplaceCode(function->shared()->code());
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00008381 return isolate->heap()->undefined_value();
ulan@chromium.org750145a2013-03-07 15:14:13 +00008382 }
8383 function->shared()->code()->set_profiler_ticks(0);
rossberg@chromium.org92597162013-08-23 13:28:00 +00008384 ASSERT(FLAG_concurrent_recompilation);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008385 if (!Compiler::RecompileConcurrent(function)) {
8386 function->ReplaceCode(function->shared()->code());
8387 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008388 return isolate->heap()->undefined_value();
8389}
8390
8391
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008392class ActivationsFinder : public ThreadVisitor {
8393 public:
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008394 Code* code_;
8395 bool has_code_activations_;
8396
8397 explicit ActivationsFinder(Code* code)
8398 : code_(code),
8399 has_code_activations_(false) { }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008400
8401 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008402 JavaScriptFrameIterator it(isolate, top);
8403 VisitFrames(&it);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008404 }
8405
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008406 void VisitFrames(JavaScriptFrameIterator* it) {
8407 for (; !it->done(); it->Advance()) {
8408 JavaScriptFrame* frame = it->frame();
8409 if (code_->contains(frame->pc())) has_code_activations_ = true;
8410 }
8411 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008412};
8413
8414
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008415RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008416 HandleScope scope(isolate);
8417 ASSERT(args.length() == 0);
8418 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008419 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008420 delete deoptimizer;
8421 return isolate->heap()->undefined_value();
8422}
8423
8424
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008425RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8426 HandleScope scope(isolate);
8427 ASSERT(args.length() == 1);
8428 RUNTIME_ASSERT(args[0]->IsSmi());
8429 Deoptimizer::BailoutType type =
8430 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8431 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008432 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008433
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008434 Handle<JSFunction> function = deoptimizer->function();
8435 Handle<Code> optimized_code = deoptimizer->compiled_code();
8436
8437 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8438 ASSERT(type == deoptimizer->bailout_type());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008439
8440 // Make sure to materialize objects before causing any allocation.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008441 JavaScriptFrameIterator it(isolate);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008442 deoptimizer->MaterializeHeapObjects(&it);
8443 delete deoptimizer;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008444
8445 JavaScriptFrame* frame = it.frame();
8446 RUNTIME_ASSERT(frame->function()->IsJSFunction());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008447 ASSERT(frame->function() == *function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008448
8449 // Avoid doing too much work when running with --always-opt and keep
8450 // the optimized code around.
8451 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008453 }
8454
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008455 // Search for other activations of the same function and code.
8456 ActivationsFinder activations_finder(*optimized_code);
8457 activations_finder.VisitFrames(&it);
8458 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008460 if (!activations_finder.has_code_activations_) {
8461 if (function->code() == *optimized_code) {
8462 if (FLAG_trace_deopt) {
8463 PrintF("[removing optimized code for: ");
8464 function->PrintName();
8465 PrintF("]\n");
8466 }
8467 function->ReplaceCode(function->shared()->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008468 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00008469 } else {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008470 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8471 // unconditionally if the code is not already marked for deoptimization.
8472 // If there is an index by shared function info, all the better.
lrn@chromium.org34e60782011-09-15 07:25:40 +00008473 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008475 // Evict optimized code for this function from the cache so that it doesn't
8476 // get used for new closures.
8477 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8478 "notify deoptimized");
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008481}
8482
8483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008487 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008489
8490 Deoptimizer::DeoptimizeFunction(*function);
8491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008493}
8494
8495
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008496RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8497 HandleScope scope(isolate);
8498 ASSERT(args.length() == 1);
8499 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8500 Code* unoptimized = function->shared()->code();
8501 if (unoptimized->kind() == Code::FUNCTION) {
8502 unoptimized->ClearInlineCaches();
8503 unoptimized->ClearTypeFeedbackCells(isolate->heap());
8504 }
8505 return isolate->heap()->undefined_value();
8506}
8507
8508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008509RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008510 SealHandleScope shs(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008511#if defined(USE_SIMULATOR)
8512 return isolate->heap()->true_value();
8513#else
8514 return isolate->heap()->false_value();
8515#endif
8516}
8517
8518
rossberg@chromium.org92597162013-08-23 13:28:00 +00008519RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008520 HandleScope scope(isolate);
rossberg@chromium.org92597162013-08-23 13:28:00 +00008521 return FLAG_concurrent_recompilation
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008522 ? isolate->heap()->true_value() : isolate->heap()->false_value();
8523}
8524
8525
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8527 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008528 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008529 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008530
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008531 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8532 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008533
8534 Code* unoptimized = function->shared()->code();
8535 if (args.length() == 2 &&
8536 unoptimized->kind() == Code::FUNCTION) {
8537 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008538 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008539 // Start patching from the currently patched loop nesting level.
8540 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008541 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008542 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00008543 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8544 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8545 }
rossberg@chromium.org92597162013-08-23 13:28:00 +00008546 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) {
8547 function->MarkForConcurrentRecompilation();
ulan@chromium.org750145a2013-03-07 15:14:13 +00008548 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008549 }
8550
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008551 return isolate->heap()->undefined_value();
8552}
8553
8554
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008555RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008556 HandleScope scope(isolate);
8557 ASSERT(args.length() == 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008558 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8559 ASSERT(!function->IsOptimized());
8560 function->shared()->set_optimization_disabled(true);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008561 return isolate->heap()->undefined_value();
8562}
8563
8564
lrn@chromium.org1c092762011-05-09 09:42:16 +00008565RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8566 HandleScope scope(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008567 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008568 if (!isolate->use_crankshaft()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00008569 return Smi::FromInt(4); // 4 == "never".
8570 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008571 bool sync_with_compiler_thread = true;
8572 if (args.length() == 2) {
8573 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8574 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8575 sync_with_compiler_thread = false;
8576 }
8577 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008578 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
rossberg@chromium.org92597162013-08-23 13:28:00 +00008579 if (FLAG_concurrent_recompilation && sync_with_compiler_thread) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00008580 while (function->IsInRecompileQueue()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008581 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8582 OS::Sleep(50);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008583 }
8584 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00008585 if (FLAG_always_opt) {
8586 // We may have always opt, but that is more best-effort than a real
8587 // promise, so we still say "no" if it is not optimized.
8588 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8589 : Smi::FromInt(2); // 2 == "no".
8590 }
jkummerow@chromium.org10480472013-07-17 08:22:15 +00008591 if (FLAG_deopt_every_n_times) {
8592 return Smi::FromInt(6); // 6 == "maybe deopted".
8593 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00008594 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8595 : Smi::FromInt(2); // 2 == "no".
8596}
8597
8598
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00008599RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
8600 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8601 isolate->optimizing_compiler_thread()->Unblock();
8602 return isolate->heap()->undefined_value();
8603}
8604
8605
lrn@chromium.org1c092762011-05-09 09:42:16 +00008606RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8607 HandleScope scope(isolate);
8608 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008609 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008610 return Smi::FromInt(function->shared()->opt_count());
8611}
8612
8613
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008614static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8615 Handle<JSFunction> function,
8616 Handle<Code> unoptimized) {
8617 // Keep track of whether we've succeeded in optimizing.
8618 if (!unoptimized->optimizable()) return false;
8619 // If we are trying to do OSR when there are already optimized
8620 // activations of the function, it means (a) the function is directly or
8621 // indirectly recursive and (b) an optimized invocation has been
8622 // deoptimized so that we are currently in an unoptimized activation.
8623 // Check for optimized activations of this function.
8624 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8625 JavaScriptFrame* frame = it.frame();
8626 if (frame->is_optimized() && frame->function() == *function) return false;
8627 }
8628
8629 return true;
8630}
8631
8632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008633RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 HandleScope scope(isolate);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008635 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008636 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008637 CONVERT_NUMBER_CHECKED(uint32_t, pc_offset, Uint32, args[1]);
8638 Handle<Code> unoptimized(function->shared()->code(), isolate);
8639
8640#ifdef DEBUG
8641 JavaScriptFrameIterator it(isolate);
8642 JavaScriptFrame* frame = it.frame();
8643 ASSERT_EQ(frame->function(), *function);
8644 ASSERT_EQ(frame->LookupCode(), *unoptimized);
8645 ASSERT(unoptimized->contains(frame->pc()));
8646
8647 ASSERT(pc_offset ==
8648 static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start()));
8649#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008650
8651 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008652 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008653
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008654 Handle<Code> result = Handle<Code>::null();
8655 BailoutId ast_id = BailoutId::None();
8656
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00008657 if (FLAG_concurrent_osr) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008658 if (isolate->optimizing_compiler_thread()->
8659 IsQueuedForOSR(function, pc_offset)) {
8660 // Still waiting for the optimizing compiler thread to finish. Carry on.
8661 if (FLAG_trace_osr) {
8662 PrintF("[COSR - polling recompile tasks for ");
8663 function->PrintName();
8664 PrintF("]\n");
8665 }
8666 return NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008667 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008668
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00008669 RecompileJob* job = isolate->optimizing_compiler_thread()->
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008670 FindReadyOSRCandidate(function, pc_offset);
8671
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00008672 if (job == NULL) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008673 if (IsSuitableForOnStackReplacement(isolate, function, unoptimized) &&
8674 Compiler::RecompileConcurrent(function, pc_offset)) {
8675 if (function->IsMarkedForLazyRecompilation() ||
8676 function->IsMarkedForConcurrentRecompilation()) {
8677 // Prevent regular recompilation if we queue this for OSR.
8678 // TODO(yangguo): remove this as soon as OSR becomes one-shot.
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00008679 function->ReplaceCode(*unoptimized);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008680 }
8681 return NULL;
8682 }
8683 // Fall through to the end in case of failure.
8684 } else {
8685 // TODO(titzer): don't install the OSR code into the function.
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00008686 ast_id = job->info()->osr_ast_id();
8687 result = Compiler::InstallOptimizedCode(job);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008688 }
8689 } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) {
8690 ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset);
8691 ASSERT(!ast_id.IsNone());
8692 if (FLAG_trace_osr) {
8693 PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt());
8694 function->PrintName();
8695 PrintF("]\n");
8696 }
8697 // Attempt OSR compilation.
8698 result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008699 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008700
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008701 // Revert the patched back edge table, regardless of whether OSR succeeds.
8702 BackEdgeTable::Revert(isolate, *unoptimized);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008703
8704 // Check whether we ended up with usable optimized code.
8705 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8706 DeoptimizationInputData* data =
8707 DeoptimizationInputData::cast(result->deoptimization_data());
8708
8709 if (data->OsrPcOffset()->value() >= 0) {
8710 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8711 if (FLAG_trace_osr) {
8712 PrintF("[OSR - entry at AST id %d, offset %d in optimized code]\n",
8713 ast_id.ToInt(), data->OsrPcOffset()->value());
8714 }
8715 // TODO(titzer): this is a massive hack to make the deopt counts
8716 // match. Fix heuristics for reenabling optimizations!
8717 function->shared()->increment_deopt_count();
8718 return *result;
8719 }
8720 }
8721
8722 if (FLAG_trace_osr) {
8723 PrintF("[OSR - optimization failed for ");
8724 function->PrintName();
8725 PrintF("]\n");
8726 }
8727
8728 if (function->IsMarkedForLazyRecompilation() ||
8729 function->IsMarkedForConcurrentRecompilation()) {
8730 function->ReplaceCode(function->shared()->code());
8731 }
8732 return NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008733}
8734
8735
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00008736RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) {
8737 SealHandleScope shs(isolate);
8738 ASSERT(args.length() == 2);
8739#ifdef DEBUG
8740 CONVERT_SMI_ARG_CHECKED(interval, 0);
8741 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8742 isolate->heap()->set_allocation_timeout(timeout);
8743 FLAG_gc_interval = interval;
8744#endif
8745 return isolate->heap()->undefined_value();
8746}
8747
8748
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008749RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008750 SealHandleScope shs(isolate);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008751 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8752 return isolate->heap()->undefined_value();
8753}
8754
8755
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008756RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008757 SealHandleScope shs(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008758 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8759 return isolate->heap()->nan_value();
8760}
8761
8762
danno@chromium.orgc612e022011-11-10 11:38:15 +00008763RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8764 HandleScope scope(isolate);
8765 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008766 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008767 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8768 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008769
8770 // If there are too many arguments, allocate argv via malloc.
8771 const int argv_small_size = 10;
8772 Handle<Object> argv_small_buffer[argv_small_size];
8773 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8774 Handle<Object>* argv = argv_small_buffer;
8775 if (argc > argv_small_size) {
8776 argv = new Handle<Object>[argc];
8777 if (argv == NULL) return isolate->StackOverflow();
8778 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8779 }
8780
8781 for (int i = 0; i < argc; ++i) {
8782 MaybeObject* maybe = args[1 + i];
8783 Object* object;
8784 if (!maybe->To<Object>(&object)) return maybe;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008785 argv[i] = Handle<Object>(object, isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008786 }
8787
8788 bool threw;
8789 Handle<JSReceiver> hfun(fun);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008790 Handle<Object> hreceiver(receiver, isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008791 Handle<Object> result = Execution::Call(
8792 isolate, hfun, hreceiver, argc, argv, &threw, true);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008793
8794 if (threw) return Failure::Exception();
8795 return *result;
8796}
8797
8798
lrn@chromium.org34e60782011-09-15 07:25:40 +00008799RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8800 HandleScope scope(isolate);
8801 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008802 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008803 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008804 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008805 CONVERT_SMI_ARG_CHECKED(offset, 3);
8806 CONVERT_SMI_ARG_CHECKED(argc, 4);
danno@chromium.org59400602013-08-13 17:09:37 +00008807 RUNTIME_ASSERT(offset >= 0);
8808 RUNTIME_ASSERT(argc >= 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008809
8810 // If there are too many arguments, allocate argv via malloc.
8811 const int argv_small_size = 10;
8812 Handle<Object> argv_small_buffer[argv_small_size];
8813 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8814 Handle<Object>* argv = argv_small_buffer;
8815 if (argc > argv_small_size) {
8816 argv = new Handle<Object>[argc];
8817 if (argv == NULL) return isolate->StackOverflow();
8818 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8819 }
8820
8821 for (int i = 0; i < argc; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008822 argv[i] = Object::GetElement(isolate, arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008823 }
8824
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008825 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008826 Handle<Object> result = Execution::Call(
8827 isolate, fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008828
8829 if (threw) return Failure::Exception();
8830 return *result;
8831}
8832
8833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008834RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 ASSERT(args.length() == 1);
8837 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008838 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008839}
8840
8841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008842RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008843 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008844 ASSERT(args.length() == 1);
8845 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008846 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0));
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008847}
8848
8849
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008850RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008851 SealHandleScope shs(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008852 ASSERT(args.length() == 2);
8853
8854 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8855 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
8856 Context* result;
8857 MaybeObject* maybe_result =
8858 isolate->heap()->AllocateGlobalContext(function, scope_info);
8859 if (!maybe_result->To(&result)) return maybe_result;
8860
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008861 ASSERT(function->context() == isolate->context());
8862 ASSERT(function->context()->global_object() == result->global_object());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008863 isolate->set_context(result);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008864 result->global_object()->set_global_context(result);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008865
8866 return result; // non-failure
8867}
8868
8869
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008870RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008871 SealHandleScope shs(isolate);
kasper.lund7276f142008-07-30 08:49:36 +00008872 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008874 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008875 int length = function->shared()->scope_info()->ContextLength();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008876 Context* result;
8877 MaybeObject* maybe_result =
8878 isolate->heap()->AllocateFunctionContext(length, function);
8879 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008881 isolate->set_context(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882
kasper.lund7276f142008-07-30 08:49:36 +00008883 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884}
8885
lrn@chromium.org303ada72010-10-27 09:33:13 +00008886
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008887RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008888 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008889 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008890 JSReceiver* extension_object;
8891 if (args[0]->IsJSReceiver()) {
8892 extension_object = JSReceiver::cast(args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008893 } else {
8894 // Convert the object to a proper JavaScript object.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008895 MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008896 if (!maybe_js_object->To(&extension_object)) {
8897 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8898 HandleScope scope(isolate);
8899 Handle<Object> handle = args.at<Object>(0);
8900 Handle<Object> result =
8901 isolate->factory()->NewTypeError("with_expression",
8902 HandleVector(&handle, 1));
8903 return isolate->Throw(*result);
8904 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008905 return maybe_js_object;
8906 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907 }
8908 }
8909
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008910 JSFunction* function;
8911 if (args[1]->IsSmi()) {
8912 // A smi sentinel indicates a context nested inside global code rather
8913 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008914 // gotten from the native context.
8915 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008916 } else {
8917 function = JSFunction::cast(args[1]);
8918 }
8919
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008920 Context* context;
8921 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008922 isolate->heap()->AllocateWithContext(function,
8923 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008924 extension_object);
8925 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008926 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008927 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008928}
8929
8930
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008931RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008932 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008933 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008934 String* name = String::cast(args[0]);
8935 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008936 JSFunction* function;
8937 if (args[2]->IsSmi()) {
8938 // A smi sentinel indicates a context nested inside global code rather
8939 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008940 // gotten from the native context.
8941 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008942 } else {
8943 function = JSFunction::cast(args[2]);
8944 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008945 Context* context;
8946 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008947 isolate->heap()->AllocateCatchContext(function,
8948 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008949 name,
8950 thrown_object);
8951 if (!maybe_context->To(&context)) return maybe_context;
8952 isolate->set_context(context);
8953 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008954}
8955
8956
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008957RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008958 SealHandleScope shs(isolate);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008959 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008960 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008961 JSFunction* function;
8962 if (args[1]->IsSmi()) {
8963 // A smi sentinel indicates a context nested inside global code rather
8964 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008965 // gotten from the native context.
8966 function = isolate->context()->native_context()->closure();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008967 } else {
8968 function = JSFunction::cast(args[1]);
8969 }
8970 Context* context;
8971 MaybeObject* maybe_context =
8972 isolate->heap()->AllocateBlockContext(function,
8973 isolate->context(),
8974 scope_info);
8975 if (!maybe_context->To(&context)) return maybe_context;
8976 isolate->set_context(context);
8977 return context;
8978}
8979
8980
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008981RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008982 SealHandleScope shs(isolate);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008983 ASSERT(args.length() == 1);
8984 Object* obj = args[0];
8985 return isolate->heap()->ToBoolean(obj->IsJSModule());
8986}
8987
8988
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008989RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008990 SealHandleScope shs(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008991 ASSERT(args.length() == 2);
8992 CONVERT_SMI_ARG_CHECKED(index, 0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008993
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008994 if (!args[1]->IsScopeInfo()) {
8995 // Module already initialized. Find hosting context and retrieve context.
8996 Context* host = Context::cast(isolate->context())->global_context();
8997 Context* context = Context::cast(host->get(index));
8998 ASSERT(context->previous() == isolate->context());
8999 isolate->set_context(context);
9000 return context;
9001 }
9002
9003 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9004
9005 // Allocate module context.
9006 HandleScope scope(isolate);
9007 Factory* factory = isolate->factory();
9008 Handle<Context> context = factory->NewModuleContext(scope_info);
9009 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
9010 context->set_module(*module);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009011 Context* previous = isolate->context();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009012 context->set_previous(previous);
9013 context->set_closure(previous->closure());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009014 context->set_global_object(previous->global_object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009015 isolate->set_context(*context);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009016
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009017 // Find hosting scope and initialize internal variable holding module there.
9018 previous->global_context()->set(index, *context);
9019
9020 return *context;
9021}
9022
9023
9024RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) {
9025 HandleScope scope(isolate);
9026 ASSERT(args.length() == 1);
9027 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9028 Context* host_context = isolate->context();
9029
9030 for (int i = 0; i < descriptions->length(); ++i) {
9031 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9032 int host_index = description->host_index();
9033 Handle<Context> context(Context::cast(host_context->get(host_index)));
9034 Handle<JSModule> module(context->module());
9035
9036 for (int j = 0; j < description->length(); ++j) {
9037 Handle<String> name(description->name(j));
9038 VariableMode mode = description->mode(j);
9039 int index = description->index(j);
9040 switch (mode) {
9041 case VAR:
9042 case LET:
9043 case CONST:
9044 case CONST_HARMONY: {
9045 PropertyAttributes attr =
9046 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9047 Handle<AccessorInfo> info =
9048 Accessors::MakeModuleExport(name, index, attr);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00009049 Handle<Object> result = JSObject::SetAccessor(module, info);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009050 ASSERT(!(result.is_null() || result->IsUndefined()));
9051 USE(result);
9052 break;
9053 }
9054 case MODULE: {
9055 Object* referenced_context = Context::cast(host_context)->get(index);
9056 Handle<JSModule> value(Context::cast(referenced_context)->module());
9057 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode);
9058 break;
9059 }
9060 case INTERNAL:
9061 case TEMPORARY:
9062 case DYNAMIC:
9063 case DYNAMIC_GLOBAL:
9064 case DYNAMIC_LOCAL:
9065 UNREACHABLE();
9066 }
9067 }
9068
9069 JSObject::PreventExtensions(module);
9070 }
9071
9072 ASSERT(!isolate->has_pending_exception());
9073 return isolate->heap()->undefined_value();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009074}
9075
9076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009077RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009078 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 ASSERT(args.length() == 2);
9080
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009081 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9082 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083
9084 int index;
9085 PropertyAttributes attributes;
9086 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009087 BindingFlags binding_flags;
9088 Handle<Object> holder = context->Lookup(name,
9089 flags,
9090 &index,
9091 &attributes,
9092 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009094 // If the slot was not found the result is true.
9095 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097 }
9098
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009099 // If the slot was found in a context, it should be DONT_DELETE.
9100 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009101 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009102 }
9103
9104 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009105 // the global object, or the subject of a with. Try to delete it
9106 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009107 Handle<JSObject> object = Handle<JSObject>::cast(holder);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009108 Handle<Object> result = JSReceiver::DeleteProperty(object, name);
9109 RETURN_IF_EMPTY_HANDLE(isolate, result);
9110 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111}
9112
9113
ager@chromium.orga1645e22009-09-09 19:27:10 +00009114// A mechanism to return a pair of Object pointers in registers (if possible).
9115// How this is achieved is calling convention-dependent.
9116// All currently supported x86 compiles uses calling conventions that are cdecl
9117// variants where a 64-bit value is returned in two 32-bit registers
9118// (edx:eax on ia32, r1:r0 on ARM).
9119// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9120// In Win64 calling convention, a struct of two pointers is returned in memory,
9121// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009122#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009123struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009124 MaybeObject* x;
9125 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009126};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009127
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009128
lrn@chromium.org303ada72010-10-27 09:33:13 +00009129static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009130 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009131 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9132 // In Win64 they are assigned to a hidden first argument.
9133 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009134}
9135#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009136typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009137static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009139 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009141#endif
9142
9143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144static inline MaybeObject* Unhole(Heap* heap,
9145 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009146 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9148 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009149 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150}
9151
9152
danno@chromium.org40cb8782011-05-25 07:58:50 +00009153static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9154 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009155 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009157 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009158 JSFunction* context_extension_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009159 top->native_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009160 // If the holder isn't a context extension object, we just return it
9161 // as the receiver. This allows arguments objects to be used as
9162 // receivers, but only if they are put in the context scope chain
9163 // explicitly via a with-statement.
9164 Object* constructor = holder->map()->constructor();
9165 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009166 // Fall back to using the global object as the implicit receiver if
9167 // the property turns out to be a local variable allocated in a
9168 // context extension object - introduced via eval. Implicit global
9169 // receivers are indicated with the hole value.
9170 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009171}
9172
9173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009174static ObjectPair LoadContextSlotHelper(Arguments args,
9175 Isolate* isolate,
9176 bool throw_error) {
9177 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009178 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009180 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009181 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009182 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009184 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185
9186 int index;
9187 PropertyAttributes attributes;
9188 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009189 BindingFlags binding_flags;
9190 Handle<Object> holder = context->Lookup(name,
9191 flags,
9192 &index,
9193 &attributes,
9194 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009195 if (isolate->has_pending_exception()) {
9196 return MakePair(Failure::Exception(), NULL);
9197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009199 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009201 ASSERT(holder->IsContext());
9202 // If the "property" we were looking for is a local variable, the
9203 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009204 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009205 // Use the hole as the receiver to signal that the receiver is implicit
9206 // and that the global receiver should be used (as distinguished from an
9207 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009208 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009209 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009210 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009211 switch (binding_flags) {
9212 case MUTABLE_CHECK_INITIALIZED:
9213 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9214 if (value->IsTheHole()) {
9215 Handle<Object> reference_error =
9216 isolate->factory()->NewReferenceError("not_defined",
9217 HandleVector(&name, 1));
9218 return MakePair(isolate->Throw(*reference_error), NULL);
9219 }
9220 // FALLTHROUGH
9221 case MUTABLE_IS_INITIALIZED:
9222 case IMMUTABLE_IS_INITIALIZED:
9223 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9224 ASSERT(!value->IsTheHole());
9225 return MakePair(value, *receiver);
9226 case IMMUTABLE_CHECK_INITIALIZED:
9227 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9228 case MISSING_BINDING:
9229 UNREACHABLE();
9230 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232 }
9233
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009234 // Otherwise, if the slot was found the holder is a context extension
9235 // object, subject of a with, or a global object. We read the named
9236 // property from it.
9237 if (!holder.is_null()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009238 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00009239 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009240 // GetProperty below can cause GC.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009241 Handle<Object> receiver_handle(
9242 object->IsGlobalObject()
9243 ? GlobalObject::cast(*object)->global_receiver()
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009244 : object->IsJSProxy() ? static_cast<Object*>(*object)
9245 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009246 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009247
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009248 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009249 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009250 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009251 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 }
9253
9254 if (throw_error) {
9255 // The property doesn't exist - throw exception.
9256 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 isolate->factory()->NewReferenceError("not_defined",
9258 HandleVector(&name, 1));
9259 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009261 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009262 return MakePair(isolate->heap()->undefined_value(),
9263 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 }
9265}
9266
9267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009268RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270}
9271
9272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009273RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275}
9276
9277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009278RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009280 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009282 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009283 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9284 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009285 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9286 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9287 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288
9289 int index;
9290 PropertyAttributes attributes;
9291 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009292 BindingFlags binding_flags;
9293 Handle<Object> holder = context->Lookup(name,
9294 flags,
9295 &index,
9296 &attributes,
9297 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009298 if (isolate->has_pending_exception()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299
9300 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009301 // The property was found in a context slot.
9302 Handle<Context> context = Handle<Context>::cast(holder);
9303 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9304 context->get(index)->IsTheHole()) {
9305 Handle<Object> error =
9306 isolate->factory()->NewReferenceError("not_defined",
9307 HandleVector(&name, 1));
9308 return isolate->Throw(*error);
9309 }
9310 // Ignore if read_only variable.
9311 if ((attributes & READ_ONLY) == 0) {
9312 // Context is a fixed array and set cannot fail.
9313 context->set(index, *value);
9314 } else if (strict_mode == kStrictMode) {
9315 // Setting read only property in strict mode.
9316 Handle<Object> error =
9317 isolate->factory()->NewTypeError("strict_cannot_assign",
9318 HandleVector(&name, 1));
9319 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320 }
9321 return *value;
9322 }
9323
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009324 // Slow case: The property is not in a context slot. It is either in a
9325 // context extension object, a property of the subject of a with, or a
9326 // property of the global object.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009327 Handle<JSReceiver> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009328
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009329 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009330 // The property exists on the holder.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009331 object = Handle<JSReceiver>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009333 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009335
9336 if (strict_mode == kStrictMode) {
9337 // Throw in strict mode (assignment to undefined variable).
9338 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009339 isolate->factory()->NewReferenceError(
9340 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009341 return isolate->Throw(*error);
9342 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009343 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 attributes = NONE;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009345 object = Handle<JSReceiver>(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346 }
9347
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009348 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009349 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009350 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009351 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009353 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009354 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009355 // Setting read only property in strict mode.
9356 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 isolate->factory()->NewTypeError(
9358 "strict_cannot_assign", HandleVector(&name, 1));
9359 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360 }
9361 return *value;
9362}
9363
9364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009365RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 ASSERT(args.length() == 1);
9368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370}
9371
9372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009373RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009374 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 ASSERT(args.length() == 1);
9376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378}
9379
9380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009381RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009382 SealHandleScope shs(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009383 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009384 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009385}
9386
9387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009388RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009389 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390 ASSERT(args.length() == 1);
9391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 isolate->factory()->NewReferenceError("not_defined",
9395 HandleVector(&name, 1));
9396 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397}
9398
9399
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) {
9401 HandleScope scope(isolate);
9402 ASSERT(args.length() == 0);
9403 return isolate->Throw(*isolate->factory()->NewTypeError(
9404 "not_date_object", HandleVector<Object>(NULL, 0)));
9405}
9406
9407
9408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009409RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009410 SealHandleScope shs(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009411 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412
9413 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 if (isolate->stack_guard()->IsStackOverflow()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009417
ulan@chromium.org812308e2012-02-29 15:58:45 +00009418 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419}
9420
9421
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00009422RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) {
9423 HandleScope scope(isolate);
9424 ASSERT(args.length() == 1);
9425 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9426
9427 // First check if this is a real stack overflow.
9428 if (isolate->stack_guard()->IsStackOverflow()) {
9429 SealHandleScope shs(isolate);
9430 return isolate->StackOverflow();
9431 }
9432
9433 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9434 return (function->IsOptimized()) ? function->code()
9435 : function->shared()->code();
9436}
9437
9438
yangguo@chromium.org56454712012-02-16 15:33:53 +00009439RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009440 SealHandleScope shs(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009441 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009442 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009443}
9444
9445
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009446static int StackSize(Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 int n = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009448 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 return n;
9450}
9451
9452
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009453static void PrintTransition(Isolate* isolate, Object* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 // indentation
9455 { const int nmax = 80;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009456 int n = StackSize(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457 if (n <= nmax)
9458 PrintF("%4d:%*s", n, n, "");
9459 else
9460 PrintF("%4d:%*s", n, nmax, "...");
9461 }
9462
9463 if (result == NULL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009464 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009465 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 } else {
9467 // function result
9468 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009469 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009470 PrintF("\n");
9471 }
9472}
9473
9474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009475RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009476 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009477 ASSERT(args.length() == 0);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009478 PrintTransition(isolate, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480}
9481
9482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009483RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009484 SealHandleScope shs(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009485 PrintTransition(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486 return args[0]; // return TOS
9487}
9488
9489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009490RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009491 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 ASSERT(args.length() == 1);
9493
9494#ifdef DEBUG
9495 if (args[0]->IsString()) {
9496 // If we have a string, assume it's a code "marker"
9497 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009498 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009500 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9501 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 } else {
9503 PrintF("DebugPrint: ");
9504 }
9505 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009506 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009507 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009508 HeapObject::cast(args[0])->map()->Print();
9509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009511 // ShortPrint is available in release mode. Print is not.
9512 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513#endif
9514 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009515 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516
9517 return args[0]; // return TOS
9518}
9519
9520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009521RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009522 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009523 ASSERT(args.length() == 0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00009524 isolate->PrintStack(stdout);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526}
9527
9528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009530 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +00009531 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532
9533 // According to ECMA-262, section 15.9.1, page 117, the precision of
9534 // the number in a Date object representing a particular instant in
9535 // time is milliseconds. Therefore, we floor the result of getting
9536 // the OS time.
9537 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539}
9540
9541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009542RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009544 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009546 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009547 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009549 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009550
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009551 JSObject::EnsureCanContainHeapObjectElements(output);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009552 RUNTIME_ASSERT(output->HasFastObjectElements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009553
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009554 DisallowHeapAllocation no_gc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009555
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009556 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009557 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9558 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009559 String::FlatContent str_content = str->GetFlatContent();
9560 if (str_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009561 result = DateParser::Parse(str_content.ToOneByteVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009562 output_array,
9563 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009565 ASSERT(str_content.IsTwoByte());
9566 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009567 output_array,
9568 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009569 }
9570
9571 if (result) {
9572 return *output;
9573 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009575 }
9576}
9577
9578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009579RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009580 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 ASSERT(args.length() == 1);
9582
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009583 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009584 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9585 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587}
9588
9589
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009590RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009591 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 ASSERT(args.length() == 1);
9593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009595 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9596
9597 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598}
9599
9600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009601RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009602 SealHandleScope shs(isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009603 ASSERT(args.length() == 1);
9604 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009605 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009606 return JSGlobalObject::cast(global)->global_receiver();
9607}
9608
9609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009610RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009612 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009613 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009614
danno@chromium.org59400602013-08-13 17:09:37 +00009615 source = Handle<String>(FlattenGetString(source));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009616 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009617 Handle<Object> result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009618 if (source->IsSeqOneByteString()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009619 result = JsonParser<true>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009620 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009621 result = JsonParser<false>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009622 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009623 if (result.is_null()) {
9624 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009626 return Failure::Exception();
9627 }
9628 return *result;
9629}
9630
9631
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009632bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9633 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009634 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9635 // Check with callback if set.
9636 AllowCodeGenerationFromStringsCallback callback =
9637 isolate->allow_code_gen_callback();
9638 if (callback == NULL) {
9639 // No callback set and code generation disallowed.
9640 return false;
9641 } else {
9642 // Callback set. Let it decide if code generation is allowed.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009643 VMState<EXTERNAL> state(isolate);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009644 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009645 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009646}
9647
9648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009649RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009650 HandleScope scope(isolate);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009651 ASSERT_EQ(2, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009652 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009653 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009654
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009655 // Extract native context.
9656 Handle<Context> context(isolate->context()->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009657
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009658 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009659 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009660 if (context->allow_code_gen_from_strings()->IsFalse() &&
9661 !CodeGenerationFromStringsAllowed(isolate, context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009662 Handle<Object> error_message =
9663 context->ErrorMessageForCodeGenerationFromStrings();
9664 return isolate->Throw(*isolate->factory()->NewEvalError(
9665 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009666 }
9667
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009668 // Compile source string in the native context.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009669 ParseRestriction restriction = function_literal_only
9670 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009671 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009672 source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009673 RETURN_IF_EMPTY_HANDLE(isolate, shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9676 context,
9677 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009678 return *fun;
9679}
9680
9681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009682static ObjectPair CompileGlobalEval(Isolate* isolate,
9683 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009684 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009685 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009686 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009687 Handle<Context> context = Handle<Context>(isolate->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009688 Handle<Context> native_context = Handle<Context>(context->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009689
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009690 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009691 // strings. Throw an exception if it doesn't.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009692 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9693 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009694 Handle<Object> error_message =
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00009695 native_context->ErrorMessageForCodeGenerationFromStrings();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009696 isolate->Throw(*isolate->factory()->NewEvalError(
9697 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009698 return MakePair(Failure::Exception(), NULL);
9699 }
9700
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009701 // Deal with a normal eval call with a string argument. Compile it
9702 // and return the compiled function bound in the local context.
9703 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9704 source,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00009705 context,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009706 context->IsNativeContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009707 language_mode,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009708 NO_PARSE_RESTRICTION,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009709 scope_position);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009710 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared,
9711 MakePair(Failure::Exception(), NULL));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 Handle<JSFunction> compiled =
9713 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009714 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009715 return MakePair(*compiled, *receiver);
9716}
9717
9718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009719RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009720 HandleScope scope(isolate);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009721 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009722
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009723 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009724
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009725 // If "eval" didn't refer to the original GlobalEval, it's not a
9726 // direct call to eval.
9727 // (And even if it is, but the first argument isn't a string, just let
9728 // execution default to an indirect call to eval, which will also return
9729 // the first argument without doing anything).
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009730 if (*callee != isolate->native_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009731 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009732 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009733 }
9734
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009735 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009736 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 return CompileGlobalEval(isolate,
9738 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009739 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009740 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009741 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009742}
9743
9744
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009745static MaybeObject* Allocate(Isolate* isolate,
9746 int size,
9747 AllocationSpace space) {
9748 // Allocate a block of memory in the given space (filled with a filler).
9749 // Use as fallback for allocation in generated code when the space
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009750 // is full.
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009751 SealHandleScope shs(isolate);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009752 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9753 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 Heap* heap = isolate->heap();
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009755 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009756 Object* allocation;
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009757 { MaybeObject* maybe_allocation;
9758 if (space == NEW_SPACE) {
9759 maybe_allocation = heap->new_space()->AllocateRaw(size);
9760 } else {
9761 ASSERT(space == OLD_POINTER_SPACE || space == OLD_DATA_SPACE);
9762 maybe_allocation = heap->paged_space(space)->AllocateRaw(size);
9763 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009764 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009766 }
9767 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009768 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009769}
9770
9771
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009772RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009773 SealHandleScope shs(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009774 ASSERT(args.length() == 1);
9775 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009776 return Allocate(isolate, size_smi->value(), NEW_SPACE);
9777}
9778
9779
9780RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInOldPointerSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009781 SealHandleScope shs(isolate);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009782 ASSERT(args.length() == 1);
9783 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
9784 return Allocate(isolate, size_smi->value(), OLD_POINTER_SPACE);
9785}
9786
9787
9788RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInOldDataSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009789 SealHandleScope shs(isolate);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009790 ASSERT(args.length() == 1);
9791 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
9792 return Allocate(isolate, size_smi->value(), OLD_DATA_SPACE);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009793}
9794
9795
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009796// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009797// array. Returns true if the element was pushed on the stack and
9798// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009799RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009800 SealHandleScope shs(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009801 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009802 CONVERT_ARG_CHECKED(JSArray, array, 0);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00009803 CONVERT_ARG_CHECKED(JSReceiver, element, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009804 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009805 int length = Smi::cast(array->length())->value();
9806 FixedArray* elements = FixedArray::cast(array->elements());
9807 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009808 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009809 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009810 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009811 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009812 { MaybeObject* maybe_obj =
9813 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009814 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009817}
9818
9819
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009820/**
9821 * A simple visitor visits every element of Array's.
9822 * The backend storage can be a fixed array for fast elements case,
9823 * or a dictionary for sparse array. Since Dictionary is a subtype
9824 * of FixedArray, the class can be used by both fast and slow cases.
9825 * The second parameter of the constructor, fast_elements, specifies
9826 * whether the storage is a FixedArray or Dictionary.
9827 *
9828 * An index limit is used to deal with the situation that a result array
9829 * length overflows 32-bit non-negative integer.
9830 */
9831class ArrayConcatVisitor {
9832 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 ArrayConcatVisitor(Isolate* isolate,
9834 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009835 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 isolate_(isolate),
9837 storage_(Handle<FixedArray>::cast(
9838 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 index_offset_(0u),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009840 fast_elements_(fast_elements),
9841 exceeds_array_limit_(false) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009842
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009843 ~ArrayConcatVisitor() {
9844 clear_storage();
9845 }
9846
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009847 void visit(uint32_t i, Handle<Object> elm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009848 if (i > JSObject::kMaxElementCount - index_offset_) {
9849 exceeds_array_limit_ = true;
9850 return;
9851 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009852 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009853
9854 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 if (index < static_cast<uint32_t>(storage_->length())) {
9856 storage_->set(index, *elm);
9857 return;
9858 }
9859 // Our initial estimate of length was foiled, possibly by
9860 // getters on the arrays increasing the length of later arrays
9861 // during iteration.
9862 // This shouldn't happen in anything but pathological cases.
9863 SetDictionaryMode(index);
9864 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009865 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009866 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009867 Handle<SeededNumberDictionary> dict(
9868 SeededNumberDictionary::cast(*storage_));
9869 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009870 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009871 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009872 // Dictionary needed to grow.
9873 clear_storage();
9874 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009875 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009876 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009877
9878 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9880 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009881 } else {
9882 index_offset_ += delta;
9883 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009884 }
9885
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009886 bool exceeds_array_limit() {
9887 return exceeds_array_limit_;
9888 }
9889
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009890 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009891 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009892 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009893 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009894 Handle<Map> map;
9895 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009896 map = isolate_->factory()->GetElementsTransitionMap(array,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009897 FAST_HOLEY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009898 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009899 map = isolate_->factory()->GetElementsTransitionMap(array,
9900 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009901 }
9902 array->set_map(*map);
9903 array->set_length(*length);
9904 array->set_elements(*storage_);
9905 return array;
9906 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009907
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009908 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009909 // Convert storage to dictionary mode.
9910 void SetDictionaryMode(uint32_t index) {
9911 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009912 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009913 Handle<SeededNumberDictionary> slow_storage(
9914 isolate_->factory()->NewSeededNumberDictionary(
9915 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009916 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9917 for (uint32_t i = 0; i < current_length; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009918 HandleScope loop_scope(isolate_);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009919 Handle<Object> element(current_storage->get(i), isolate_);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009920 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009921 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009923 if (!new_storage.is_identical_to(slow_storage)) {
9924 slow_storage = loop_scope.CloseAndEscape(new_storage);
9925 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009926 }
9927 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009928 clear_storage();
9929 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 fast_elements_ = false;
9931 }
9932
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009933 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 isolate_->global_handles()->Destroy(
9935 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009936 }
9937
9938 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009939 storage_ = Handle<FixedArray>::cast(
9940 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009941 }
9942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009944 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009945 // Index after last seen index. Always less than or equal to
9946 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009947 uint32_t index_offset_;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009948 bool fast_elements_ : 1;
9949 bool exceeds_array_limit_ : 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009950};
9951
9952
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009953static uint32_t EstimateElementCount(Handle<JSArray> array) {
9954 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9955 int element_count = 0;
9956 switch (array->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009957 case FAST_SMI_ELEMENTS:
9958 case FAST_HOLEY_SMI_ELEMENTS:
9959 case FAST_ELEMENTS:
9960 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009961 // Fast elements can't have lengths that are not representable by
9962 // a 32-bit signed integer.
9963 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9964 int fast_length = static_cast<int>(length);
9965 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9966 for (int i = 0; i < fast_length; i++) {
9967 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009968 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009969 break;
9970 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009971 case FAST_DOUBLE_ELEMENTS:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009972 case FAST_HOLEY_DOUBLE_ELEMENTS: {
9973 // Fast elements can't have lengths that are not representable by
9974 // a 32-bit signed integer.
9975 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
9976 int fast_length = static_cast<int>(length);
9977 if (array->elements()->IsFixedArray()) {
9978 ASSERT(FixedArray::cast(array->elements())->length() == 0);
9979 break;
9980 }
9981 Handle<FixedDoubleArray> elements(
9982 FixedDoubleArray::cast(array->elements()));
9983 for (int i = 0; i < fast_length; i++) {
9984 if (!elements->is_the_hole(i)) element_count++;
9985 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009986 break;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009989 Handle<SeededNumberDictionary> dictionary(
9990 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 int capacity = dictionary->Capacity();
9992 for (int i = 0; i < capacity; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009993 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 if (dictionary->IsKey(*key)) {
9995 element_count++;
9996 }
9997 }
9998 break;
9999 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010000 case NON_STRICT_ARGUMENTS_ELEMENTS:
10001 case EXTERNAL_BYTE_ELEMENTS:
10002 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10003 case EXTERNAL_SHORT_ELEMENTS:
10004 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10005 case EXTERNAL_INT_ELEMENTS:
10006 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10007 case EXTERNAL_FLOAT_ELEMENTS:
10008 case EXTERNAL_DOUBLE_ELEMENTS:
10009 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010010 // External arrays are always dense.
10011 return length;
10012 }
10013 // As an estimate, we assume that the prototype doesn't contain any
10014 // inherited elements.
10015 return element_count;
10016}
10017
10018
10019
10020template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021static void IterateExternalArrayElements(Isolate* isolate,
10022 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010023 bool elements_are_ints,
10024 bool elements_are_guaranteed_smis,
10025 ArrayConcatVisitor* visitor) {
10026 Handle<ExternalArrayClass> array(
10027 ExternalArrayClass::cast(receiver->elements()));
10028 uint32_t len = static_cast<uint32_t>(array->length());
10029
10030 ASSERT(visitor != NULL);
10031 if (elements_are_ints) {
10032 if (elements_are_guaranteed_smis) {
10033 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010034 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010035 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10036 isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 visitor->visit(j, e);
10038 }
10039 } else {
10040 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010041 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010042 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010043 if (Smi::IsValid(static_cast<intptr_t>(val))) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010044 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010045 visitor->visit(j, e);
10046 } else {
10047 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 visitor->visit(j, e);
10050 }
10051 }
10052 }
10053 } else {
10054 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010056 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 visitor->visit(j, e);
10058 }
10059 }
10060}
10061
10062
10063// Used for sorting indices in a List<uint32_t>.
10064static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10065 uint32_t a = *ap;
10066 uint32_t b = *bp;
10067 return (a == b) ? 0 : (a < b) ? -1 : 1;
10068}
10069
10070
10071static void CollectElementIndices(Handle<JSObject> object,
10072 uint32_t range,
10073 List<uint32_t>* indices) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010074 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010075 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010076 switch (kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010077 case FAST_SMI_ELEMENTS:
10078 case FAST_ELEMENTS:
10079 case FAST_HOLEY_SMI_ELEMENTS:
10080 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010081 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10082 uint32_t length = static_cast<uint32_t>(elements->length());
10083 if (range < length) length = range;
10084 for (uint32_t i = 0; i < length; i++) {
10085 if (!elements->get(i)->IsTheHole()) {
10086 indices->Add(i);
10087 }
10088 }
10089 break;
10090 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010091 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010092 case FAST_DOUBLE_ELEMENTS: {
10093 // TODO(1810): Decide if it's worthwhile to implement this.
10094 UNREACHABLE();
10095 break;
10096 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010097 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010098 Handle<SeededNumberDictionary> dict(
10099 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010100 uint32_t capacity = dict->Capacity();
10101 for (uint32_t j = 0; j < capacity; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010102 HandleScope loop_scope(isolate);
10103 Handle<Object> k(dict->KeyAt(j), isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010104 if (dict->IsKey(*k)) {
10105 ASSERT(k->IsNumber());
10106 uint32_t index = static_cast<uint32_t>(k->Number());
10107 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010108 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010109 }
10110 }
10111 }
10112 break;
10113 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010114 default: {
10115 int dense_elements_length;
10116 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010117 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010118 dense_elements_length =
10119 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010120 break;
10121 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010122 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010123 dense_elements_length =
10124 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010125 break;
10126 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010127 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010128 dense_elements_length =
10129 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010130 break;
10131 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010132 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010133 dense_elements_length =
10134 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010135 break;
10136 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010137 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010138 dense_elements_length =
10139 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010140 break;
10141 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010142 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010143 dense_elements_length =
10144 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010145 break;
10146 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010147 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010148 dense_elements_length =
10149 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010150 break;
10151 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010152 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010153 dense_elements_length =
10154 ExternalFloatArray::cast(object->elements())->length();
10155 break;
10156 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010157 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010158 dense_elements_length =
10159 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010160 break;
10161 }
10162 default:
10163 UNREACHABLE();
10164 dense_elements_length = 0;
10165 break;
10166 }
10167 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10168 if (range <= length) {
10169 length = range;
10170 // We will add all indices, so we might as well clear it first
10171 // and avoid duplicates.
10172 indices->Clear();
10173 }
10174 for (uint32_t i = 0; i < length; i++) {
10175 indices->Add(i);
10176 }
10177 if (length == range) return; // All indices accounted for already.
10178 break;
10179 }
10180 }
10181
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010182 Handle<Object> prototype(object->GetPrototype(), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010183 if (prototype->IsJSObject()) {
10184 // The prototype will usually have no inherited element indices,
10185 // but we have to check.
10186 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10187 }
10188}
10189
10190
10191/**
10192 * A helper function that visits elements of a JSArray in numerical
10193 * order.
10194 *
10195 * The visitor argument called for each existing element in the array
10196 * with the element index and the element's value.
10197 * Afterwards it increments the base-index of the visitor by the array
10198 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010199 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010200 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201static bool IterateElements(Isolate* isolate,
10202 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010203 ArrayConcatVisitor* visitor) {
10204 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10205 switch (receiver->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010206 case FAST_SMI_ELEMENTS:
10207 case FAST_ELEMENTS:
10208 case FAST_HOLEY_SMI_ELEMENTS:
10209 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010210 // Run through the elements FixedArray and use HasElement and GetElement
10211 // to check the prototype for missing elements.
10212 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10213 int fast_length = static_cast<int>(length);
10214 ASSERT(fast_length <= elements->length());
10215 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 HandleScope loop_scope(isolate);
10217 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010218 if (!element_value->IsTheHole()) {
10219 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010220 } else if (JSReceiver::HasElement(receiver, j)) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010221 // Call GetElement on receiver, not its prototype, or getters won't
10222 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010223 element_value = Object::GetElement(isolate, receiver, j);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010224 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010225 visitor->visit(j, element_value);
10226 }
10227 }
10228 break;
10229 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010230 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010231 case FAST_DOUBLE_ELEMENTS: {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010232 // Run through the elements FixedArray and use HasElement and GetElement
10233 // to check the prototype for missing elements.
10234 Handle<FixedDoubleArray> elements(
10235 FixedDoubleArray::cast(receiver->elements()));
10236 int fast_length = static_cast<int>(length);
10237 ASSERT(fast_length <= elements->length());
10238 for (int j = 0; j < fast_length; j++) {
10239 HandleScope loop_scope(isolate);
10240 if (!elements->is_the_hole(j)) {
10241 double double_value = elements->get_scalar(j);
10242 Handle<Object> element_value =
10243 isolate->factory()->NewNumber(double_value);
10244 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010245 } else if (JSReceiver::HasElement(receiver, j)) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010246 // Call GetElement on receiver, not its prototype, or getters won't
10247 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010248 Handle<Object> element_value =
10249 Object::GetElement(isolate, receiver, j);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010250 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10251 visitor->visit(j, element_value);
10252 }
10253 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010254 break;
10255 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010256 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010257 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010258 List<uint32_t> indices(dict->Capacity() / 2);
10259 // Collect all indices in the object and the prototypes less
10260 // than length. This might introduce duplicates in the indices list.
10261 CollectElementIndices(receiver, length, &indices);
10262 indices.Sort(&compareUInt32);
10263 int j = 0;
10264 int n = indices.length();
10265 while (j < n) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010266 HandleScope loop_scope(isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010267 uint32_t index = indices[j];
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010268 Handle<Object> element = Object::GetElement(isolate, receiver, index);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010269 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010270 visitor->visit(index, element);
10271 // Skip to next different index (i.e., omit duplicates).
10272 do {
10273 j++;
10274 } while (j < n && indices[j] == index);
10275 }
10276 break;
10277 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010278 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010279 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10280 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010281 for (uint32_t j = 0; j < length; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010282 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010283 visitor->visit(j, e);
10284 }
10285 break;
10286 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010287 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010288 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010289 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010290 break;
10291 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010292 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010293 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010294 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010295 break;
10296 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010297 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010298 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010299 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010300 break;
10301 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010302 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010303 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010305 break;
10306 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010307 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010308 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010309 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010310 break;
10311 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010312 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010313 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010314 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010315 break;
10316 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010317 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010318 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010319 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010320 break;
10321 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010322 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010323 IterateExternalArrayElements<ExternalDoubleArray, double>(
10324 isolate, receiver, false, false, visitor);
10325 break;
10326 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010327 default:
10328 UNREACHABLE();
10329 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010330 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010331 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010332 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010333}
10334
10335
10336/**
10337 * Array::concat implementation.
10338 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010339 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010340 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010341 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010342RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010343 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010344 ASSERT(args.length() == 1);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010345
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010346 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010347 int argument_count = static_cast<int>(arguments->length()->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010348 RUNTIME_ASSERT(arguments->HasFastObjectElements());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010349 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010350
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010351 // Pass 1: estimate the length and number of elements of the result.
10352 // The actual length can be larger if any of the arguments have getters
10353 // that mutate other arguments (but will otherwise be precise).
10354 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010355
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010356 ElementsKind kind = FAST_SMI_ELEMENTS;
10357
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010358 uint32_t estimate_result_length = 0;
10359 uint32_t estimate_nof_elements = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010360 for (int i = 0; i < argument_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010361 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010362 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010363 uint32_t length_estimate;
10364 uint32_t element_estimate;
10365 if (obj->IsJSArray()) {
10366 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10367 length_estimate = static_cast<uint32_t>(array->length()->Number());
10368 if (length_estimate != 0) {
10369 ElementsKind array_kind =
10370 GetPackedElementsKind(array->map()->elements_kind());
10371 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10372 kind = array_kind;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010373 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010374 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010375 element_estimate = EstimateElementCount(array);
10376 } else {
10377 if (obj->IsHeapObject()) {
10378 if (obj->IsNumber()) {
10379 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10380 kind = FAST_DOUBLE_ELEMENTS;
10381 }
10382 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10383 kind = FAST_ELEMENTS;
10384 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010385 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010386 length_estimate = 1;
10387 element_estimate = 1;
10388 }
10389 // Avoid overflows by capping at kMaxElementCount.
10390 if (JSObject::kMaxElementCount - estimate_result_length <
10391 length_estimate) {
10392 estimate_result_length = JSObject::kMaxElementCount;
10393 } else {
10394 estimate_result_length += length_estimate;
10395 }
10396 if (JSObject::kMaxElementCount - estimate_nof_elements <
10397 element_estimate) {
10398 estimate_nof_elements = JSObject::kMaxElementCount;
10399 } else {
10400 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010401 }
10402 }
10403
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010404 // If estimated number of elements is more than half of length, a
10405 // fixed array (fast case) is more time and space-efficient than a
10406 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010407 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010408
10409 Handle<FixedArray> storage;
10410 if (fast_case) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010411 if (kind == FAST_DOUBLE_ELEMENTS) {
10412 Handle<FixedDoubleArray> double_storage =
10413 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10414 int j = 0;
10415 bool failure = false;
10416 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010417 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010418 if (obj->IsSmi()) {
10419 double_storage->set(j, Smi::cast(*obj)->value());
10420 j++;
10421 } else if (obj->IsNumber()) {
10422 double_storage->set(j, obj->Number());
10423 j++;
10424 } else {
10425 JSArray* array = JSArray::cast(*obj);
10426 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10427 switch (array->map()->elements_kind()) {
10428 case FAST_HOLEY_DOUBLE_ELEMENTS:
10429 case FAST_DOUBLE_ELEMENTS: {
10430 // Empty fixed array indicates that there are no elements.
10431 if (array->elements()->IsFixedArray()) break;
10432 FixedDoubleArray* elements =
10433 FixedDoubleArray::cast(array->elements());
10434 for (uint32_t i = 0; i < length; i++) {
10435 if (elements->is_the_hole(i)) {
10436 failure = true;
10437 break;
10438 }
10439 double double_value = elements->get_scalar(i);
10440 double_storage->set(j, double_value);
10441 j++;
10442 }
10443 break;
10444 }
10445 case FAST_HOLEY_SMI_ELEMENTS:
10446 case FAST_SMI_ELEMENTS: {
10447 FixedArray* elements(
10448 FixedArray::cast(array->elements()));
10449 for (uint32_t i = 0; i < length; i++) {
10450 Object* element = elements->get(i);
10451 if (element->IsTheHole()) {
10452 failure = true;
10453 break;
10454 }
10455 int32_t int_value = Smi::cast(element)->value();
10456 double_storage->set(j, int_value);
10457 j++;
10458 }
10459 break;
10460 }
10461 case FAST_HOLEY_ELEMENTS:
10462 ASSERT_EQ(0, length);
10463 break;
10464 default:
10465 UNREACHABLE();
10466 }
10467 }
10468 if (failure) break;
10469 }
10470 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10471 Smi* length = Smi::FromInt(j);
10472 Handle<Map> map;
10473 map = isolate->factory()->GetElementsTransitionMap(array, kind);
10474 array->set_map(*map);
10475 array->set_length(length);
10476 array->set_elements(*double_storage);
10477 return *array;
10478 }
10479 // The backing storage array must have non-existing elements to preserve
10480 // holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010481 storage = isolate->factory()->NewFixedArrayWithHoles(
10482 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010483 } else {
10484 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10485 uint32_t at_least_space_for = estimate_nof_elements +
10486 (estimate_nof_elements >> 2);
10487 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010488 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010489 }
10490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010492
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010493 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010494 Handle<Object> obj(elements->get(i), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010495 if (obj->IsJSArray()) {
10496 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010498 return Failure::Exception();
10499 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010500 } else {
10501 visitor.visit(0, obj);
10502 visitor.increase_index_offset(1);
10503 }
10504 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010505
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000010506 if (visitor.exceeds_array_limit()) {
10507 return isolate->Throw(
10508 *isolate->factory()->NewRangeError("invalid_array_length",
10509 HandleVector<Object>(NULL, 0)));
10510 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010511 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010512}
10513
10514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515// This will not allocate (flatten the string), but it may run
10516// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010517RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010518 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 ASSERT(args.length() == 1);
10520
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010521 CONVERT_ARG_CHECKED(String, string, 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010522 ConsStringIteratorOp op;
10523 StringCharacterStream stream(string, &op);
10524 while (stream.HasMore()) {
10525 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 PrintF("%c", character);
10527 }
10528 return string;
10529}
10530
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010531
ager@chromium.org5ec48922009-05-05 07:25:34 +000010532// Moves all own elements of an object, that are below a limit, to positions
10533// starting at zero. All undefined values are placed after non-undefined values,
10534// and are followed by non-existing element. Does not change the length
10535// property.
10536// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010537RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010538 SealHandleScope shs(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010539 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010540 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010541 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10542 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010543}
10544
10545
10546// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010547RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010548 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010550 CONVERT_ARG_CHECKED(JSArray, from, 0);
10551 CONVERT_ARG_CHECKED(JSArray, to, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010552 from->ValidateElements();
10553 to->ValidateElements();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010554 FixedArrayBase* new_elements = from->elements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010555 ElementsKind from_kind = from->GetElementsKind();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010556 MaybeObject* maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010557 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010558 Object* new_map;
10559 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010560 to->set_map_and_elements(Map::cast(new_map), new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010562 Object* obj;
10563 { MaybeObject* maybe_obj = from->ResetElements();
10564 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10565 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010566 from->set_length(Smi::FromInt(0));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010567 to->ValidateElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 return to;
10569}
10570
10571
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010572// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010573RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010574 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010576 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010577 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010579 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10580 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010581 } else if (object->IsJSArray()) {
10582 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010584 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585 }
10586}
10587
10588
10589// Returns an array that tells you where in the [0, length) interval an array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010590// might have elements. Can either return an array of keys (positive integers
10591// or undefined) or a number representing the positive length of an interval
10592// starting at index 0.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010593// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010596 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010597 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010599 if (array->elements()->IsDictionary()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010600 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10601 for (Handle<Object> p = array;
10602 !p->IsNull();
10603 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10604 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10605 // Bail out if we find a proxy or interceptor, likely not worth
10606 // collecting keys in that case.
10607 return *isolate->factory()->NewNumberFromUint(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010609 Handle<JSObject> current = Handle<JSObject>::cast(p);
10610 Handle<FixedArray> current_keys =
10611 isolate->factory()->NewFixedArray(
10612 current->NumberOfLocalElements(NONE));
10613 current->GetLocalElementKeys(*current_keys, NONE);
10614 keys = UnionOfKeys(keys, current_keys);
10615 }
10616 // Erase any keys >= length.
10617 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10618 // is changed to let this happen on the JS side.
10619 for (int i = 0; i < keys->length(); i++) {
10620 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010624 ASSERT(array->HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010625 array->HasFastDoubleElements());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010626 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10627 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628 }
10629}
10630
10631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010632RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010633 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634 ASSERT(args.length() == 3);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010635 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10636 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010637 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010638 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000010639 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010640 Handle<Object> result =
10641 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component);
10642 RETURN_IF_EMPTY_HANDLE(isolate, result);
10643 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644}
10645
10646
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010647#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010648RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010649 SealHandleScope shs(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010650 ASSERT(args.length() == 0);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000010651 return Execution::DebugBreakHelper(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010652}
10653
10654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655// Helper functions for wrapping and unwrapping stack frame ids.
10656static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010657 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658 return Smi::FromInt(id >> 2);
10659}
10660
10661
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010662static StackFrame::Id UnwrapFrameId(int wrapped) {
10663 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664}
10665
10666
10667// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010668// args[0]: debug event listener function to set or null or undefined for
10669// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010671RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010672 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010674 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10675 args[0]->IsUndefined() ||
10676 args[0]->IsNull());
10677 Handle<Object> callback = args.at<Object>(0);
10678 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682}
10683
10684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010685RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010686 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010687 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010688 isolate->stack_guard()->DebugBreak();
10689 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690}
10691
10692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693static MaybeObject* DebugLookupResultValue(Heap* heap,
10694 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000010695 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010696 LookupResult* result,
10697 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010698 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010700 case NORMAL:
10701 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010702 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010703 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 }
10705 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010706 case FIELD: {
10707 Object* value;
10708 MaybeObject* maybe_value =
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010709 JSObject::cast(result->holder())->FastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010710 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010711 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010712 if (!maybe_value->To(&value)) return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010713 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010714 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010715 }
10716 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010717 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000010718 case CONSTANT:
10719 return result->GetConstant();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010720 case CALLBACKS: {
10721 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010722 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010723 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10724 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010725 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010726 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010727 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010728 maybe_value = heap->isolate()->pending_exception();
10729 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010730 if (caught_exception != NULL) {
10731 *caught_exception = true;
10732 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010733 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010734 }
10735 return value;
10736 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010737 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010738 }
10739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740 case INTERCEPTOR:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010741 case TRANSITION:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010743 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010744 case NONEXISTENT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010746 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010748 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010750}
10751
10752
ager@chromium.org32912102009-01-16 10:38:43 +000010753// Get debugger related details for an object property.
10754// args[0]: object holding property
10755// args[1]: name of the property
10756//
10757// The array returned contains the following information:
10758// 0: Property value
10759// 1: Property details
10760// 2: Property value is exception
10761// 3: Getter function if defined
10762// 4: Setter function if defined
10763// Items 2-4 are only filled if the property has either a getter or a setter
10764// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010765RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010767
10768 ASSERT(args.length() == 2);
10769
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010770 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010771 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010773 // Make sure to set the current context to the context before the debugger was
10774 // entered (if the debugger is entered). The reason for switching context here
10775 // is that for some property lookups (accessors and interceptors) callbacks
10776 // into the embedding application can occour, and the embedding application
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010777 // could have the assumption that its own native context is the current
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010778 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 SaveContext save(isolate);
10780 if (isolate->debug()->InDebugger()) {
10781 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010782 }
10783
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010784 // Skip the global proxy as it has no properties and always delegates to the
10785 // real global object.
10786 if (obj->IsJSGlobalProxy()) {
10787 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10788 }
10789
10790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 // Check if the name is trivially convertible to an index and get the element
10792 // if so.
10793 uint32_t index;
10794 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010795 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010796 Object* element_or_char;
10797 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010798 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010799 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10800 return maybe_element_or_char;
10801 }
10802 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010803 details->set(0, element_or_char);
danno@chromium.orgf005df62013-04-30 16:36:45 +000010804 details->set(
10805 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 }
10808
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010809 // Find the number of objects making up this.
10810 int length = LocalPrototypeChainLength(*obj);
10811
10812 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010813 Handle<JSObject> jsproto = obj;
10814 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010815 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010816 jsproto->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010817 if (result.IsFound()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010818 // LookupResult is not GC safe as it holds raw object pointers.
10819 // GC can happen later in this code so put the required fields into
10820 // local variables using handles when required for later use.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010821 Handle<Object> result_callback_obj;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010822 if (result.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10824 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010825 }
10826 Smi* property_details = result.GetPropertyDetails().AsSmi();
10827 // DebugLookupResultValue can cause GC so details from LookupResult needs
10828 // to be copied to handles before this.
10829 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010830 Object* raw_value;
10831 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010832 DebugLookupResultValue(isolate->heap(), *obj, *name,
10833 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010834 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010837
10838 // If the callback object is a fixed array then it contains JavaScript
10839 // getter and/or setter.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010840 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010841 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010842 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010844 details->set(0, *value);
10845 details->set(1, property_details);
10846 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010847 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010848 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010849 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10850 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010851 }
10852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010854 }
10855 if (i < length - 1) {
10856 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10857 }
10858 }
10859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861}
10862
10863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010864RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866
10867 ASSERT(args.length() == 2);
10868
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010869 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010870 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010872 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 obj->Lookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010874 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010875 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878}
10879
10880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881// Return the property type calculated from the property details.
10882// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010883RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010884 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010886 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10887 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888}
10889
10890
10891// Return the property attribute calculated from the property details.
10892// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010893RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010894 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010896 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10897 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898}
10899
10900
10901// Return the property insertion index calculated from the property details.
10902// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010903RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010904 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010905 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010906 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010907 // TODO(verwaest): Depends on the type of details.
10908 return Smi::FromInt(details.dictionary_index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909}
10910
10911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912// Return property value from named interceptor.
10913// args[0]: object
10914// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010915RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010918 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919 RUNTIME_ASSERT(obj->HasNamedInterceptor());
ulan@chromium.org750145a2013-03-07 15:14:13 +000010920 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921
10922 PropertyAttributes attributes;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000010923 Handle<Object> result =
10924 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes);
10925 RETURN_IF_EMPTY_HANDLE(isolate, result);
10926 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927}
10928
10929
10930// Return element value from indexed interceptor.
10931// args[0]: object
10932// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010933RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010934 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010936 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10938 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10939
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010940 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941}
10942
10943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010944RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010945 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 ASSERT(args.length() >= 1);
10947 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010948 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 if (isolate->debug()->break_id() == 0 ||
10950 break_id != isolate->debug()->break_id()) {
10951 return isolate->Throw(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010952 isolate->heap()->illegal_execution_state_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953 }
10954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010955 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956}
10957
10958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010959RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961 ASSERT(args.length() == 1);
10962
10963 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010964 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010965 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10966 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010967 if (!maybe_result->ToObject(&result)) return maybe_result;
10968 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969
10970 // Count all frames which are relevant to debugging stack trace.
10971 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010972 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010973 if (id == StackFrame::NO_ID) {
10974 // If there is no JavaScript stack frame count is 0.
10975 return Smi::FromInt(0);
10976 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010977
10978 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10979 n += it.frame()->GetInlineCount();
10980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 return Smi::FromInt(n);
10982}
10983
10984
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010985class FrameInspector {
10986 public:
10987 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010988 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010989 Isolate* isolate)
10990 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10991 // Calculate the deoptimized frame.
10992 if (frame->is_optimized()) {
10993 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010994 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010995 }
10996 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010997 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010998 is_optimized_ = frame_->is_optimized();
10999 }
11000
11001 ~FrameInspector() {
11002 // Get rid of the calculated deoptimized frame if any.
11003 if (deoptimized_frame_ != NULL) {
11004 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
11005 isolate_);
11006 }
11007 }
11008
11009 int GetParametersCount() {
11010 return is_optimized_
11011 ? deoptimized_frame_->parameters_count()
11012 : frame_->ComputeParametersCount();
11013 }
11014 int expression_count() { return deoptimized_frame_->expression_count(); }
11015 Object* GetFunction() {
11016 return is_optimized_
11017 ? deoptimized_frame_->GetFunction()
11018 : frame_->function();
11019 }
11020 Object* GetParameter(int index) {
11021 return is_optimized_
11022 ? deoptimized_frame_->GetParameter(index)
11023 : frame_->GetParameter(index);
11024 }
11025 Object* GetExpression(int index) {
11026 return is_optimized_
11027 ? deoptimized_frame_->GetExpression(index)
11028 : frame_->GetExpression(index);
11029 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011030 int GetSourcePosition() {
11031 return is_optimized_
11032 ? deoptimized_frame_->GetSourcePosition()
11033 : frame_->LookupCode()->SourcePosition(frame_->pc());
11034 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000011035 bool IsConstructor() {
11036 return is_optimized_ && !is_bottommost_
11037 ? deoptimized_frame_->HasConstructStub()
11038 : frame_->IsConstructor();
11039 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011040
11041 // To inspect all the provided arguments the frame might need to be
11042 // replaced with the arguments frame.
11043 void SetArgumentsFrame(JavaScriptFrame* frame) {
11044 ASSERT(has_adapted_arguments_);
11045 frame_ = frame;
11046 is_optimized_ = frame_->is_optimized();
11047 ASSERT(!is_optimized_);
11048 }
11049
11050 private:
11051 JavaScriptFrame* frame_;
11052 DeoptimizedFrameInfo* deoptimized_frame_;
11053 Isolate* isolate_;
11054 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000011055 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011056 bool has_adapted_arguments_;
11057
11058 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11059};
11060
11061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062static const int kFrameDetailsFrameIdIndex = 0;
11063static const int kFrameDetailsReceiverIndex = 1;
11064static const int kFrameDetailsFunctionIndex = 2;
11065static const int kFrameDetailsArgumentCountIndex = 3;
11066static const int kFrameDetailsLocalCountIndex = 4;
11067static const int kFrameDetailsSourcePositionIndex = 5;
11068static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011069static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011070static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011071static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011072
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011073
11074static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11075 JavaScriptFrame* frame) {
11076 SaveContext* save = isolate->save_context();
11077 while (save != NULL && !save->IsBelowFrame(frame)) {
11078 save = save->prev();
11079 }
11080 ASSERT(save != NULL);
11081 return save;
11082}
11083
11084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085// Return an array with frame details
11086// args[0]: number: break id
11087// args[1]: number: frame index
11088//
11089// The array returned contains the following information:
11090// 0: Frame id
11091// 1: Receiver
11092// 2: Function
11093// 3: Argument count
11094// 4: Local count
11095// 5: Source position
11096// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011097// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011098// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011099// Arguments name, value
11100// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011101// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011102RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104 ASSERT(args.length() == 2);
11105
11106 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011107 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011108 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11109 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011110 if (!maybe_check->ToObject(&check)) return maybe_check;
11111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011113 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114
11115 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011117 if (id == StackFrame::NO_ID) {
11118 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011120 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011123 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011124 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011125 if (index < count + it.frame()->GetInlineCount()) break;
11126 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011128 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011130 bool is_optimized = it.frame()->is_optimized();
11131
11132 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11133 if (is_optimized) {
11134 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011135 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011136 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011137 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011139 // Traverse the saved contexts chain to find the active context for the
11140 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011141 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142
11143 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011144 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011146 // Find source position in unoptimized code.
11147 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011148
ulan@chromium.org967e2702012-02-28 09:49:15 +000011149 // Check for constructor frame.
11150 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011152 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011153 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011154 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011155 Handle<ScopeInfo> scope_info(shared->scope_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011156 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011158 // Get the locals names and values into a temporary array.
11159 //
11160 // TODO(1240907): Hide compiler-introduced stack variables
11161 // (e.g. .result)? For users of the debugger, they will probably be
11162 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011163 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011164 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011165
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011166 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011167 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011168 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011169 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011170 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011171 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011172 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011173 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011174 // Get the context containing declarations.
11175 Handle<Context> context(
11176 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011177 for (; i < scope_info->LocalCount(); ++i) {
11178 Handle<String> name(scope_info->LocalName(i));
11179 VariableMode mode;
11180 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011181 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011182 locals->set(i * 2 + 1, context->get(
11183 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011184 }
11185 }
11186
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011187 // Check whether this frame is positioned at return. If not top
11188 // frame or if the frame is optimized it cannot be at a return.
11189 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011190 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011191 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011192 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011193
11194 // If positioned just before return find the value to be returned and add it
11195 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011196 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011197 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011198 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011199 Address internal_frame_sp = NULL;
11200 while (!it2.done()) {
11201 if (it2.frame()->is_internal()) {
11202 internal_frame_sp = it2.frame()->sp();
11203 } else {
11204 if (it2.frame()->is_java_script()) {
11205 if (it2.frame()->id() == it.frame()->id()) {
11206 // The internal frame just before the JavaScript frame contains the
11207 // value to return on top. A debug break at return will create an
11208 // internal frame to store the return value (eax/rax/r0) before
11209 // entering the debug break exit frame.
11210 if (internal_frame_sp != NULL) {
11211 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011212 Handle<Object>(Memory::Object_at(internal_frame_sp),
11213 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011214 break;
11215 }
11216 }
11217 }
11218
11219 // Indicate that the previous frame was not an internal frame.
11220 internal_frame_sp = NULL;
11221 }
11222 it2.Advance();
11223 }
11224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011225
11226 // Now advance to the arguments adapter frame (if any). It contains all
11227 // the provided parameters whereas the function frame always have the number
11228 // of arguments matching the functions parameters. The rest of the
11229 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011230 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011231 it.AdvanceToArgumentsFrame();
11232 frame_inspector.SetArgumentsFrame(it.frame());
11233 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011234
11235 // Find the number of arguments to fill. At least fill the number of
11236 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011237 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011238 if (argument_count < frame_inspector.GetParametersCount()) {
11239 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011240 }
11241
11242 // Calculate the size of the result.
11243 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011244 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011245 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011246 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011247
11248 // Add the frame id.
11249 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11250
11251 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011252 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253
11254 // Add the arguments count.
11255 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11256
11257 // Add the locals count
11258 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011259 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260
11261 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000011262 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011263 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11264 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011266 }
11267
11268 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011270
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011271 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011273
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011274 // Add flags to indicate information on whether this frame is
11275 // bit 0: invoked in the debugger context.
11276 // bit 1: optimized frame.
11277 // bit 2: inlined in optimized frame
11278 int flags = 0;
11279 if (*save->context() == *isolate->debug()->debug_context()) {
11280 flags |= 1 << 0;
11281 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011282 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011283 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011284 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011285 }
11286 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011287
11288 // Fill the dynamic part.
11289 int details_index = kFrameDetailsFirstDynamicIndex;
11290
11291 // Add arguments name and value.
11292 for (int i = 0; i < argument_count; i++) {
11293 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011294 if (i < scope_info->ParameterCount()) {
11295 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011296 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011297 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011298 }
11299
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011300 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011301 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011302 // Get the value from the stack.
11303 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011304 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011305 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011306 }
11307 }
11308
11309 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011310 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011311 details->set(details_index++, locals->get(i));
11312 }
11313
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011314 // Add the value being returned.
11315 if (at_return) {
11316 details->set(details_index++, *return_value);
11317 }
11318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319 // Add the receiver (same as in function frame).
11320 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11321 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011323 if (!receiver->IsJSObject() &&
11324 shared->is_classic_mode() &&
danno@chromium.orgbee51992013-07-10 14:57:15 +000011325 !function->IsBuiltin()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011326 // If the receiver is not a JSObject and the function is not a
11327 // builtin or strict-mode we have hit an optimization where a
11328 // value object is not converted into a wrapped JS objects. To
11329 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011330 // by creating correct wrapper object based on the calling frame's
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011331 // native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011332 it.Advance();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011333 Handle<Context> calling_frames_native_context(
11334 Context::cast(Context::cast(it.frame()->context())->native_context()));
danno@chromium.orgbee51992013-07-10 14:57:15 +000011335 ASSERT(!receiver->IsUndefined() && !receiver->IsNull());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011336 receiver =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011337 isolate->factory()->ToObject(receiver, calling_frames_native_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 }
11339 details->set(kFrameDetailsReceiverIndex, *receiver);
11340
11341 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011342 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011343}
11344
11345
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011346// Create a plain JSObject which materializes the local scope for the specified
11347// frame.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011348static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011349 Isolate* isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011350 Handle<JSObject> target,
11351 Handle<JSFunction> function,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011352 FrameInspector* frame_inspector) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011353 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011354 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011355
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011356 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011357 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011358 Handle<Object> value(i < frame_inspector->GetParametersCount()
11359 ? frame_inspector->GetParameter(i)
11360 : isolate->heap()->undefined_value(),
11361 isolate);
danno@chromium.org59400602013-08-13 17:09:37 +000011362 ASSERT(!value->IsTheHole());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011363
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011364 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011366 SetProperty(isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011367 target,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011368 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011369 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011370 NONE,
11371 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011372 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011373 }
11374
11375 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011376 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011377 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11378 if (value->IsTheHole()) continue;
11379
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011380 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011382 SetProperty(isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011383 target,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011384 Handle<String>(scope_info->StackLocalName(i)),
danno@chromium.org59400602013-08-13 17:09:37 +000011385 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011386 NONE,
11387 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011388 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011389 }
11390
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011391 return target;
11392}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011393
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011394
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011395static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11396 Handle<JSObject> target,
11397 Handle<JSFunction> function,
11398 JavaScriptFrame* frame,
11399 int inlined_jsframe_index) {
11400 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11401 // Optimized frames are not supported.
11402 // TODO(yangguo): make sure all code deoptimized when debugger is active
11403 // and assert that this cannot happen.
11404 return;
11405 }
11406
11407 Handle<SharedFunctionInfo> shared(function->shared());
11408 Handle<ScopeInfo> scope_info(shared->scope_info());
11409
11410 // Parameters.
11411 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011412 ASSERT(!frame->GetParameter(i)->IsTheHole());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011413 HandleScope scope(isolate);
11414 Handle<Object> value = GetProperty(
11415 isolate, target, Handle<String>(scope_info->ParameterName(i)));
11416 frame->SetParameterValue(i, *value);
11417 }
11418
11419 // Stack locals.
11420 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011421 if (frame->GetExpression(i)->IsTheHole()) continue;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011422 HandleScope scope(isolate);
11423 Handle<Object> value = GetProperty(
11424 isolate, target, Handle<String>(scope_info->StackLocalName(i)));
11425 frame->SetExpression(i, *value);
11426 }
11427}
11428
11429
11430static Handle<JSObject> MaterializeLocalContext(Isolate* isolate,
11431 Handle<JSObject> target,
11432 Handle<JSFunction> function,
11433 JavaScriptFrame* frame) {
11434 HandleScope scope(isolate);
11435 Handle<SharedFunctionInfo> shared(function->shared());
11436 Handle<ScopeInfo> scope_info(shared->scope_info());
11437
11438 if (!scope_info->HasContext()) return target;
11439
11440 // Third fill all context locals.
11441 Handle<Context> frame_context(Context::cast(frame->context()));
11442 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011443 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11444 scope_info, function_context, target)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011445 return Handle<JSObject>();
11446 }
11447
11448 // Finally copy any properties from the function context extension.
11449 // These will be variables introduced by eval.
11450 if (function_context->closure() == *function) {
11451 if (function_context->has_extension() &&
11452 !function_context->IsNativeContext()) {
11453 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11454 bool threw = false;
11455 Handle<FixedArray> keys =
11456 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11457 if (threw) return Handle<JSObject>();
11458
11459 for (int i = 0; i < keys->length(); i++) {
11460 // Names of variables introduced by eval are strings.
11461 ASSERT(keys->get(i)->IsString());
11462 Handle<String> key(String::cast(keys->get(i)));
11463 RETURN_IF_EMPTY_HANDLE_VALUE(
11464 isolate,
11465 SetProperty(isolate,
11466 target,
11467 key,
11468 GetProperty(isolate, ext, key),
11469 NONE,
11470 kNonStrictMode),
11471 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472 }
11473 }
11474 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011475
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011476 return target;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011477}
11478
11479
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011480static Handle<JSObject> MaterializeLocalScope(
11481 Isolate* isolate,
11482 JavaScriptFrame* frame,
11483 int inlined_jsframe_index) {
11484 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011485 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11486
11487 Handle<JSObject> local_scope =
11488 isolate->factory()->NewJSObject(isolate->object_function());
11489 local_scope = MaterializeStackLocalsWithFrameInspector(
11490 isolate, local_scope, function, &frame_inspector);
11491 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
11492
11493 return MaterializeLocalContext(isolate, local_scope, function, frame);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011494}
11495
11496
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011497// Set the context local variable value.
11498static bool SetContextLocalValue(Isolate* isolate,
11499 Handle<ScopeInfo> scope_info,
11500 Handle<Context> context,
11501 Handle<String> variable_name,
11502 Handle<Object> new_value) {
11503 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11504 Handle<String> next_name(scope_info->ContextLocalName(i));
11505 if (variable_name->Equals(*next_name)) {
11506 VariableMode mode;
11507 InitializationFlag init_flag;
11508 int context_index =
11509 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
11510 context->set(context_index, *new_value);
11511 return true;
11512 }
11513 }
11514
11515 return false;
11516}
11517
11518
11519static bool SetLocalVariableValue(Isolate* isolate,
11520 JavaScriptFrame* frame,
11521 int inlined_jsframe_index,
11522 Handle<String> variable_name,
11523 Handle<Object> new_value) {
11524 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11525 // Optimized frames are not supported.
11526 return false;
11527 }
11528
danno@chromium.org169691d2013-07-15 08:01:13 +000011529 Handle<JSFunction> function(frame->function());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011530 Handle<SharedFunctionInfo> shared(function->shared());
11531 Handle<ScopeInfo> scope_info(shared->scope_info());
11532
11533 bool default_result = false;
11534
11535 // Parameters.
11536 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11537 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
11538 frame->SetParameterValue(i, *new_value);
11539 // Argument might be shadowed in heap context, don't stop here.
11540 default_result = true;
11541 }
11542 }
11543
11544 // Stack locals.
11545 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11546 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
11547 frame->SetExpression(i, *new_value);
11548 return true;
11549 }
11550 }
11551
11552 if (scope_info->HasContext()) {
11553 // Context locals.
11554 Handle<Context> frame_context(Context::cast(frame->context()));
11555 Handle<Context> function_context(frame_context->declaration_context());
11556 if (SetContextLocalValue(
11557 isolate, scope_info, function_context, variable_name, new_value)) {
11558 return true;
11559 }
11560
11561 // Function context extension. These are variables introduced by eval.
11562 if (function_context->closure() == *function) {
11563 if (function_context->has_extension() &&
11564 !function_context->IsNativeContext()) {
11565 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11566
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011567 if (JSReceiver::HasProperty(ext, variable_name)) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011568 // We don't expect this to do anything except replacing
11569 // property value.
11570 SetProperty(isolate,
11571 ext,
11572 variable_name,
11573 new_value,
11574 NONE,
11575 kNonStrictMode);
11576 return true;
11577 }
11578 }
11579 }
11580 }
11581
11582 return default_result;
11583}
11584
11585
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011586// Create a plain JSObject which materializes the closure content for the
11587// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11589 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011590 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011592 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011593 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011594
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011595 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011596 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 Handle<JSObject> closure_scope =
11598 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011599
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011600 // Fill all context locals to the context extension.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011601 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11602 scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011603 return Handle<JSObject>();
11604 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605
11606 // Finally copy any properties from the function context extension. This will
11607 // be variables introduced by eval.
11608 if (context->has_extension()) {
11609 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011610 bool threw = false;
11611 Handle<FixedArray> keys =
11612 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11613 if (threw) return Handle<JSObject>();
11614
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011615 for (int i = 0; i < keys->length(); i++) {
11616 // Names of variables introduced by eval are strings.
11617 ASSERT(keys->get(i)->IsString());
11618 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 RETURN_IF_EMPTY_HANDLE_VALUE(
11620 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011621 SetProperty(isolate,
11622 closure_scope,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011623 key,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011624 GetProperty(isolate, ext, key),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011625 NONE,
11626 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011627 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011628 }
11629 }
11630
11631 return closure_scope;
11632}
11633
11634
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011635// This method copies structure of MaterializeClosure method above.
11636static bool SetClosureVariableValue(Isolate* isolate,
11637 Handle<Context> context,
11638 Handle<String> variable_name,
11639 Handle<Object> new_value) {
11640 ASSERT(context->IsFunctionContext());
11641
11642 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11643 Handle<ScopeInfo> scope_info(shared->scope_info());
11644
11645 // Context locals to the context extension.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011646 if (SetContextLocalValue(
11647 isolate, scope_info, context, variable_name, new_value)) {
11648 return true;
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011649 }
11650
11651 // Properties from the function context extension. This will
11652 // be variables introduced by eval.
11653 if (context->has_extension()) {
11654 Handle<JSObject> ext(JSObject::cast(context->extension()));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011655 if (JSReceiver::HasProperty(ext, variable_name)) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011656 // We don't expect this to do anything except replacing property value.
11657 SetProperty(isolate,
11658 ext,
11659 variable_name,
11660 new_value,
11661 NONE,
11662 kNonStrictMode);
11663 return true;
11664 }
11665 }
11666
11667 return false;
11668}
11669
11670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011671// Create a plain JSObject which materializes the scope for the specified
11672// catch context.
11673static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11674 Handle<Context> context) {
11675 ASSERT(context->IsCatchContext());
11676 Handle<String> name(String::cast(context->extension()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011677 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11678 isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011679 Handle<JSObject> catch_scope =
11680 isolate->factory()->NewJSObject(isolate->object_function());
11681 RETURN_IF_EMPTY_HANDLE_VALUE(
11682 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011683 SetProperty(isolate,
11684 catch_scope,
11685 name,
11686 thrown_object,
11687 NONE,
11688 kNonStrictMode),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011689 Handle<JSObject>());
11690 return catch_scope;
11691}
11692
11693
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011694static bool SetCatchVariableValue(Isolate* isolate,
11695 Handle<Context> context,
11696 Handle<String> variable_name,
11697 Handle<Object> new_value) {
11698 ASSERT(context->IsCatchContext());
11699 Handle<String> name(String::cast(context->extension()));
11700 if (!name->Equals(*variable_name)) {
11701 return false;
11702 }
11703 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11704 return true;
11705}
11706
11707
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011708// Create a plain JSObject which materializes the block scope for the specified
11709// block context.
11710static Handle<JSObject> MaterializeBlockScope(
11711 Isolate* isolate,
11712 Handle<Context> context) {
11713 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011714 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011715
11716 // Allocate and initialize a JSObject with all the arguments, stack locals
11717 // heap locals and extension properties of the debugged function.
11718 Handle<JSObject> block_scope =
11719 isolate->factory()->NewJSObject(isolate->object_function());
11720
11721 // Fill all context locals.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011722 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11723 scope_info, context, block_scope)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011724 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011725 }
11726
11727 return block_scope;
11728}
11729
11730
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011731// Create a plain JSObject which materializes the module scope for the specified
11732// module context.
11733static Handle<JSObject> MaterializeModuleScope(
11734 Isolate* isolate,
11735 Handle<Context> context) {
11736 ASSERT(context->IsModuleContext());
11737 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11738
11739 // Allocate and initialize a JSObject with all the members of the debugged
11740 // module.
11741 Handle<JSObject> module_scope =
11742 isolate->factory()->NewJSObject(isolate->object_function());
11743
11744 // Fill all context locals.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011745 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11746 scope_info, context, module_scope)) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011747 return Handle<JSObject>();
11748 }
11749
11750 return module_scope;
11751}
11752
11753
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011754// Iterate over the actual scopes visible from a stack frame or from a closure.
11755// The iteration proceeds from the innermost visible nested scope outwards.
11756// All scopes are backed by an actual context except the local scope,
11757// which is inserted "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011758class ScopeIterator {
11759 public:
11760 enum ScopeType {
11761 ScopeTypeGlobal = 0,
11762 ScopeTypeLocal,
11763 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011764 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011765 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011766 ScopeTypeBlock,
11767 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011768 };
11769
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011770 ScopeIterator(Isolate* isolate,
11771 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011772 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 : isolate_(isolate),
11774 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011775 inlined_jsframe_index_(inlined_jsframe_index),
danno@chromium.org169691d2013-07-15 08:01:13 +000011776 function_(frame->function()),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011777 context_(Context::cast(frame->context())),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011778 nested_scope_chain_(4),
11779 failed_(false) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011780
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011781 // Catch the case when the debugger stops in an internal function.
11782 Handle<SharedFunctionInfo> shared_info(function_->shared());
11783 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11784 if (shared_info->script() == isolate->heap()->undefined_value()) {
11785 while (context_->closure() == *function_) {
11786 context_ = Handle<Context>(context_->previous(), isolate_);
11787 }
11788 return;
11789 }
11790
11791 // Get the debug info (create it if it does not exist).
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011792 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011793 // Return if ensuring debug info failed.
11794 return;
11795 }
11796 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11797
11798 // Find the break point where execution has stopped.
11799 BreakLocationIterator break_location_iterator(debug_info,
11800 ALL_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +000011801 // pc points to the instruction after the current one, possibly a break
11802 // location as well. So the "- 1" to exclude it from the search.
11803 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011804 if (break_location_iterator.IsExit()) {
11805 // We are within the return sequence. At the momemt it is not possible to
11806 // get a source position which is consistent with the current scope chain.
11807 // Thus all nested with, catch and block contexts are skipped and we only
11808 // provide the function scope.
11809 if (scope_info->HasContext()) {
11810 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11811 } else {
11812 while (context_->closure() == *function_) {
11813 context_ = Handle<Context>(context_->previous(), isolate_);
11814 }
11815 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011816 if (scope_info->scope_type() != EVAL_SCOPE) {
11817 nested_scope_chain_.Add(scope_info);
11818 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011819 } else {
11820 // Reparse the code and analyze the scopes.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011821 Handle<Script> script(Script::cast(shared_info->script()));
11822 Scope* scope = NULL;
11823
11824 // Check whether we are in global, eval or function code.
11825 Handle<ScopeInfo> scope_info(shared_info->scope_info());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011826 if (scope_info->scope_type() != FUNCTION_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011827 // Global or eval code.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011828 CompilationInfoWithZone info(script);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011829 if (scope_info->scope_type() == GLOBAL_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011830 info.MarkAsGlobal();
11831 } else {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011832 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011833 info.MarkAsEval();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011834 info.SetContext(Handle<Context>(function_->context()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011835 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011836 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011837 scope = info.function()->scope();
11838 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011839 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011840 } else {
11841 // Function code
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011842 CompilationInfoWithZone info(shared_info);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011843 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011844 scope = info.function()->scope();
11845 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011846 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011847 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011848 }
11849 }
11850
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011851 ScopeIterator(Isolate* isolate,
11852 Handle<JSFunction> function)
11853 : isolate_(isolate),
11854 frame_(NULL),
11855 inlined_jsframe_index_(0),
11856 function_(function),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011857 context_(function->context()),
11858 failed_(false) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011859 if (function->IsBuiltin()) {
11860 context_ = Handle<Context>();
11861 }
11862 }
11863
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011864 // More scopes?
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011865 bool Done() {
11866 ASSERT(!failed_);
11867 return context_.is_null();
11868 }
11869
11870 bool Failed() { return failed_; }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011871
11872 // Move to the next scope.
11873 void Next() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011874 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011875 ScopeType scope_type = Type();
11876 if (scope_type == ScopeTypeGlobal) {
11877 // The global scope is always the last in the chain.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011878 ASSERT(context_->IsNativeContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011879 context_ = Handle<Context>();
11880 return;
11881 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011882 if (nested_scope_chain_.is_empty()) {
11883 context_ = Handle<Context>(context_->previous(), isolate_);
11884 } else {
11885 if (nested_scope_chain_.last()->HasContext()) {
11886 ASSERT(context_->previous() != NULL);
11887 context_ = Handle<Context>(context_->previous(), isolate_);
11888 }
11889 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011890 }
11891 }
11892
11893 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011894 ScopeType Type() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011895 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011896 if (!nested_scope_chain_.is_empty()) {
11897 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011898 switch (scope_info->scope_type()) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011899 case FUNCTION_SCOPE:
11900 ASSERT(context_->IsFunctionContext() ||
11901 !scope_info->HasContext());
11902 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011903 case MODULE_SCOPE:
11904 ASSERT(context_->IsModuleContext());
11905 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011906 case GLOBAL_SCOPE:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011907 ASSERT(context_->IsNativeContext());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011908 return ScopeTypeGlobal;
11909 case WITH_SCOPE:
11910 ASSERT(context_->IsWithContext());
11911 return ScopeTypeWith;
11912 case CATCH_SCOPE:
11913 ASSERT(context_->IsCatchContext());
11914 return ScopeTypeCatch;
11915 case BLOCK_SCOPE:
11916 ASSERT(!scope_info->HasContext() ||
11917 context_->IsBlockContext());
11918 return ScopeTypeBlock;
11919 case EVAL_SCOPE:
11920 UNREACHABLE();
11921 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011922 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011923 if (context_->IsNativeContext()) {
11924 ASSERT(context_->global_object()->IsGlobalObject());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011925 return ScopeTypeGlobal;
11926 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011927 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011928 return ScopeTypeClosure;
11929 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011930 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011931 return ScopeTypeCatch;
11932 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011933 if (context_->IsBlockContext()) {
11934 return ScopeTypeBlock;
11935 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011936 if (context_->IsModuleContext()) {
11937 return ScopeTypeModule;
11938 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011939 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011940 return ScopeTypeWith;
11941 }
11942
11943 // Return the JavaScript object with the content of the current scope.
11944 Handle<JSObject> ScopeObject() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011945 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011946 switch (Type()) {
11947 case ScopeIterator::ScopeTypeGlobal:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011948 return Handle<JSObject>(CurrentContext()->global_object());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011949 case ScopeIterator::ScopeTypeLocal:
11950 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011951 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011952 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011953 case ScopeIterator::ScopeTypeWith:
11954 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011955 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11956 case ScopeIterator::ScopeTypeCatch:
11957 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011958 case ScopeIterator::ScopeTypeClosure:
11959 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011961 case ScopeIterator::ScopeTypeBlock:
11962 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011963 case ScopeIterator::ScopeTypeModule:
11964 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011965 }
11966 UNREACHABLE();
11967 return Handle<JSObject>();
11968 }
11969
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011970 bool SetVariableValue(Handle<String> variable_name,
11971 Handle<Object> new_value) {
11972 ASSERT(!failed_);
11973 switch (Type()) {
11974 case ScopeIterator::ScopeTypeGlobal:
11975 break;
11976 case ScopeIterator::ScopeTypeLocal:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011977 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
11978 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011979 case ScopeIterator::ScopeTypeWith:
11980 break;
11981 case ScopeIterator::ScopeTypeCatch:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011982 return SetCatchVariableValue(isolate_, CurrentContext(),
11983 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011984 case ScopeIterator::ScopeTypeClosure:
11985 return SetClosureVariableValue(isolate_, CurrentContext(),
11986 variable_name, new_value);
11987 case ScopeIterator::ScopeTypeBlock:
11988 // TODO(2399): should we implement it?
11989 break;
11990 case ScopeIterator::ScopeTypeModule:
11991 // TODO(2399): should we implement it?
11992 break;
11993 }
11994 return false;
11995 }
11996
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011997 Handle<ScopeInfo> CurrentScopeInfo() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011998 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011999 if (!nested_scope_chain_.is_empty()) {
12000 return nested_scope_chain_.last();
12001 } else if (context_->IsBlockContext()) {
12002 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
12003 } else if (context_->IsFunctionContext()) {
12004 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
12005 }
12006 return Handle<ScopeInfo>::null();
12007 }
12008
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012009 // Return the context for this scope. For the local context there might not
12010 // be an actual context.
12011 Handle<Context> CurrentContext() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012012 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012013 if (Type() == ScopeTypeGlobal ||
12014 nested_scope_chain_.is_empty()) {
12015 return context_;
12016 } else if (nested_scope_chain_.last()->HasContext()) {
12017 return context_;
12018 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012019 return Handle<Context>();
12020 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012021 }
12022
12023#ifdef DEBUG
12024 // Debug print of the content of the current scope.
12025 void DebugPrint() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012026 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012027 switch (Type()) {
12028 case ScopeIterator::ScopeTypeGlobal:
12029 PrintF("Global:\n");
12030 CurrentContext()->Print();
12031 break;
12032
12033 case ScopeIterator::ScopeTypeLocal: {
12034 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012035 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012036 if (!CurrentContext().is_null()) {
12037 CurrentContext()->Print();
12038 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012039 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012040 if (extension->IsJSContextExtensionObject()) {
12041 extension->Print();
12042 }
12043 }
12044 }
12045 break;
12046 }
12047
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012048 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012049 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012050 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012051 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012052
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012053 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000012054 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012055 CurrentContext()->extension()->Print();
12056 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012057 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012059 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012060 PrintF("Closure:\n");
12061 CurrentContext()->Print();
12062 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012063 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012064 if (extension->IsJSContextExtensionObject()) {
12065 extension->Print();
12066 }
12067 }
12068 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012069
12070 default:
12071 UNREACHABLE();
12072 }
12073 PrintF("\n");
12074 }
12075#endif
12076
12077 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012078 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012079 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012080 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012081 Handle<JSFunction> function_;
12082 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012083 List<Handle<ScopeInfo> > nested_scope_chain_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012084 bool failed_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012085
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012086 void RetrieveScopeChain(Scope* scope,
12087 Handle<SharedFunctionInfo> shared_info) {
12088 if (scope != NULL) {
12089 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12090 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12091 } else {
12092 // A failed reparse indicates that the preparser has diverged from the
12093 // parser or that the preparse data given to the initial parse has been
12094 // faulty. We fail in debug mode but in release mode we only provide the
12095 // information we get from the context chain but nothing about
12096 // completely stack allocated scopes or stack allocated locals.
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012097 // Or it could be due to stack overflow.
12098 ASSERT(isolate_->has_pending_exception());
12099 failed_ = true;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012100 }
12101 }
12102
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012103 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12104};
12105
12106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012107RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012109 ASSERT(args.length() == 2);
12110
12111 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012112 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012113 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12114 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012115 if (!maybe_check->ToObject(&check)) return maybe_check;
12116 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012117 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012118
12119 // Get the frame where the debugging is performed.
12120 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012121 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012122 JavaScriptFrame* frame = it.frame();
12123
12124 // Count the visible scopes.
12125 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012126 for (ScopeIterator it(isolate, frame, 0);
12127 !it.Done();
12128 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012129 n++;
12130 }
12131
12132 return Smi::FromInt(n);
12133}
12134
12135
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012136// Returns the list of step-in positions (text offset) in a function of the
12137// stack frame in a range from the current debug break position to the end
12138// of the corresponding statement.
12139RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) {
12140 HandleScope scope(isolate);
12141 ASSERT(args.length() == 2);
12142
12143 // Check arguments.
12144 Object* check;
12145 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12146 RUNTIME_ARGUMENTS(isolate, args));
12147 if (!maybe_check->ToObject(&check)) return maybe_check;
12148 }
12149 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12150
12151 // Get the frame where the debugging is performed.
12152 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12153 JavaScriptFrameIterator frame_it(isolate, id);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012154 RUNTIME_ASSERT(!frame_it.done());
12155
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012156 JavaScriptFrame* frame = frame_it.frame();
12157
danno@chromium.org59400602013-08-13 17:09:37 +000012158 Handle<JSFunction> fun =
12159 Handle<JSFunction>(frame->function());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012160 Handle<SharedFunctionInfo> shared =
danno@chromium.org59400602013-08-13 17:09:37 +000012161 Handle<SharedFunctionInfo>(fun->shared());
12162
12163 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12164 return isolate->heap()->undefined_value();
12165 }
12166
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012167 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12168
12169 int len = 0;
12170 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12171 // Find the break point where execution has stopped.
12172 BreakLocationIterator break_location_iterator(debug_info,
12173 ALL_BREAK_LOCATIONS);
12174
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012175 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012176 int current_statement_pos = break_location_iterator.statement_position();
12177
12178 while (!break_location_iterator.Done()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012179 bool accept;
danno@chromium.org59400602013-08-13 17:09:37 +000012180 if (break_location_iterator.pc() > frame->pc()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012181 accept = true;
12182 } else {
12183 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12184 // The break point is near our pc. Could be a step-in possibility,
12185 // that is currently taken by active debugger call.
12186 if (break_frame_id == StackFrame::NO_ID) {
12187 // We are not stepping.
12188 accept = false;
12189 } else {
12190 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12191 // If our frame is a top frame and we are stepping, we can do step-in
12192 // at this place.
12193 accept = additional_frame_it.frame()->id() == id;
12194 }
12195 }
12196 if (accept) {
danno@chromium.org59400602013-08-13 17:09:37 +000012197 if (break_location_iterator.IsStepInLocation(isolate)) {
12198 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12199 JSObject::SetElement(array, len,
12200 Handle<Object>(position_value, isolate),
12201 NONE, kNonStrictMode);
12202 len++;
12203 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012204 }
12205 // Advance iterator.
12206 break_location_iterator.Next();
12207 if (current_statement_pos !=
12208 break_location_iterator.statement_position()) {
12209 break;
12210 }
12211 }
12212 return *array;
12213}
12214
12215
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012216static const int kScopeDetailsTypeIndex = 0;
12217static const int kScopeDetailsObjectIndex = 1;
12218static const int kScopeDetailsSize = 2;
12219
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012220
12221static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
12222 ScopeIterator* it) {
12223 // Calculate the size of the result.
12224 int details_size = kScopeDetailsSize;
12225 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12226
12227 // Fill in scope details.
12228 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12229 Handle<JSObject> scope_object = it->ScopeObject();
12230 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
12231 details->set(kScopeDetailsObjectIndex, *scope_object);
12232
12233 return *isolate->factory()->NewJSArrayWithElements(details);
12234}
12235
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000012236
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012237// Return an array with scope details
12238// args[0]: number: break id
12239// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012240// args[2]: number: inlined frame index
12241// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012242//
12243// The array returned contains the following information:
12244// 0: Scope type
12245// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012246RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012247 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012248 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012249
12250 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012251 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012252 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12253 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012254 if (!maybe_check->ToObject(&check)) return maybe_check;
12255 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012256 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012257 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012258 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012259
12260 // Get the frame where the debugging is performed.
12261 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012262 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012263 JavaScriptFrame* frame = frame_it.frame();
12264
12265 // Find the requested scope.
12266 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012267 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012268 for (; !it.Done() && n < index; it.Next()) {
12269 n++;
12270 }
12271 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012273 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012274 return MaterializeScopeDetails(isolate, &it);
12275}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012276
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012277
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012278RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
12279 HandleScope scope(isolate);
12280 ASSERT(args.length() == 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012281
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012282 // Check arguments.
12283 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12284
12285 // Count the visible scopes.
12286 int n = 0;
12287 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12288 n++;
12289 }
12290
12291 return Smi::FromInt(n);
12292}
12293
12294
12295RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
12296 HandleScope scope(isolate);
12297 ASSERT(args.length() == 2);
12298
12299 // Check arguments.
12300 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12301 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12302
12303 // Find the requested scope.
12304 int n = 0;
12305 ScopeIterator it(isolate, fun);
12306 for (; !it.Done() && n < index; it.Next()) {
12307 n++;
12308 }
12309 if (it.Done()) {
12310 return isolate->heap()->undefined_value();
12311 }
12312
12313 return MaterializeScopeDetails(isolate, &it);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012314}
12315
12316
mmassi@chromium.org49a44672012-12-04 13:52:03 +000012317static bool SetScopeVariableValue(ScopeIterator* it, int index,
12318 Handle<String> variable_name,
12319 Handle<Object> new_value) {
12320 for (int n = 0; !it->Done() && n < index; it->Next()) {
12321 n++;
12322 }
12323 if (it->Done()) {
12324 return false;
12325 }
12326 return it->SetVariableValue(variable_name, new_value);
12327}
12328
12329
12330// Change variable value in closure or local scope
12331// args[0]: number or JsFunction: break id or function
12332// args[1]: number: frame index (when arg[0] is break id)
12333// args[2]: number: inlined frame index (when arg[0] is break id)
12334// args[3]: number: scope index
12335// args[4]: string: variable name
12336// args[5]: object: new value
12337//
12338// Return true if success and false otherwise
12339RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
12340 HandleScope scope(isolate);
12341 ASSERT(args.length() == 6);
12342
12343 // Check arguments.
12344 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12345 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12346 Handle<Object> new_value = args.at<Object>(5);
12347
12348 bool res;
12349 if (args[0]->IsNumber()) {
12350 Object* check;
12351 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12352 RUNTIME_ARGUMENTS(isolate, args));
12353 if (!maybe_check->ToObject(&check)) return maybe_check;
12354 }
12355 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12356 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12357
12358 // Get the frame where the debugging is performed.
12359 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12360 JavaScriptFrameIterator frame_it(isolate, id);
12361 JavaScriptFrame* frame = frame_it.frame();
12362
12363 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12364 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12365 } else {
12366 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12367 ScopeIterator it(isolate, fun);
12368 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12369 }
12370
12371 return isolate->heap()->ToBoolean(res);
12372}
12373
12374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012375RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012376 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012377 ASSERT(args.length() == 0);
12378
12379#ifdef DEBUG
12380 // Print the scopes for the top frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000012381 StackFrameLocator locator(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012382 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012383 for (ScopeIterator it(isolate, frame, 0);
12384 !it.Done();
12385 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012386 it.DebugPrint();
12387 }
12388#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012389 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012390}
12391
12392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012393RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012394 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012395 ASSERT(args.length() == 1);
12396
12397 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012398 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012399 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12400 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012401 if (!maybe_result->ToObject(&result)) return maybe_result;
12402 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012403
12404 // Count all archived V8 threads.
12405 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012406 for (ThreadState* thread =
12407 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012408 thread != NULL;
12409 thread = thread->Next()) {
12410 n++;
12411 }
12412
12413 // Total number of threads is current thread and archived threads.
12414 return Smi::FromInt(n + 1);
12415}
12416
12417
12418static const int kThreadDetailsCurrentThreadIndex = 0;
12419static const int kThreadDetailsThreadIdIndex = 1;
12420static const int kThreadDetailsSize = 2;
12421
12422// Return an array with thread details
12423// args[0]: number: break id
12424// args[1]: number: thread index
12425//
12426// The array returned contains the following information:
12427// 0: Is current thread?
12428// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012429RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012430 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012431 ASSERT(args.length() == 2);
12432
12433 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012434 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012435 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12436 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012437 if (!maybe_check->ToObject(&check)) return maybe_check;
12438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012439 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12440
12441 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012442 Handle<FixedArray> details =
12443 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012444
12445 // Thread index 0 is current thread.
12446 if (index == 0) {
12447 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012448 details->set(kThreadDetailsCurrentThreadIndex,
12449 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012450 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012451 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012452 } else {
12453 // Find the thread with the requested index.
12454 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012455 ThreadState* thread =
12456 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012457 while (index != n && thread != NULL) {
12458 thread = thread->Next();
12459 n++;
12460 }
12461 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012462 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012463 }
12464
12465 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 details->set(kThreadDetailsCurrentThreadIndex,
12467 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012468 details->set(kThreadDetailsThreadIdIndex,
12469 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012470 }
12471
12472 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012473 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012474}
12475
12476
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012477// Sets the disable break state
12478// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012479RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012481 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012482 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012483 isolate->debug()->set_disable_break(disable_break);
12484 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012485}
12486
12487
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012488static bool IsPositionAlignmentCodeCorrect(int alignment) {
12489 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12490}
12491
12492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012493RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012494 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012495 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012496
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012497 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012498 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12499
12500 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12501 return isolate->ThrowIllegalOperation();
12502 }
12503 BreakPositionAlignment alignment =
12504 static_cast<BreakPositionAlignment>(statement_aligned_code);
12505
ager@chromium.org5aa501c2009-06-23 07:57:28 +000012506 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507 // Find the number of break points
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012508 Handle<Object> break_locations =
12509 Debug::GetSourceBreakLocations(shared, alignment);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012510 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012511 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012513 Handle<FixedArray>::cast(break_locations));
12514}
12515
12516
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012517// Set a break point in a function.
12518// args[0]: function
12519// args[1]: number: break source position (within the function source)
12520// args[2]: number: break point object
12521RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
12522 HandleScope scope(isolate);
12523 ASSERT(args.length() == 3);
12524 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12525 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12526 RUNTIME_ASSERT(source_position >= 0);
12527 Handle<Object> break_point_object_arg = args.at<Object>(2);
12528
12529 // Set break point.
12530 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12531 &source_position);
12532
12533 return Smi::FromInt(source_position);
12534}
12535
12536
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012537// Changes the state of a break point in a script and returns source position
12538// where break point was set. NOTE: Regarding performance see the NOTE for
12539// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012540// args[0]: script to set break point in
12541// args[1]: number: break source position (within the script source)
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012542// args[2]: number, breakpoint position alignment
12543// args[3]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012544RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012545 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012546 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012547 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12549 RUNTIME_ASSERT(source_position >= 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012550 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12551 Handle<Object> break_point_object_arg = args.at<Object>(3);
12552
12553 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12554 return isolate->ThrowIllegalOperation();
12555 }
12556 BreakPositionAlignment alignment =
12557 static_cast<BreakPositionAlignment>(statement_aligned_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012558
12559 // Get the script from the script wrapper.
12560 RUNTIME_ASSERT(wrapper->value()->IsScript());
12561 Handle<Script> script(Script::cast(wrapper->value()));
12562
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012563 // Set break point.
12564 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012565 &source_position,
12566 alignment)) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012567 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012568 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012569
12570 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012571}
12572
12573
12574// Clear a break point
12575// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012576RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012577 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012578 ASSERT(args.length() == 1);
12579 Handle<Object> break_point_object_arg = args.at<Object>(0);
12580
12581 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012582 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012584 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012585}
12586
12587
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012588// Change the state of break on exceptions.
12589// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12590// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012592 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012593 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012594 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012595 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012596
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012597 // If the number doesn't match an enum value, the ChangeBreakOnException
12598 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012599 ExceptionBreakType type =
12600 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012601 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012602 isolate->debug()->ChangeBreakOnException(type, enable);
12603 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012604}
12605
12606
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012607// Returns the state of break on exceptions
12608// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012609RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012611 ASSERT(args.length() == 1);
12612 RUNTIME_ASSERT(args[0]->IsNumber());
12613
12614 ExceptionBreakType type =
12615 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012616 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012617 return Smi::FromInt(result);
12618}
12619
12620
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012621// Prepare for stepping
12622// args[0]: break id for checking execution state
12623// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000012624// args[2]: number of times to perform the step, for step out it is the number
12625// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012626RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012627 HandleScope scope(isolate);
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012628 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012629 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012630 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012631 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12632 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012633 if (!maybe_check->ToObject(&check)) return maybe_check;
12634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012635 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012636 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012637 }
12638
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012639 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12640
12641 StackFrame::Id frame_id;
12642 if (wrapped_frame_id == 0) {
12643 frame_id = StackFrame::NO_ID;
12644 } else {
12645 frame_id = UnwrapFrameId(wrapped_frame_id);
12646 }
12647
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012648 // Get the step action and check validity.
12649 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12650 if (step_action != StepIn &&
12651 step_action != StepNext &&
12652 step_action != StepOut &&
12653 step_action != StepInMin &&
12654 step_action != StepMin) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012655 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012656 }
12657
mvstanton@chromium.org63ea3d22013-10-10 09:24:12 +000012658 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12659 step_action != StepMin && step_action != StepOut) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012660 return isolate->ThrowIllegalOperation();
12661 }
12662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012663 // Get the number of steps.
12664 int step_count = NumberToInt32(args[2]);
12665 if (step_count < 1) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012666 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012667 }
12668
ager@chromium.orga1645e22009-09-09 19:27:10 +000012669 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012670 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012672 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012673 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012674 step_count,
12675 frame_id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012677}
12678
12679
12680// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012681RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012682 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012683 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 isolate->debug()->ClearStepping();
12685 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012686}
12687
12688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012689// Helper function to find or create the arguments object for
12690// Runtime_DebugEvaluate.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012691static Handle<JSObject> MaterializeArgumentsObject(
12692 Isolate* isolate,
12693 Handle<JSObject> target,
12694 Handle<JSFunction> function) {
12695 // Do not materialize the arguments object for eval or top-level code.
12696 // Skip if "arguments" is already taken.
12697 if (!function->shared()->is_function() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012698 JSReceiver::HasLocalProperty(target,
12699 isolate->factory()->arguments_string())) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012700 return target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012701 }
12702
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012703 // FunctionGetArguments can't throw an exception.
12704 Handle<JSObject> arguments = Handle<JSObject>::cast(
12705 Accessors::FunctionGetArguments(function));
12706 SetProperty(isolate,
12707 target,
12708 isolate->factory()->arguments_string(),
12709 arguments,
12710 ::NONE,
12711 kNonStrictMode);
12712 return target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012713}
12714
12715
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012716// Compile and evaluate source for the given context.
12717static MaybeObject* DebugEvaluate(Isolate* isolate,
12718 Handle<Context> context,
12719 Handle<Object> context_extension,
12720 Handle<Object> receiver,
12721 Handle<String> source) {
12722 if (context_extension->IsJSObject()) {
12723 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
12724 Handle<JSFunction> closure(context->closure(), isolate);
12725 context = isolate->factory()->NewWithContext(closure, context, extension);
12726 }
12727
12728 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
12729 source,
12730 context,
12731 context->IsNativeContext(),
12732 CLASSIC_MODE,
12733 NO_PARSE_RESTRICTION,
12734 RelocInfo::kNoPosition);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000012735 RETURN_IF_EMPTY_HANDLE(isolate, shared);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012736
12737 Handle<JSFunction> eval_fun =
12738 isolate->factory()->NewFunctionFromSharedFunctionInfo(
12739 shared, context, NOT_TENURED);
12740 bool pending_exception;
12741 Handle<Object> result = Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000012742 isolate, eval_fun, receiver, 0, NULL, &pending_exception);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012743
12744 if (pending_exception) return Failure::Exception();
12745
12746 // Skip the global proxy as it has no properties and always delegates to the
12747 // real global object.
12748 if (result->IsJSGlobalProxy()) {
12749 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
12750 }
12751
12752 // Clear the oneshot breakpoints so that the debugger does not step further.
12753 isolate->debug()->ClearStepping();
12754 return *result;
12755}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756
12757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012758// Evaluate a piece of JavaScript in the context of a stack frame for
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012759// debugging. Things that need special attention are:
12760// - Parameters and stack-allocated locals need to be materialized. Altered
12761// values need to be written back to the stack afterwards.
12762// - The arguments object needs to materialized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012763RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012765
12766 // Check the execution state and decode arguments frame and source to be
12767 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012768 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012769 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012770 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012772 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012773 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012774 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012775 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012776 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12777 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012778 Handle<Object> context_extension(args[5], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012779
12780 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012781 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012782
12783 // Get the frame where the debugging is performed.
12784 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012785 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012786 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012787 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12788 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012789
12790 // Traverse the saved contexts chain to find the active context for the
12791 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012792 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012794 SaveContext savex(isolate);
12795 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012796
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012797 // Evaluate on the context of the frame.
12798 Handle<Context> context(Context::cast(frame->context()));
12799 ASSERT(!context.is_null());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012800
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012801 // Materialize stack locals and the arguments object.
12802 Handle<JSObject> materialized =
12803 isolate->factory()->NewJSObject(isolate->object_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012804
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012805 materialized = MaterializeStackLocalsWithFrameInspector(
12806 isolate, materialized, function, &frame_inspector);
12807 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012808
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012809 materialized = MaterializeArgumentsObject(isolate, materialized, function);
12810 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012811
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012812 // Add the materialized object in a with-scope to shadow the stack locals.
12813 context = isolate->factory()->NewWithContext(function, context, materialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012814
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 Handle<Object> receiver(frame->receiver(), isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012816 Object* evaluate_result_object;
12817 { MaybeObject* maybe_result =
12818 DebugEvaluate(isolate, context, context_extension, receiver, source);
12819 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
12820 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012821
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012822 Handle<Object> result(evaluate_result_object, isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012823
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012824 // Write back potential changes to materialized stack locals to the stack.
12825 UpdateStackLocalsFromMaterializedObject(
12826 isolate, materialized, function, frame, inlined_jsframe_index);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012827
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012828 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012829}
12830
12831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012832RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012833 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012834
12835 // Check the execution state and decode arguments frame and source to be
12836 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012837 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012838 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012839 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012840 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012841 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012842 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012843 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12844 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012845 Handle<Object> context_extension(args[3], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012846
12847 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012848 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012849
12850 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012851 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012852 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012853 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012854 top = top->prev();
12855 }
12856 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012857 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012858 }
12859
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012860 // Get the native context now set to the top context from before the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012861 // debugger was invoked.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012862 Handle<Context> context = isolate->native_context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012863 Handle<Object> receiver = isolate->global_object();
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012864 return DebugEvaluate(isolate, context, context_extension, receiver, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012865}
12866
12867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012868RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012870 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012872 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012874
12875 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012876 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012877 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12878 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12879 // because using
12880 // instances->set(i, *GetScriptWrapper(script))
12881 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012882 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012883 Handle<JSValue> wrapper = GetScriptWrapper(script);
12884 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012885 }
12886
12887 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012888 Handle<JSObject> result =
12889 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012890 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012891 return *result;
12892}
12893
12894
12895// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012896static int DebugReferencedBy(HeapIterator* iterator,
12897 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012898 Object* instance_filter, int max_references,
12899 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012900 JSFunction* arguments_function) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012901 Isolate* isolate = target->GetIsolate();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012902 SealHandleScope shs(isolate);
12903 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012904
12905 // Iterate the heap.
12906 int count = 0;
12907 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012908 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012909 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012910 (max_references == 0 || count < max_references)) {
12911 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012912 if (heap_obj->IsJSObject()) {
12913 // Skip context extension objects and argument arrays as these are
12914 // checked in the context of functions using them.
12915 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012916 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012917 obj->map()->constructor() == arguments_function) {
12918 continue;
12919 }
12920
12921 // Check if the JS object has a reference to the object looked for.
12922 if (obj->ReferencesObject(target)) {
12923 // Check instance filter if supplied. This is normally used to avoid
12924 // references from mirror objects (see Runtime_IsInPrototypeChain).
12925 if (!instance_filter->IsUndefined()) {
12926 Object* V = obj;
12927 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012928 Object* prototype = V->GetPrototype(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012929 if (prototype->IsNull()) {
12930 break;
12931 }
12932 if (instance_filter == prototype) {
12933 obj = NULL; // Don't add this object.
12934 break;
12935 }
12936 V = prototype;
12937 }
12938 }
12939
12940 if (obj != NULL) {
12941 // Valid reference found add to instance array if supplied an update
12942 // count.
12943 if (instances != NULL && count < instances_size) {
12944 instances->set(count, obj);
12945 }
12946 last = obj;
12947 count++;
12948 }
12949 }
12950 }
12951 }
12952
12953 // Check for circular reference only. This can happen when the object is only
12954 // referenced from mirrors and has a circular reference in which case the
12955 // object is not really alive and would have been garbage collected if not
12956 // referenced from the mirror.
12957 if (count == 1 && last == target) {
12958 count = 0;
12959 }
12960
12961 // Return the number of referencing objects found.
12962 return count;
12963}
12964
12965
12966// Scan the heap for objects with direct references to an object
12967// args[0]: the object to find references to
12968// args[1]: constructor function for instances to exclude (Mirror)
12969// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012970RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012971 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012972 ASSERT(args.length() == 3);
12973
12974 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012975 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12976 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012977 // The heap iterator reserves the right to do a GC to make the heap iterable.
12978 // Due to the GC above we know it won't need to do that, but it seems cleaner
12979 // to get the heap iterator constructed before we start having unprotected
12980 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012981
12982 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012983 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012984 Object* instance_filter = args[1];
12985 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12986 instance_filter->IsJSObject());
12987 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12988 RUNTIME_ASSERT(max_references >= 0);
12989
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012991 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012992 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012993 isolate->context()->native_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012994 JSFunction* arguments_function =
12995 JSFunction::cast(arguments_boilerplate->map()->constructor());
12996
12997 // Get the number of referencing objects.
12998 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012999 Heap* heap = isolate->heap();
13000 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013001 count = DebugReferencedBy(&heap_iterator,
13002 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000013003 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013004
13005 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013006 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013007 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013008 if (!maybe_object->ToObject(&object)) return maybe_object;
13009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013010 FixedArray* instances = FixedArray::cast(object);
13011
13012 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013013 // AllocateFixedArray above does not make the heap non-iterable.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013014 ASSERT(heap->IsHeapIterable());
13015 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013016 count = DebugReferencedBy(&heap_iterator2,
13017 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000013018 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013019
13020 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013021 Object* result;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013022 MaybeObject* maybe_result = heap->AllocateJSObject(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013023 isolate->context()->native_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013024 if (!maybe_result->ToObject(&result)) return maybe_result;
13025 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013026}
13027
13028
13029// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013030static int DebugConstructedBy(HeapIterator* iterator,
13031 JSFunction* constructor,
13032 int max_references,
13033 FixedArray* instances,
13034 int instances_size) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013035 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013036
13037 // Iterate the heap.
13038 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013039 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013040 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013041 (max_references == 0 || count < max_references)) {
13042 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013043 if (heap_obj->IsJSObject()) {
13044 JSObject* obj = JSObject::cast(heap_obj);
13045 if (obj->map()->constructor() == constructor) {
13046 // Valid reference found add to instance array if supplied an update
13047 // count.
13048 if (instances != NULL && count < instances_size) {
13049 instances->set(count, obj);
13050 }
13051 count++;
13052 }
13053 }
13054 }
13055
13056 // Return the number of referencing objects found.
13057 return count;
13058}
13059
13060
13061// Scan the heap for objects constructed by a specific function.
13062// args[0]: the constructor to find instances of
13063// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013064RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013065 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013066 ASSERT(args.length() == 2);
13067
13068 // First perform a full GC in order to avoid dead objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013069 Heap* heap = isolate->heap();
13070 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013071
13072 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013073 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013074 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13075 RUNTIME_ASSERT(max_references >= 0);
13076
13077 // Get the number of referencing objects.
13078 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013079 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013080 count = DebugConstructedBy(&heap_iterator,
13081 constructor,
13082 max_references,
13083 NULL,
13084 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013085
13086 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013087 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013088 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013089 if (!maybe_object->ToObject(&object)) return maybe_object;
13090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013091 FixedArray* instances = FixedArray::cast(object);
13092
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000013093 ASSERT(isolate->heap()->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013094 // Fill the referencing objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013095 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013096 count = DebugConstructedBy(&heap_iterator2,
13097 constructor,
13098 max_references,
13099 instances,
13100 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013101
13102 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013103 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013104 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013105 isolate->context()->native_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013106 if (!maybe_result->ToObject(&result)) return maybe_result;
13107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013108 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013109}
13110
13111
ager@chromium.orgddb913d2009-01-27 10:01:48 +000013112// Find the effective prototype object as returned by __proto__.
13113// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013114RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013115 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013116 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013117 CONVERT_ARG_CHECKED(JSObject, obj, 0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013118 return GetPrototypeSkipHiddenPrototypes(isolate, obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013119}
13120
13121
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013122// Patches script source (should be called upon BeforeCompile event).
13123RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
13124 HandleScope scope(isolate);
13125 ASSERT(args.length() == 2);
13126
13127 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013128 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013129
13130 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13131 Handle<Script> script(Script::cast(script_wrapper->value()));
13132
danno@chromium.orgd3c42102013-08-01 16:58:23 +000013133 int compilation_state = script->compilation_state();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013134 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13135 script->set_source(*source);
13136
13137 return isolate->heap()->undefined_value();
13138}
13139
13140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013141RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013142 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000013143 ASSERT(args.length() == 0);
rossberg@chromium.org92597162013-08-23 13:28:00 +000013144 OS::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013145 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013146}
13147
13148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013149RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013150 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013151#ifdef DEBUG
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013152 ASSERT(args.length() == 1);
13153 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013154 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013155 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013156 return Failure::Exception();
13157 }
13158 func->code()->PrintLn();
13159#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013160 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013161}
ager@chromium.org9085a012009-05-11 19:22:57 +000013162
13163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013165 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013166#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013167 ASSERT(args.length() == 1);
13168 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013169 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013170 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013171 return Failure::Exception();
13172 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +000013173 func->shared()->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013174#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013175 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013176}
13177
13178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013179RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013180 SealHandleScope shs(isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +000013181 ASSERT(args.length() == 1);
13182
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013183 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000013184 return f->shared()->inferred_name();
13185}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013188static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13189 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013190 FixedArray* buffer) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013191 DisallowHeapAllocation no_allocation;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013192 int counter = 0;
13193 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013194 for (HeapObject* obj = iterator->next();
13195 obj != NULL;
13196 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013197 ASSERT(obj != NULL);
13198 if (!obj->IsSharedFunctionInfo()) {
13199 continue;
13200 }
13201 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13202 if (shared->script() != script) {
13203 continue;
13204 }
13205 if (counter < buffer_size) {
13206 buffer->set(counter, shared);
13207 }
13208 counter++;
13209 }
13210 return counter;
13211}
13212
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013213
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013214// For a script finds all SharedFunctionInfo's in the heap that points
13215// to this script. Returns JSArray of SharedFunctionInfo wrapped
13216// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013217RUNTIME_FUNCTION(MaybeObject*,
13218 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013219 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013220 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013221 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013222 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013223
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013224 RUNTIME_ASSERT(script_value->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013225 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13226
13227 const int kBufferSize = 32;
13228
13229 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013230 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013231 int number;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013232 Heap* heap = isolate->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013233 {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013234 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013235 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013236 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013237 Script* scr = *script;
13238 FixedArray* arr = *array;
13239 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13240 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013241 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013242 array = isolate->factory()->NewFixedArray(number);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013243 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013244 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013245 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013246 Script* scr = *script;
13247 FixedArray* arr = *array;
13248 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013249 }
13250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013251 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013252 result->set_length(Smi::FromInt(number));
13253
13254 LiveEdit::WrapSharedFunctionInfos(result);
13255
13256 return *result;
13257}
13258
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013259
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013260// For a script calculates compilation information about all its functions.
13261// The script source is explicitly specified by the second argument.
13262// The source of the actual script is not used, however it is important that
13263// all generated code keeps references to this particular instance of script.
13264// Returns a JSArray of compilation infos. The array is ordered so that
13265// each function with all its descendant is always stored in a continues range
13266// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013267RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013268 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013269 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013270 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013271 CONVERT_ARG_CHECKED(JSValue, script, 0);
13272 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013273
13274 RUNTIME_ASSERT(script->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013275 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13276
13277 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
13278
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013279 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013280 return Failure::Exception();
13281 }
13282
13283 return result;
13284}
13285
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013286
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013287// Changes the source of the script to a new_source.
13288// If old_script_name is provided (i.e. is a String), also creates a copy of
13289// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013290RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013291 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013292 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013293 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013294 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13295 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013296 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013297
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013298 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13299 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013300
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013301 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
13302 new_source,
13303 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013304
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013305 if (old_script->IsScript()) {
13306 Handle<Script> script_handle(Script::cast(old_script));
13307 return *(GetScriptWrapper(script_handle));
13308 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013309 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013310 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013311}
13312
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013314RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013315 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013316 CHECK(isolate->debugger()->live_edit_enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013317 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013318 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013319 return LiveEdit::FunctionSourceUpdated(shared_info);
13320}
13321
13322
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013323// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013324RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013325 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013326 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013327 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013328 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13329 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013330
ager@chromium.orgac091b72010-05-05 07:34:42 +000013331 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013332}
13333
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013334
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013335// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013336RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013337 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013338 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013339 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013340 Handle<Object> function_object(args[0], isolate);
13341 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013342
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013343 if (function_object->IsJSValue()) {
13344 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13345 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013346 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13347 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013348 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013349 }
13350
13351 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13352 } else {
13353 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13354 // and we check it in this function.
13355 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013357 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013358}
13359
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013360
13361// In a code of a parent function replaces original function as embedded object
13362// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013363RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013364 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013365 CHECK(isolate->debugger()->live_edit_enabled());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013366 ASSERT(args.length() == 3);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013367
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013368 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13369 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13370 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013371
13372 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
13373 subst_wrapper);
13374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013375 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013376}
13377
13378
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013379// Updates positions of a shared function info (first parameter) according
13380// to script source change. Text change is described in second parameter as
13381// array of groups of 3 numbers:
13382// (change_begin, change_end, change_end_new_position).
13383// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013384RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013385 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013386 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013387 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013388 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13389 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013390
ager@chromium.orgac091b72010-05-05 07:34:42 +000013391 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013392}
13393
13394
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013395// For array of SharedFunctionInfo's (each wrapped in JSValue)
13396// checks that none of them have activations on stacks (of any thread).
13397// Returns array of the same length with corresponding results of
13398// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013399RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013400 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013401 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.org357bf652010-04-12 11:30:10 +000013402 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013403 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13404 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013405
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013406 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013407}
13408
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013409
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013410// Compares 2 strings line-by-line, then token-wise and returns diff in form
13411// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13412// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013413RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013414 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013415 CHECK(isolate->debugger()->live_edit_enabled());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013416 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013417 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13418 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013419
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013420 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013421}
13422
13423
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013424// Restarts a call frame and completely drops all frames above.
13425// Returns true if successful. Otherwise returns undefined or an error message.
13426RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
13427 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013428 CHECK(isolate->debugger()->live_edit_enabled());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013429 ASSERT(args.length() == 2);
13430
13431 // Check arguments.
13432 Object* check;
13433 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
13434 RUNTIME_ARGUMENTS(isolate, args));
13435 if (!maybe_check->ToObject(&check)) return maybe_check;
13436 }
13437 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13438 Heap* heap = isolate->heap();
13439
13440 // Find the relevant frame with the requested index.
13441 StackFrame::Id id = isolate->debug()->break_frame_id();
13442 if (id == StackFrame::NO_ID) {
13443 // If there are no JavaScript stack frames return undefined.
13444 return heap->undefined_value();
13445 }
13446
13447 int count = 0;
13448 JavaScriptFrameIterator it(isolate, id);
13449 for (; !it.done(); it.Advance()) {
13450 if (index < count + it.frame()->GetInlineCount()) break;
13451 count += it.frame()->GetInlineCount();
13452 }
13453 if (it.done()) return heap->undefined_value();
13454
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013455 const char* error_message = LiveEdit::RestartFrame(it.frame());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013456 if (error_message) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013457 return *(isolate->factory()->InternalizeUtf8String(error_message));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013458 }
13459 return heap->true_value();
13460}
13461
13462
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013463// A testing entry. Returns statement position which is the closest to
13464// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013465RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013466 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013467 CHECK(isolate->debugger()->live_edit_enabled());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013468 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013469 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013470 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013472 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013473
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013474 if (code->kind() != Code::FUNCTION &&
13475 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013476 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013477 }
13478
13479 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013480 int closest_pc = 0;
13481 int distance = kMaxInt;
13482 while (!it.done()) {
13483 int statement_position = static_cast<int>(it.rinfo()->data());
13484 // Check if this break point is closer that what was previously found.
13485 if (source_position <= statement_position &&
13486 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000013487 closest_pc =
13488 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013489 distance = statement_position - source_position;
13490 // Check whether we can't get any closer.
13491 if (distance == 0) break;
13492 }
13493 it.next();
13494 }
13495
13496 return Smi::FromInt(closest_pc);
13497}
13498
13499
ager@chromium.org357bf652010-04-12 11:30:10 +000013500// Calls specified function with or without entering the debugger.
13501// This is used in unit tests to run code as if debugger is entered or simply
13502// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013503RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013504 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013505 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013506 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13507 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000013508
13509 Handle<Object> result;
13510 bool pending_exception;
13511 {
13512 if (without_debugger) {
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013513 result = Execution::Call(isolate,
13514 function,
13515 isolate->global_object(),
13516 0,
13517 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013518 &pending_exception);
13519 } else {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013520 EnterDebugger enter_debugger(isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013521 result = Execution::Call(isolate,
13522 function,
13523 isolate->global_object(),
13524 0,
13525 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013526 &pending_exception);
13527 }
13528 }
13529 if (!pending_exception) {
13530 return *result;
13531 } else {
13532 return Failure::Exception();
13533 }
13534}
13535
13536
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013537// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013538RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013539 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013540 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000013541 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013542 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
13543 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013544 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013545}
13546
13547
13548// Performs a GC.
13549// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013550RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013551 SealHandleScope shs(isolate);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000013552 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013553 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013554}
13555
13556
13557// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013558RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013559 SealHandleScope shs(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013560 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013561 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013562 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013563 }
13564 return Smi::FromInt(usage);
13565}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013566
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013567#endif // ENABLE_DEBUGGER_SUPPORT
13568
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013569
danno@chromium.org59400602013-08-13 17:09:37 +000013570#ifdef V8_I18N_SUPPORT
13571RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) {
13572 HandleScope scope(isolate);
13573
13574 ASSERT(args.length() == 1);
13575 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13576
13577 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13578
13579 // Return value which denotes invalid language tag.
13580 const char* const kInvalidTag = "invalid-tag";
13581
13582 UErrorCode error = U_ZERO_ERROR;
13583 char icu_result[ULOC_FULLNAME_CAPACITY];
13584 int icu_length = 0;
13585
13586 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13587 &icu_length, &error);
13588 if (U_FAILURE(error) || icu_length == 0) {
13589 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13590 }
13591
13592 char result[ULOC_FULLNAME_CAPACITY];
13593
13594 // Force strict BCP47 rules.
13595 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13596
13597 if (U_FAILURE(error)) {
13598 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13599 }
13600
13601 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13602}
13603
13604
13605RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) {
13606 HandleScope scope(isolate);
13607
13608 ASSERT(args.length() == 1);
13609 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13610
13611 const icu::Locale* available_locales = NULL;
13612 int32_t count = 0;
13613
13614 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13615 available_locales = icu::Collator::getAvailableLocales(count);
13616 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13617 available_locales = icu::NumberFormat::getAvailableLocales(count);
13618 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13619 available_locales = icu::DateFormat::getAvailableLocales(count);
13620 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13621 available_locales = icu::BreakIterator::getAvailableLocales(count);
13622 }
13623
13624 UErrorCode error = U_ZERO_ERROR;
13625 char result[ULOC_FULLNAME_CAPACITY];
13626 Handle<JSObject> locales =
13627 isolate->factory()->NewJSObject(isolate->object_function());
13628
13629 for (int32_t i = 0; i < count; ++i) {
13630 const char* icu_name = available_locales[i].getName();
13631
13632 error = U_ZERO_ERROR;
13633 // No need to force strict BCP47 rules.
13634 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13635 if (U_FAILURE(error)) {
13636 // This shouldn't happen, but lets not break the user.
13637 continue;
13638 }
13639
13640 RETURN_IF_EMPTY_HANDLE(isolate,
13641 JSObject::SetLocalPropertyIgnoreAttributes(
13642 locales,
13643 isolate->factory()->NewStringFromAscii(CStrVector(result)),
13644 isolate->factory()->NewNumber(i),
13645 NONE));
13646 }
13647
13648 return *locales;
13649}
13650
13651
13652RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) {
13653 SealHandleScope shs(isolate);
13654
13655 ASSERT(args.length() == 0);
13656
13657 icu::Locale default_locale;
13658
13659 // Set the locale
13660 char result[ULOC_FULLNAME_CAPACITY];
13661 UErrorCode status = U_ZERO_ERROR;
13662 uloc_toLanguageTag(
13663 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13664 if (U_SUCCESS(status)) {
13665 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13666 }
13667
13668 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und"));
13669}
13670
13671
13672RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
13673 HandleScope scope(isolate);
13674
13675 ASSERT(args.length() == 1);
13676
13677 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13678
13679 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13680 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length);
13681 Handle<Name> maximized =
13682 isolate->factory()->NewStringFromAscii(CStrVector("maximized"));
13683 Handle<Name> base =
13684 isolate->factory()->NewStringFromAscii(CStrVector("base"));
13685 for (unsigned int i = 0; i < length; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000013686 MaybeObject* maybe_string = input->GetElement(isolate, i);
danno@chromium.org59400602013-08-13 17:09:37 +000013687 Object* locale_id;
13688 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) {
13689 return isolate->Throw(isolate->heap()->illegal_argument_string());
13690 }
13691
13692 v8::String::Utf8Value utf8_locale_id(
13693 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id))));
13694
13695 UErrorCode error = U_ZERO_ERROR;
13696
13697 // Convert from BCP47 to ICU format.
13698 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13699 char icu_locale[ULOC_FULLNAME_CAPACITY];
13700 int icu_locale_length = 0;
13701 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13702 &icu_locale_length, &error);
13703 if (U_FAILURE(error) || icu_locale_length == 0) {
13704 return isolate->Throw(isolate->heap()->illegal_argument_string());
13705 }
13706
13707 // Maximize the locale.
13708 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13709 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13710 uloc_addLikelySubtags(
13711 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13712
13713 // Remove extensions from maximized locale.
13714 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13715 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13716 uloc_getBaseName(
13717 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13718
13719 // Get original name without extensions.
13720 // de_DE@collation=phonebook -> de_DE
13721 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13722 uloc_getBaseName(
13723 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13724
13725 // Convert from ICU locale format to BCP47 format.
13726 // de_Latn_DE -> de-Latn-DE
13727 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13728 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13729 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13730
13731 // de_DE -> de-DE
13732 char base_locale[ULOC_FULLNAME_CAPACITY];
13733 uloc_toLanguageTag(
13734 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13735
13736 if (U_FAILURE(error)) {
13737 return isolate->Throw(isolate->heap()->illegal_argument_string());
13738 }
13739
13740 Handle<JSObject> result =
13741 isolate->factory()->NewJSObject(isolate->object_function());
13742 RETURN_IF_EMPTY_HANDLE(isolate,
13743 JSObject::SetLocalPropertyIgnoreAttributes(
13744 result,
13745 maximized,
13746 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)),
13747 NONE));
13748 RETURN_IF_EMPTY_HANDLE(isolate,
13749 JSObject::SetLocalPropertyIgnoreAttributes(
13750 result,
13751 base,
13752 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)),
13753 NONE));
13754 output->set(i, *result);
13755 }
13756
13757 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output);
13758 result->set_length(Smi::FromInt(length));
13759 return *result;
13760}
13761
13762
13763RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
13764 HandleScope scope(isolate);
13765
13766 ASSERT(args.length() == 3);
13767
13768 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13769 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13770 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13771
13772 Handle<ObjectTemplateInfo> date_format_template =
13773 I18N::GetTemplate(isolate);
13774
13775 // Create an empty object wrapper.
13776 bool has_pending_exception = false;
13777 Handle<JSObject> local_object = Execution::InstantiateObject(
13778 date_format_template, &has_pending_exception);
13779 if (has_pending_exception) {
13780 ASSERT(isolate->has_pending_exception());
13781 return Failure::Exception();
13782 }
13783
13784 // Set date time formatter as internal field of the resulting JS object.
13785 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
13786 isolate, locale, options, resolved);
13787
13788 if (!date_format) return isolate->ThrowIllegalOperation();
13789
13790 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
13791
13792 RETURN_IF_EMPTY_HANDLE(isolate,
13793 JSObject::SetLocalPropertyIgnoreAttributes(
13794 local_object,
13795 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
13796 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13797 NONE));
13798
danno@chromium.org59400602013-08-13 17:09:37 +000013799 // Make object handle weak so we can delete the data format once GC kicks in.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013800 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
13801 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
13802 NULL,
13803 DateFormat::DeleteDateFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013804 return *local_object;
13805}
13806
13807
13808RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
13809 HandleScope scope(isolate);
13810
13811 ASSERT(args.length() == 2);
13812
13813 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13814 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
13815
13816 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013817 Handle<Object> value =
13818 Execution::ToNumber(isolate, date, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013819 if (has_pending_exception) {
13820 ASSERT(isolate->has_pending_exception());
13821 return Failure::Exception();
13822 }
13823
13824 icu::SimpleDateFormat* date_format =
13825 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13826 if (!date_format) return isolate->ThrowIllegalOperation();
13827
13828 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013829 date_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013830
13831 return *isolate->factory()->NewStringFromTwoByte(
13832 Vector<const uint16_t>(
13833 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13834 result.length()));
13835}
13836
13837
13838RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
13839 HandleScope scope(isolate);
13840
13841 ASSERT(args.length() == 2);
13842
13843 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13844 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
13845
13846 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
13847 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
13848 icu::SimpleDateFormat* date_format =
13849 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13850 if (!date_format) return isolate->ThrowIllegalOperation();
13851
13852 UErrorCode status = U_ZERO_ERROR;
13853 UDate date = date_format->parse(u_date, status);
13854 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13855
13856 bool has_pending_exception = false;
13857 Handle<JSDate> result = Handle<JSDate>::cast(
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013858 Execution::NewDate(
13859 isolate, static_cast<double>(date), &has_pending_exception));
danno@chromium.org59400602013-08-13 17:09:37 +000013860 if (has_pending_exception) {
13861 ASSERT(isolate->has_pending_exception());
13862 return Failure::Exception();
13863 }
13864 return *result;
13865}
13866
13867
13868RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
13869 HandleScope scope(isolate);
13870
13871 ASSERT(args.length() == 3);
13872
13873 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13874 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13875 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13876
13877 Handle<ObjectTemplateInfo> number_format_template =
13878 I18N::GetTemplate(isolate);
13879
13880 // Create an empty object wrapper.
13881 bool has_pending_exception = false;
13882 Handle<JSObject> local_object = Execution::InstantiateObject(
13883 number_format_template, &has_pending_exception);
13884 if (has_pending_exception) {
13885 ASSERT(isolate->has_pending_exception());
13886 return Failure::Exception();
13887 }
13888
13889 // Set number formatter as internal field of the resulting JS object.
13890 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
13891 isolate, locale, options, resolved);
13892
13893 if (!number_format) return isolate->ThrowIllegalOperation();
13894
13895 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
13896
13897 RETURN_IF_EMPTY_HANDLE(isolate,
13898 JSObject::SetLocalPropertyIgnoreAttributes(
13899 local_object,
13900 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
13901 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13902 NONE));
13903
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013904 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
13905 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
13906 NULL,
13907 NumberFormat::DeleteNumberFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013908 return *local_object;
13909}
13910
13911
13912RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
13913 HandleScope scope(isolate);
13914
13915 ASSERT(args.length() == 2);
13916
13917 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13918 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
13919
13920 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013921 Handle<Object> value = Execution::ToNumber(
13922 isolate, number, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013923 if (has_pending_exception) {
13924 ASSERT(isolate->has_pending_exception());
13925 return Failure::Exception();
13926 }
13927
13928 icu::DecimalFormat* number_format =
13929 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13930 if (!number_format) return isolate->ThrowIllegalOperation();
13931
13932 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013933 number_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013934
13935 return *isolate->factory()->NewStringFromTwoByte(
13936 Vector<const uint16_t>(
13937 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13938 result.length()));
13939}
13940
13941
13942RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
13943 HandleScope scope(isolate);
13944
13945 ASSERT(args.length() == 2);
13946
13947 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13948 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
13949
13950 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
13951 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
13952 icu::DecimalFormat* number_format =
13953 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13954 if (!number_format) return isolate->ThrowIllegalOperation();
13955
13956 UErrorCode status = U_ZERO_ERROR;
13957 icu::Formattable result;
13958 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
13959 // to be part of Chrome.
13960 // TODO(cira): Include currency parsing code using parseCurrency call.
13961 // We need to check if the formatter parses all currencies or only the
13962 // one it was constructed with (it will impact the API - how to return ISO
13963 // code and the value).
13964 number_format->parse(u_number, result, status);
13965 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13966
13967 switch (result.getType()) {
13968 case icu::Formattable::kDouble:
13969 return *isolate->factory()->NewNumber(result.getDouble());
13970 case icu::Formattable::kLong:
13971 return *isolate->factory()->NewNumberFromInt(result.getLong());
13972 case icu::Formattable::kInt64:
13973 return *isolate->factory()->NewNumber(
13974 static_cast<double>(result.getInt64()));
13975 default:
13976 return isolate->heap()->undefined_value();
13977 }
13978}
13979
13980
13981RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) {
13982 HandleScope scope(isolate);
13983
13984 ASSERT(args.length() == 3);
13985
13986 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13987 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13988 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13989
13990 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
13991
13992 // Create an empty object wrapper.
13993 bool has_pending_exception = false;
13994 Handle<JSObject> local_object = Execution::InstantiateObject(
13995 collator_template, &has_pending_exception);
13996 if (has_pending_exception) {
13997 ASSERT(isolate->has_pending_exception());
13998 return Failure::Exception();
13999 }
14000
14001 // Set collator as internal field of the resulting JS object.
14002 icu::Collator* collator = Collator::InitializeCollator(
14003 isolate, locale, options, resolved);
14004
14005 if (!collator) return isolate->ThrowIllegalOperation();
14006
14007 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
14008
14009 RETURN_IF_EMPTY_HANDLE(isolate,
14010 JSObject::SetLocalPropertyIgnoreAttributes(
14011 local_object,
14012 isolate->factory()->NewStringFromAscii(CStrVector("collator")),
14013 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14014 NONE));
14015
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014016 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14017 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
14018 NULL,
14019 Collator::DeleteCollator);
danno@chromium.org59400602013-08-13 17:09:37 +000014020 return *local_object;
14021}
14022
14023
14024RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) {
14025 HandleScope scope(isolate);
14026
14027 ASSERT(args.length() == 3);
14028
14029 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14030 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14031 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14032
14033 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14034 if (!collator) return isolate->ThrowIllegalOperation();
14035
14036 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14037 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14038 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14039 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14040 UErrorCode status = U_ZERO_ERROR;
14041 UCollationResult result = collator->compare(u_string1,
14042 string_value1.length(),
14043 u_string2,
14044 string_value2.length(),
14045 status);
14046 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14047
14048 return *isolate->factory()->NewNumberFromInt(result);
14049}
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014050
14051
14052RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) {
14053 HandleScope scope(isolate);
14054
14055 ASSERT(args.length() == 3);
14056
14057 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14058 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14059 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14060
14061 Handle<ObjectTemplateInfo> break_iterator_template =
14062 I18N::GetTemplate2(isolate);
14063
14064 // Create an empty object wrapper.
14065 bool has_pending_exception = false;
14066 Handle<JSObject> local_object = Execution::InstantiateObject(
14067 break_iterator_template, &has_pending_exception);
14068 if (has_pending_exception) {
14069 ASSERT(isolate->has_pending_exception());
14070 return Failure::Exception();
14071 }
14072
14073 // Set break iterator as internal field of the resulting JS object.
14074 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14075 isolate, locale, options, resolved);
14076
14077 if (!break_iterator) return isolate->ThrowIllegalOperation();
14078
14079 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14080 // Make sure that the pointer to adopted text is NULL.
14081 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14082
14083 RETURN_IF_EMPTY_HANDLE(isolate,
14084 JSObject::SetLocalPropertyIgnoreAttributes(
14085 local_object,
14086 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")),
14087 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14088 NONE));
14089
14090 // Make object handle weak so we can delete the break iterator once GC kicks
14091 // in.
14092 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
14093 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()),
14094 NULL,
14095 BreakIterator::DeleteBreakIterator);
14096 return *local_object;
14097}
14098
14099
14100RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) {
14101 HandleScope scope(isolate);
14102
14103 ASSERT(args.length() == 2);
14104
14105 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14106 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14107
14108 icu::BreakIterator* break_iterator =
14109 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14110 if (!break_iterator) return isolate->ThrowIllegalOperation();
14111
14112 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14113 break_iterator_holder->GetInternalField(1));
14114 delete u_text;
14115
14116 v8::String::Value text_value(v8::Utils::ToLocal(text));
14117 u_text = new icu::UnicodeString(
14118 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14119 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14120
14121 break_iterator->setText(*u_text);
14122
14123 return isolate->heap()->undefined_value();
14124}
14125
14126
14127RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) {
14128 HandleScope scope(isolate);
14129
14130 ASSERT(args.length() == 1);
14131
14132 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14133
14134 icu::BreakIterator* break_iterator =
14135 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14136 if (!break_iterator) return isolate->ThrowIllegalOperation();
14137
14138 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14139}
14140
14141
14142RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) {
14143 HandleScope scope(isolate);
14144
14145 ASSERT(args.length() == 1);
14146
14147 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14148
14149 icu::BreakIterator* break_iterator =
14150 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14151 if (!break_iterator) return isolate->ThrowIllegalOperation();
14152
14153 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14154}
14155
14156
14157RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) {
14158 HandleScope scope(isolate);
14159
14160 ASSERT(args.length() == 1);
14161
14162 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14163
14164 icu::BreakIterator* break_iterator =
14165 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14166 if (!break_iterator) return isolate->ThrowIllegalOperation();
14167
14168 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14169}
14170
14171
14172RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) {
14173 HandleScope scope(isolate);
14174
14175 ASSERT(args.length() == 1);
14176
14177 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14178
14179 icu::BreakIterator* break_iterator =
14180 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14181 if (!break_iterator) return isolate->ThrowIllegalOperation();
14182
14183 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14184 icu::RuleBasedBreakIterator* rule_based_iterator =
14185 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14186 int32_t status = rule_based_iterator->getRuleStatus();
14187 // Keep return values in sync with JavaScript BreakType enum.
14188 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14189 return *isolate->factory()->NewStringFromAscii(CStrVector("none"));
14190 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14191 return *isolate->factory()->NewStringFromAscii(CStrVector("number"));
14192 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14193 return *isolate->factory()->NewStringFromAscii(CStrVector("letter"));
14194 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14195 return *isolate->factory()->NewStringFromAscii(CStrVector("kana"));
14196 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14197 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo"));
14198 } else {
14199 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown"));
14200 }
14201}
danno@chromium.org59400602013-08-13 17:09:37 +000014202#endif // V8_I18N_SUPPORT
14203
14204
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014205// Finds the script object from the script data. NOTE: This operation uses
14206// heap traversal to find the function generated for the source position
14207// for the requested break point. For lazily compiled functions several heap
14208// traversals might be required rendering this operation as a rather slow
14209// operation. However for setting break points which is normally done through
14210// some kind of user interaction the performance is not crucial.
14211static Handle<Object> Runtime_GetScriptFromScriptName(
14212 Handle<String> script_name) {
14213 // Scan the heap for Script objects to find the script with the requested
14214 // script data.
14215 Handle<Script> script;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014216 Factory* factory = script_name->GetIsolate()->factory();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014217 Heap* heap = script_name->GetHeap();
14218 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014219 DisallowHeapAllocation no_allocation_during_heap_iteration;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014220 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014221 HeapObject* obj = NULL;
14222 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014223 // If a script is found check if it has the script data requested.
14224 if (obj->IsScript()) {
14225 if (Script::cast(obj)->name()->IsString()) {
14226 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14227 script = Handle<Script>(Script::cast(obj));
14228 }
14229 }
14230 }
14231 }
14232
14233 // If no script with the requested script data is found return undefined.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014234 if (script.is_null()) return factory->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014235
14236 // Return the script found.
14237 return GetScriptWrapper(script);
14238}
14239
14240
14241// Get the script object from script data. NOTE: Regarding performance
14242// see the NOTE for GetScriptFromScriptData.
14243// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014244RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014245 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014246
14247 ASSERT(args.length() == 1);
14248
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014249 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014250
14251 // Find the requested script.
14252 Handle<Object> result =
14253 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14254 return *result;
14255}
14256
14257
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014258// Collect the raw data for a stack trace. Returns an array of 4
14259// element segments each containing a receiver, function, code and
14260// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014261RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014262 HandleScope scope(isolate);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014263 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014264 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014265 Handle<Object> caller = args.at<Object>(1);
14266 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014267
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014268 // Optionally capture a more detailed stack trace for the message.
14269 isolate->CaptureAndSetDetailedStackTrace(error_object);
14270 // Capture a simple stack trace for the stack property.
14271 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14272}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014273
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014274
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014275// Retrieve the stack trace. This is the raw stack trace that yet has to
14276// be formatted. Since we only need this once, clear it afterwards.
14277RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000014278 HandleScope scope(isolate);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014279 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014280 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14281 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14282 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014283 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14284 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014285 JSObject::DeleteHiddenProperty(error_object, key);
14286 return *result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014287}
14288
14289
ager@chromium.org3811b432009-10-28 14:53:37 +000014290// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014291RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014292 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014293 ASSERT_EQ(args.length(), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000014294
14295 const char* version_string = v8::V8::GetVersion();
14296
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000014297 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014298 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000014299}
14300
14301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014302RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014303 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014304 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014305 OS::PrintError("abort: %s\n",
14306 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000014307 isolate->PrintStack(stderr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014308 OS::Abort();
14309 UNREACHABLE();
14310 return NULL;
14311}
14312
14313
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014314RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
14315 HandleScope scope(isolate);
14316 ASSERT(args.length() == 1);
14317 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14318 FlattenString(str);
14319 return isolate->heap()->undefined_value();
14320}
14321
14322
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +000014323RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) {
14324 HandleScope scope(isolate);
14325 ASSERT(args.length() == 0);
14326 isolate->heap()->NotifyContextDisposed();
14327 return isolate->heap()->undefined_value();
14328}
14329
14330
danno@chromium.org59400602013-08-13 17:09:37 +000014331RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) {
14332 HandleScope scope(isolate);
14333 ASSERT(args.length() == 1);
14334 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14335 if (!object->IsJSObject()) return Smi::FromInt(0);
14336 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14337 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14338 JSObject::MigrateInstance(js_object);
14339 return *object;
14340}
14341
14342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014343RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014344 SealHandleScope shs(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014345 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014346 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014347 Object* key = args[1];
14348
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014349 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014350 Object* o = cache->get(finger_index);
14351 if (o == key) {
14352 // The fastest case: hit the same place again.
14353 return cache->get(finger_index + 1);
14354 }
14355
14356 for (int i = finger_index - 2;
14357 i >= JSFunctionResultCache::kEntriesIndex;
14358 i -= 2) {
14359 o = cache->get(i);
14360 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014361 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014362 return cache->get(i + 1);
14363 }
14364 }
14365
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014366 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014367 ASSERT(size <= cache->length());
14368
14369 for (int i = size - 2; i > finger_index; i -= 2) {
14370 o = cache->get(i);
14371 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014372 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014373 return cache->get(i + 1);
14374 }
14375 }
14376
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014377 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014378 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014379
14380 Handle<JSFunctionResultCache> cache_handle(cache);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014381 Handle<Object> key_handle(key, isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014382 Handle<Object> value;
14383 {
14384 Handle<JSFunction> factory(JSFunction::cast(
14385 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14386 // TODO(antonm): consider passing a receiver when constructing a cache.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014387 Handle<Object> receiver(isolate->native_context()->global_object(),
14388 isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014389 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014390 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014391 bool pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000014392 value = Execution::Call(isolate,
14393 factory,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014394 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014395 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014396 argv,
14397 &pending_exception);
14398 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014399 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014400
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014401#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014402 if (FLAG_verify_heap) {
14403 cache_handle->JSFunctionResultCacheVerify();
14404 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014405#endif
14406
14407 // Function invocation may have cleared the cache. Reread all the data.
14408 finger_index = cache_handle->finger_index();
14409 size = cache_handle->size();
14410
14411 // If we have spare room, put new data into it, otherwise evict post finger
14412 // entry which is likely to be the least recently used.
14413 int index = -1;
14414 if (size < cache_handle->length()) {
14415 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14416 index = size;
14417 } else {
14418 index = finger_index + JSFunctionResultCache::kEntrySize;
14419 if (index == cache_handle->length()) {
14420 index = JSFunctionResultCache::kEntriesIndex;
14421 }
14422 }
14423
14424 ASSERT(index % 2 == 0);
14425 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14426 ASSERT(index < cache_handle->length());
14427
14428 cache_handle->set(index, *key_handle);
14429 cache_handle->set(index + 1, *value);
14430 cache_handle->set_finger_index(index);
14431
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014432#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014433 if (FLAG_verify_heap) {
14434 cache_handle->JSFunctionResultCacheVerify();
14435 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014436#endif
14437
14438 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014439}
14440
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014442RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014443 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014444 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014445 return Smi::FromInt(message->start_position());
14446}
14447
14448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014449RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014450 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014451 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014452 return message->script();
14453}
14454
14455
kasper.lund44510672008-07-25 07:37:58 +000014456#ifdef DEBUG
14457// ListNatives is ONLY used by the fuzz-natives.js in debug mode
14458// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014459RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014460 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014461 ASSERT(args.length() == 0);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014462#define COUNT_ENTRY(Name, argc, ressize) + 1
14463 int entry_count = 0
14464 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14465 INLINE_FUNCTION_LIST(COUNT_ENTRY)
14466 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
14467#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014468 Factory* factory = isolate->factory();
14469 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014470 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014471 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000014472#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014473 { \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014474 HandleScope inner(isolate); \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014475 Handle<String> name; \
14476 /* Inline runtime functions have an underscore in front of the name. */ \
14477 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014478 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014479 Vector<const char>("_" #Name, StrLength("_" #Name))); \
14480 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014481 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014482 Vector<const char>(#Name, StrLength(#Name))); \
14483 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014484 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014485 pair_elements->set(0, *name); \
14486 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014487 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014488 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014489 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014490 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014491 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014492 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014493 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014494 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014495#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014496 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014497 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014498 return *result;
14499}
kasper.lund44510672008-07-25 07:37:58 +000014500#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014501
14502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014503RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014504 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014505 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014506 CONVERT_ARG_CHECKED(String, format, 0);
14507 CONVERT_ARG_CHECKED(JSArray, elms, 1);
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014508 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014509 String::FlatContent format_content = format->GetFlatContent();
14510 RUNTIME_ASSERT(format_content.IsAscii());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014511 Vector<const uint8_t> chars = format_content.ToOneByteVector();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000014512 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014513 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014514}
14515
14516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014517RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014518 UNREACHABLE(); // implemented as macro in the parser
14519 return NULL;
14520}
14521
14522
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014523#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14524 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014525 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014526 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14527 }
14528
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
14530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14531ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014533ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014534ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014535ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014536ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
14537ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14538ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
14539ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
14540ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
14541ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
14542ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
14543ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
14544ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
14545ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
mmassi@chromium.org7028c052012-06-13 11:51:58 +000014546// Properties test sitting with elements tests - not fooling anyone.
14547ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014548
14549#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14550
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014551
14552RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014553 SealHandleScope shs(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014554 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014555 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14556 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014557 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14558}
14559
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014560
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014561RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) {
14562 SealHandleScope shs(isolate);
14563 ASSERT(args.length() == 1);
14564 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
14565 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded());
14566}
14567
14568
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014569RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014570 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014571 ASSERT(args.length() == 1);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +000014572
14573 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14574 JSReceiver* obj = JSReceiver::cast(args[0]);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014575 if (obj->IsJSGlobalProxy()) {
14576 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014577 if (proto->IsNull()) return isolate->heap()->false_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014578 ASSERT(proto->IsJSGlobalObject());
14579 obj = JSReceiver::cast(proto);
14580 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014581 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14582}
14583
14584
14585RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014586 HandleScope scope(isolate);
danno@chromium.org169691d2013-07-15 08:01:13 +000014587 ASSERT(args.length() == 1);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014588 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014589 if (obj->IsJSGlobalProxy()) {
14590 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014591 if (proto->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014592 ASSERT(proto->IsJSGlobalObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014593 obj = handle(JSReceiver::cast(proto));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014594 }
danno@chromium.org59400602013-08-13 17:09:37 +000014595 if (obj->IsJSProxy())
14596 return isolate->heap()->undefined_value();
14597
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014598 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014599 Handle<JSObject>::cast(obj)->HasFastElements()));
danno@chromium.org169691d2013-07-15 08:01:13 +000014600 ASSERT(obj->IsJSObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014601 JSObject::SetObserved(Handle<JSObject>::cast(obj));
14602 return isolate->heap()->undefined_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014603}
14604
14605
14606RUNTIME_FUNCTION(MaybeObject*, Runtime_SetObserverDeliveryPending) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014607 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014608 ASSERT(args.length() == 0);
14609 isolate->set_observer_delivery_pending(true);
14610 return isolate->heap()->undefined_value();
14611}
14612
14613
14614RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014615 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014616 ASSERT(args.length() == 0);
14617 return isolate->heap()->observation_state();
14618}
14619
14620
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014621RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014622 HandleScope scope(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014623 ASSERT(args.length() == 0);
14624 // TODO(adamk): Currently this runtime function is only called three times per
14625 // isolate. If it's called more often, the map should be moved into the
14626 // strong root list.
14627 Handle<Map> map =
14628 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
14629 Handle<JSWeakMap> weakmap =
14630 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000014631 return WeakCollectionInitialize(isolate, weakmap);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014632}
14633
14634
14635RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014636 SealHandleScope shs(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014637 ASSERT(args.length() == 1);
14638 Object* object = args[0];
14639 if (object->IsJSGlobalProxy()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000014640 object = object->GetPrototype(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014641 if (object->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014642 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014643 return object;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014644}
14645
14646
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014647RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) {
14648 HandleScope scope(isolate);
14649 ASSERT(args.length() == 3);
14650 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
14651 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
14652 ASSERT(object->IsAccessCheckNeeded());
14653 Handle<Object> key = args.at<Object>(2);
14654 SaveContext save(isolate);
14655 isolate->set_context(observer->context());
14656 if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
14657 v8::ACCESS_KEYS)) {
14658 return isolate->heap()->false_value();
14659 }
14660 bool access_allowed = false;
14661 uint32_t index = 0;
14662 if (key->ToArrayIndex(&index) ||
14663 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) {
14664 access_allowed =
14665 isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) &&
14666 isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS);
14667 } else {
14668 access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) &&
14669 isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS);
14670 }
14671 return isolate->heap()->ToBoolean(access_allowed);
14672}
14673
14674
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014675static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
14676 Handle<JSFunction> constructor,
14677 Handle<Object> type_info,
14678 Arguments* caller_args) {
14679 bool holey = false;
14680 bool can_use_type_feedback = true;
14681 if (caller_args->length() == 1) {
14682 Object* argument_one = (*caller_args)[0];
14683 if (argument_one->IsSmi()) {
14684 int value = Smi::cast(argument_one)->value();
14685 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
14686 // the array is a dictionary in this case.
14687 can_use_type_feedback = false;
14688 } else if (value != 0) {
14689 holey = true;
14690 }
14691 } else {
14692 // Non-smi length argument produces a dictionary
14693 can_use_type_feedback = false;
14694 }
14695 }
14696
14697 JSArray* array;
14698 MaybeObject* maybe_array;
14699 if (!type_info.is_null() &&
14700 *type_info != isolate->heap()->undefined_value() &&
danno@chromium.orgbee51992013-07-10 14:57:15 +000014701 Cell::cast(*type_info)->value()->IsAllocationSite() &&
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014702 can_use_type_feedback) {
danno@chromium.orgbee51992013-07-10 14:57:15 +000014703 Handle<Cell> cell = Handle<Cell>::cast(type_info);
14704 Handle<AllocationSite> site = Handle<AllocationSite>(
14705 AllocationSite::cast(cell->value()), isolate);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014706 ASSERT(!site->SitePointsToLiteral());
danno@chromium.orgbee51992013-07-10 14:57:15 +000014707 ElementsKind to_kind = site->GetElementsKind();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014708 if (holey && !IsFastHoleyElementsKind(to_kind)) {
14709 to_kind = GetHoleyElementsKind(to_kind);
14710 // Update the allocation site info to reflect the advice alteration.
danno@chromium.orgbee51992013-07-10 14:57:15 +000014711 site->SetElementsKind(to_kind);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014712 }
14713
14714 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
danno@chromium.orgbee51992013-07-10 14:57:15 +000014715 *constructor, site);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014716 if (!maybe_array->To(&array)) return maybe_array;
14717 } else {
14718 maybe_array = isolate->heap()->AllocateJSObject(*constructor);
14719 if (!maybe_array->To(&array)) return maybe_array;
14720 // We might need to transition to holey
14721 ElementsKind kind = constructor->initial_map()->elements_kind();
14722 if (holey && !IsFastHoleyElementsKind(kind)) {
14723 kind = GetHoleyElementsKind(kind);
14724 maybe_array = array->TransitionElementsKind(kind);
14725 if (maybe_array->IsFailure()) return maybe_array;
14726 }
14727 }
14728
14729 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
14730 DONT_INITIALIZE_ARRAY_ELEMENTS);
14731 if (maybe_array->IsFailure()) return maybe_array;
14732 maybe_array = ArrayConstructInitializeElements(array, caller_args);
14733 if (maybe_array->IsFailure()) return maybe_array;
14734 return array;
14735}
14736
14737
14738RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
14739 HandleScope scope(isolate);
14740 // If we get 2 arguments then they are the stub parameters (constructor, type
14741 // info). If we get 3, then the first one is a pointer to the arguments
14742 // passed by the caller.
14743 Arguments empty_args(0, NULL);
14744 bool no_caller_args = args.length() == 2;
14745 ASSERT(no_caller_args || args.length() == 3);
14746 int parameters_start = no_caller_args ? 0 : 1;
14747 Arguments* caller_args = no_caller_args
14748 ? &empty_args
14749 : reinterpret_cast<Arguments*>(args[0]);
14750 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14751 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
14752
14753 return ArrayConstructorCommon(isolate,
14754 constructor,
14755 type_info,
14756 caller_args);
14757}
14758
14759
14760RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) {
14761 HandleScope scope(isolate);
14762 Arguments empty_args(0, NULL);
14763 bool no_caller_args = args.length() == 1;
14764 ASSERT(no_caller_args || args.length() == 2);
14765 int parameters_start = no_caller_args ? 0 : 1;
14766 Arguments* caller_args = no_caller_args
14767 ? &empty_args
14768 : reinterpret_cast<Arguments*>(args[0]);
14769 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14770
14771 return ArrayConstructorCommon(isolate,
14772 constructor,
14773 Handle<Object>::null(),
14774 caller_args);
14775}
14776
14777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014778// ----------------------------------------------------------------------------
14779// Implementation of Runtime
14780
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014781#define F(name, number_of_args, result_size) \
14782 { Runtime::k##name, Runtime::RUNTIME, #name, \
14783 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014784
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014785
14786#define I(name, number_of_args, result_size) \
14787 { Runtime::kInline##name, Runtime::INLINE, \
14788 "_" #name, NULL, number_of_args, result_size },
14789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014790static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014791 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014792 INLINE_FUNCTION_LIST(I)
14793 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014794};
14795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014797MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
14798 Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014799 ASSERT(dictionary != NULL);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014800 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014801 for (int i = 0; i < kNumFunctions; ++i) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014802 Object* name_string;
14803 { MaybeObject* maybe_name_string =
14804 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
14805 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014806 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000014807 NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
14808 { MaybeObject* maybe_dictionary = name_dictionary->Add(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014809 String::cast(name_string),
lrn@chromium.org303ada72010-10-27 09:33:13 +000014810 Smi::FromInt(i),
danno@chromium.orgf005df62013-04-30 16:36:45 +000014811 PropertyDetails(NONE, NORMAL, Representation::None()));
lrn@chromium.org303ada72010-10-27 09:33:13 +000014812 if (!maybe_dictionary->ToObject(&dictionary)) {
14813 // Non-recoverable failure. Calling code must restart heap
14814 // initialization.
14815 return maybe_dictionary;
14816 }
14817 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014818 }
14819 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014820}
14821
14822
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014823const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014824 Heap* heap = name->GetHeap();
14825 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014826 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014827 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014828 int function_index = Smi::cast(smi_index)->value();
14829 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014830 }
14831 return NULL;
14832}
14833
14834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014835const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014836 return &(kIntrinsicFunctions[static_cast<int>(id)]);
14837}
14838
14839
machenbach@chromium.org528ce022013-09-23 14:09:36 +000014840void Runtime::PerformGC(Object* result, Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014841 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014842 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014843 if (isolate->heap()->new_space()->AddFreshPage()) {
14844 return;
14845 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000014846
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014847 // Try to do a garbage collection; ignore it if it fails. The C
14848 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014849 isolate->heap()->CollectGarbage(failure->allocation_space(),
14850 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014851 } else {
14852 // Handle last resort GC and make sure to allow future allocations
14853 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014854 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014855 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
14856 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014857 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014858}
14859
14860
14861} } // namespace v8::internal