blob: 713d4501ae5dfe521f6d28d743335366019db7a4 [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
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000557static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate,
558 Handle<FixedArray> literals,
559 int literals_index,
560 Handle<FixedArray> elements,
561 int flags) {
562 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals,
563 literals_index, elements);
564 RETURN_IF_EMPTY_HANDLE(isolate, site);
565
566 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
567 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
568 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
569 usage_context.EnterNewScope();
570 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
571 ? JSObject::kNoHints
572 : JSObject::kObjectIsShallowArray;
573 Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context,
574 hints);
575 usage_context.ExitScope(site, boilerplate);
576 RETURN_IF_EMPTY_HANDLE(isolate, copy);
577 return *copy;
578}
579
580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000581RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 HandleScope scope(isolate);
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000583 ASSERT(args.length() == 4);
584 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
585 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
586 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
587 CONVERT_SMI_ARG_CHECKED(flags, 3);
588
589 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
590 flags);
591}
592
593
594RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralStubBailout) {
595 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000599 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000600
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000601 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
602 ArrayLiteral::kShallowElements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000607 HandleScope scope(isolate);
608 ASSERT(args.length() == 1);
609 Handle<Object> name(args[0], isolate);
610 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
611 Symbol* symbol;
612 MaybeObject* maybe = isolate->heap()->AllocateSymbol();
613 if (!maybe->To(&symbol)) return maybe;
614 if (name->IsString()) symbol->set_name(*name);
615 return symbol;
616}
617
618
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) {
620 HandleScope scope(isolate);
621 ASSERT(args.length() == 1);
622 Handle<Object> name(args[0], isolate);
623 RUNTIME_ASSERT(name->IsString() || name->IsUndefined());
624 Symbol* symbol;
625 MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol();
626 if (!maybe->To(&symbol)) return maybe;
627 if (name->IsString()) symbol->set_name(*name);
628 return symbol;
629}
630
631
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000632RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000633 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000634 ASSERT(args.length() == 1);
635 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
636 return symbol->name();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000637}
638
639
machenbach@chromium.org0cc09502013-11-13 12:20:55 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) {
641 SealHandleScope shs(isolate);
642 ASSERT(args.length() == 1);
643 CONVERT_ARG_CHECKED(Symbol, symbol, 0);
644 return isolate->heap()->ToBoolean(symbol->is_private());
645}
646
647
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000648RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000649 SealHandleScope shs(isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000650 ASSERT(args.length() == 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000651 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000652 Object* prototype = args[1];
653 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000654 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000655 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
656}
657
658
lrn@chromium.org34e60782011-09-15 07:25:40 +0000659RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000660 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000661 ASSERT(args.length() == 4);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000662 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000663 Object* call_trap = args[1];
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000664 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
665 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000666 Object* prototype = args[3];
667 Object* used_prototype =
668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
669 return isolate->heap()->AllocateJSFunctionProxy(
670 handler, call_trap, construct_trap, used_prototype);
671}
672
673
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000675 SealHandleScope shs(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000678 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679}
680
681
lrn@chromium.org34e60782011-09-15 07:25:40 +0000682RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000683 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000684 ASSERT(args.length() == 1);
685 Object* obj = args[0];
686 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
687}
688
689
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000691 SealHandleScope shs(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000692 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000693 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000694 return proxy->handler();
695}
696
697
lrn@chromium.org34e60782011-09-15 07:25:40 +0000698RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000699 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000700 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000701 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000702 return proxy->call_trap();
703}
704
705
706RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000707 SealHandleScope shs(isolate);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->construct_trap();
711}
712
713
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000714RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000715 HandleScope scope(isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000716 ASSERT(args.length() == 1);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000717 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
718 JSProxy::Fix(proxy);
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000719 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000720}
721
722
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000723void Runtime::FreeArrayBuffer(Isolate* isolate,
724 JSArrayBuffer* phantom_array_buffer) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000725 if (phantom_array_buffer->should_be_freed()) {
726 ASSERT(phantom_array_buffer->is_external());
727 free(phantom_array_buffer->backing_store());
728 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000729 if (phantom_array_buffer->is_external()) return;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000730
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000731 size_t allocated_length = NumberToSize(
732 isolate, phantom_array_buffer->byte_length());
733
734 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000735 -static_cast<int64_t>(allocated_length));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000736 CHECK(V8::ArrayBufferAllocator() != NULL);
danno@chromium.org307dd6e2013-08-06 07:31:48 +0000737 V8::ArrayBufferAllocator()->Free(
738 phantom_array_buffer->backing_store(),
739 allocated_length);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000740}
741
742
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000743void Runtime::SetupArrayBuffer(Isolate* isolate,
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000744 Handle<JSArrayBuffer> array_buffer,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000745 bool is_external,
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000746 void* data,
747 size_t allocated_length) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000748 ASSERT(array_buffer->GetInternalFieldCount() ==
749 v8::ArrayBuffer::kInternalFieldCount);
750 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
751 array_buffer->SetInternalField(i, Smi::FromInt(0));
752 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000753 array_buffer->set_backing_store(data);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000754 array_buffer->set_flag(Smi::FromInt(0));
755 array_buffer->set_is_external(is_external);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000756
757 Handle<Object> byte_length =
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000758 isolate->factory()->NewNumberFromSize(allocated_length);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000759 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
760 array_buffer->set_byte_length(*byte_length);
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000761
762 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
763 isolate->heap()->set_array_buffers_list(*array_buffer);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000764 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000765}
766
767
768bool Runtime::SetupArrayBufferAllocatingData(
769 Isolate* isolate,
770 Handle<JSArrayBuffer> array_buffer,
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000771 size_t allocated_length,
772 bool initialize) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000773 void* data;
ulan@chromium.org837a67e2013-06-11 15:39:48 +0000774 CHECK(V8::ArrayBufferAllocator() != NULL);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000775 if (allocated_length != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000776 if (initialize) {
777 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
778 } else {
779 data =
780 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
781 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000782 if (data == NULL) return false;
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000783 } else {
784 data = NULL;
785 }
786
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000787 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000788
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000789 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length);
790
791 return true;
792}
793
794
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000795RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) {
796 HandleScope scope(isolate);
797 ASSERT(args.length() == 2);
798 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
799 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1);
800 size_t allocated_length;
801 if (byteLength->IsSmi()) {
802 allocated_length = Smi::cast(*byteLength)->value();
803 } else {
804 ASSERT(byteLength->IsHeapNumber());
805 double value = HeapNumber::cast(*byteLength)->value();
806
807 ASSERT(value >= 0);
808
809 if (value > std::numeric_limits<size_t>::max()) {
810 return isolate->Throw(
811 *isolate->factory()->NewRangeError("invalid_array_buffer_length",
812 HandleVector<Object>(NULL, 0)));
813 }
814
815 allocated_length = static_cast<size_t>(value);
816 }
817
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000818 if (!Runtime::SetupArrayBufferAllocatingData(isolate,
819 holder, allocated_length)) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000820 return isolate->Throw(*isolate->factory()->
821 NewRangeError("invalid_array_buffer_length",
822 HandleVector<Object>(NULL, 0)));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000823 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000824
825 return *holder;
826}
827
828
829RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000830 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000831 ASSERT(args.length() == 1);
832 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
833 return holder->byte_length();
834}
835
836
837RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
838 HandleScope scope(isolate);
839 ASSERT(args.length() == 3);
840 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
841 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
842 CONVERT_DOUBLE_ARG_CHECKED(first, 2);
843 size_t start = static_cast<size_t>(first);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000844 size_t target_length = NumberToSize(isolate, target->byte_length());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000845
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000846 if (target_length == 0) return isolate->heap()->undefined_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000847
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000848 ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000849 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
850 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
851 CopyBytes(target_data, source_data + start, target_length);
852 return isolate->heap()->undefined_value();
853}
854
855
mvstanton@chromium.org63ea3d22013-10-10 09:24:12 +0000856RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) {
857 HandleScope scope(isolate);
858 ASSERT(args.length() == 1);
859 CONVERT_ARG_CHECKED(Object, object, 0);
860 return object->IsJSArrayBufferView()
861 ? isolate->heap()->true_value()
862 : isolate->heap()->false_value();
863}
864
865
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000866void Runtime::ArrayIdToTypeAndSize(
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000867 int arrayId, ExternalArrayType* array_type, size_t* element_size) {
868 switch (arrayId) {
869 case ARRAY_ID_UINT8:
870 *array_type = kExternalUnsignedByteArray;
871 *element_size = 1;
872 break;
873 case ARRAY_ID_INT8:
874 *array_type = kExternalByteArray;
875 *element_size = 1;
876 break;
877 case ARRAY_ID_UINT16:
878 *array_type = kExternalUnsignedShortArray;
879 *element_size = 2;
880 break;
881 case ARRAY_ID_INT16:
882 *array_type = kExternalShortArray;
883 *element_size = 2;
884 break;
885 case ARRAY_ID_UINT32:
886 *array_type = kExternalUnsignedIntArray;
887 *element_size = 4;
888 break;
889 case ARRAY_ID_INT32:
890 *array_type = kExternalIntArray;
891 *element_size = 4;
892 break;
893 case ARRAY_ID_FLOAT32:
894 *array_type = kExternalFloatArray;
895 *element_size = 4;
896 break;
897 case ARRAY_ID_FLOAT64:
898 *array_type = kExternalDoubleArray;
899 *element_size = 8;
900 break;
901 case ARRAY_ID_UINT8C:
902 *array_type = kExternalPixelArray;
903 *element_size = 1;
904 break;
905 default:
906 UNREACHABLE();
907 }
908}
909
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000910
911RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
912 HandleScope scope(isolate);
913 ASSERT(args.length() == 5);
914 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
915 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
916 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
917 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
918 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
919
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000920 ASSERT(holder->GetInternalFieldCount() ==
921 v8::ArrayBufferView::kInternalFieldCount);
922 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
923 holder->SetInternalField(i, Smi::FromInt(0));
924 }
925
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000926 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
927 size_t element_size = 1; // Bogus initialization.
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000928 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000929
930 holder->set_buffer(*buffer);
931 holder->set_byte_offset(*byte_offset_object);
932 holder->set_byte_length(*byte_length_object);
933
934 size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
935 size_t byte_length = NumberToSize(isolate, *byte_length_object);
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000936 ASSERT(byte_length % element_size == 0);
937 size_t length = byte_length / element_size;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000938
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000939 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
940 return isolate->Throw(*isolate->factory()->
941 NewRangeError("invalid_typed_array_length",
942 HandleVector<Object>(NULL, 0)));
943 }
944
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000945 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000946 holder->set_length(*length_obj);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000947 holder->set_weak_next(buffer->weak_first_view());
948 buffer->set_weak_first_view(*holder);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000949
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000950 Handle<ExternalArray> elements =
951 isolate->factory()->NewExternalArray(
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000952 static_cast<int>(length), array_type,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000953 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000954 holder->set_elements(*elements);
955 return isolate->heap()->undefined_value();
956}
957
958
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000959// Initializes a typed array from an array-like object.
960// If an array-like object happens to be a typed array of the same type,
961// initializes backing store using memove.
962//
963// Returns true if backing store was initialized or false otherwise.
964RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) {
965 HandleScope scope(isolate);
966 ASSERT(args.length() == 4);
967 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
968 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
969 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
970 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3);
971
972 ASSERT(holder->GetInternalFieldCount() ==
973 v8::ArrayBufferView::kInternalFieldCount);
974 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
975 holder->SetInternalField(i, Smi::FromInt(0));
976 }
977
978 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
979 size_t element_size = 1; // Bogus initialization.
machenbach@chromium.org37be4082013-11-26 13:50:38 +0000980 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size);
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000981
982 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
983 size_t length = NumberToSize(isolate, *length_obj);
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000984
985 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
986 (length > (kMaxInt / element_size))) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000987 return isolate->Throw(*isolate->factory()->
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000988 NewRangeError("invalid_typed_array_length",
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000989 HandleVector<Object>(NULL, 0)));
990 }
machenbach@chromium.orgfeecfde2013-11-14 10:55:00 +0000991 size_t byte_length = length * element_size;
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000992
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000993 // NOTE: not initializing backing store.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000994 // We assume that the caller of this function will initialize holder
995 // with the loop
996 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000997 // We assume that the caller of this function is always a typed array
998 // constructor.
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000999 // If source is a typed array, this loop will always run to completion,
1000 // so we are sure that the backing store will be initialized.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001001 // Otherwise, the indexing operation might throw, so the loop will not
1002 // run to completion and the typed array might remain partly initialized.
1003 // However we further assume that the caller of this function is a typed array
1004 // constructor, and the exception will propagate out of the constructor,
1005 // therefore uninitialized memory will not be accessible by a user program.
1006 //
1007 // TODO(dslomov): revise this once we support subclassing.
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001008
1009 if (!Runtime::SetupArrayBufferAllocatingData(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001010 isolate, buffer, byte_length, false)) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001011 return isolate->Throw(*isolate->factory()->
1012 NewRangeError("invalid_array_buffer_length",
1013 HandleVector<Object>(NULL, 0)));
1014 }
1015
1016 holder->set_buffer(*buffer);
1017 holder->set_byte_offset(Smi::FromInt(0));
1018 Handle<Object> byte_length_obj(
1019 isolate->factory()->NewNumberFromSize(byte_length));
1020 holder->set_byte_length(*byte_length_obj);
1021 holder->set_length(*length_obj);
1022 holder->set_weak_next(buffer->weak_first_view());
1023 buffer->set_weak_first_view(*holder);
1024
1025 Handle<ExternalArray> elements =
1026 isolate->factory()->NewExternalArray(
1027 static_cast<int>(length), array_type,
1028 static_cast<uint8_t*>(buffer->backing_store()));
1029 holder->set_elements(*elements);
1030
1031 if (source->IsJSTypedArray()) {
1032 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
1033
1034 if (typed_array->type() == holder->type()) {
1035 uint8_t* backing_store =
1036 static_cast<uint8_t*>(
1037 JSArrayBuffer::cast(typed_array->buffer())->backing_store());
1038 size_t source_byte_offset =
1039 NumberToSize(isolate, typed_array->byte_offset());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001040 memcpy(
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001041 buffer->backing_store(),
1042 backing_store + source_byte_offset,
1043 byte_length);
1044 return *isolate->factory()->true_value();
1045 } else {
1046 return *isolate->factory()->false_value();
1047 }
1048 }
1049
1050 return *isolate->factory()->false_value();
1051}
1052
1053
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001054#define TYPED_ARRAY_GETTER(getter, accessor) \
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001055 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
1056 HandleScope scope(isolate); \
1057 ASSERT(args.length() == 1); \
1058 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \
1059 if (!holder->IsJSTypedArray()) \
1060 return isolate->Throw(*isolate->factory()->NewTypeError( \
1061 "not_typed_array", HandleVector<Object>(NULL, 0))); \
1062 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \
1063 return typed_array->accessor(); \
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001064 }
1065
1066TYPED_ARRAY_GETTER(Buffer, buffer)
1067TYPED_ARRAY_GETTER(ByteLength, byte_length)
1068TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
1069TYPED_ARRAY_GETTER(Length, length)
1070
1071#undef TYPED_ARRAY_GETTER
1072
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001073// Return codes for Runtime_TypedArraySetFastCases.
1074// Should be synchronized with typedarray.js natives.
1075enum TypedArraySetResultCodes {
1076 // Set from typed array of the same type.
1077 // This is processed by TypedArraySetFastCases
1078 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
1079 // Set from typed array of the different type, overlapping in memory.
1080 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
1081 // Set from typed array of the different type, non-overlapping.
1082 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
1083 // Set from non-typed array.
1084 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
1085};
1086
1087
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001088RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) {
1089 HandleScope scope(isolate);
1090 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
1091 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1);
1092 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2);
1093
1094 if (!target_obj->IsJSTypedArray())
1095 return isolate->Throw(*isolate->factory()->NewTypeError(
1096 "not_typed_array", HandleVector<Object>(NULL, 0)));
1097
1098 if (!source_obj->IsJSTypedArray())
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001099 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001100
1101 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
1102 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
1103 size_t offset = NumberToSize(isolate, *offset_obj);
1104 size_t target_length = NumberToSize(isolate, target->length());
1105 size_t source_length = NumberToSize(isolate, source->length());
1106 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
1107 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
1108 if (offset > target_length ||
1109 offset + source_length > target_length ||
1110 offset + source_length < offset) // overflow
1111 return isolate->Throw(*isolate->factory()->NewRangeError(
1112 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0)));
1113
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001114 size_t target_offset = NumberToSize(isolate, target->byte_offset());
1115 size_t source_offset = NumberToSize(isolate, source->byte_offset());
1116 uint8_t* target_base =
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001117 static_cast<uint8_t*>(
1118 JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001119 uint8_t* source_base =
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001120 static_cast<uint8_t*>(
1121 JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001122
1123 // Typed arrays of the same type: use memmove.
1124 if (target->type() == source->type()) {
1125 memmove(target_base + offset * target->element_size(),
1126 source_base, source_byte_length);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001127 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001128 }
1129
1130 // Typed arrays of different types over the same backing store
1131 if ((source_base <= target_base &&
1132 source_base + source_byte_length > target_base) ||
1133 (target_base <= source_base &&
1134 target_base + target_byte_length > source_base)) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001135 // We do not support overlapping ArrayBuffers
1136 ASSERT(
1137 JSArrayBuffer::cast(target->buffer())->backing_store() ==
1138 JSArrayBuffer::cast(source->buffer())->backing_store());
1139 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001140 } else { // Non-overlapping typed arrays
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001141 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001142 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001143}
1144
1145
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001146RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) {
1147 HandleScope scope(isolate);
1148 ASSERT(args.length() == 4);
1149 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
1150 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
1151 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
1152 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
1153
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001154 ASSERT(holder->GetInternalFieldCount() ==
1155 v8::ArrayBufferView::kInternalFieldCount);
1156 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
1157 holder->SetInternalField(i, Smi::FromInt(0));
1158 }
1159
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001160 holder->set_buffer(*buffer);
1161 ASSERT(byte_offset->IsNumber());
1162 ASSERT(
1163 NumberToSize(isolate, buffer->byte_length()) >=
1164 NumberToSize(isolate, *byte_offset)
1165 + NumberToSize(isolate, *byte_length));
1166 holder->set_byte_offset(*byte_offset);
1167 ASSERT(byte_length->IsNumber());
1168 holder->set_byte_length(*byte_length);
1169
1170 holder->set_weak_next(buffer->weak_first_view());
1171 buffer->set_weak_first_view(*holder);
1172
1173 return isolate->heap()->undefined_value();
1174}
1175
1176
1177RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) {
1178 HandleScope scope(isolate);
1179 ASSERT(args.length() == 1);
1180 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1181 return data_view->buffer();
1182}
1183
1184
1185RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) {
1186 HandleScope scope(isolate);
1187 ASSERT(args.length() == 1);
1188 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1189 return data_view->byte_offset();
1190}
1191
1192
1193RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) {
1194 HandleScope scope(isolate);
1195 ASSERT(args.length() == 1);
1196 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0);
1197 return data_view->byte_length();
1198}
1199
1200
1201inline static bool NeedToFlipBytes(bool is_little_endian) {
1202#ifdef V8_TARGET_LITTLE_ENDIAN
1203 return !is_little_endian;
1204#else
1205 return is_little_endian;
1206#endif
1207}
1208
1209
1210template<int n>
1211inline void CopyBytes(uint8_t* target, uint8_t* source) {
1212 for (int i = 0; i < n; i++) {
1213 *(target++) = *(source++);
1214 }
1215}
1216
1217
1218template<int n>
1219inline void FlipBytes(uint8_t* target, uint8_t* source) {
1220 source = source + (n-1);
1221 for (int i = 0; i < n; i++) {
1222 *(target++) = *(source--);
1223 }
1224}
1225
1226
1227template<typename T>
1228inline static bool DataViewGetValue(
1229 Isolate* isolate,
1230 Handle<JSDataView> data_view,
1231 Handle<Object> byte_offset_obj,
1232 bool is_little_endian,
1233 T* result) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001234 size_t byte_offset = 0;
1235 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1236 return false;
1237 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001238 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1239
1240 size_t data_view_byte_offset =
1241 NumberToSize(isolate, data_view->byte_offset());
1242 size_t data_view_byte_length =
1243 NumberToSize(isolate, data_view->byte_length());
1244 if (byte_offset + sizeof(T) > data_view_byte_length ||
1245 byte_offset + sizeof(T) < byte_offset) { // overflow
1246 return false;
1247 }
1248
1249 union Value {
1250 T data;
1251 uint8_t bytes[sizeof(T)];
1252 };
1253
1254 Value value;
1255 size_t buffer_offset = data_view_byte_offset + byte_offset;
1256 ASSERT(
1257 NumberToSize(isolate, buffer->byte_length())
1258 >= buffer_offset + sizeof(T));
1259 uint8_t* source =
1260 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1261 if (NeedToFlipBytes(is_little_endian)) {
1262 FlipBytes<sizeof(T)>(value.bytes, source);
1263 } else {
1264 CopyBytes<sizeof(T)>(value.bytes, source);
1265 }
1266 *result = value.data;
1267 return true;
1268}
1269
1270
1271template<typename T>
1272static bool DataViewSetValue(
1273 Isolate* isolate,
1274 Handle<JSDataView> data_view,
1275 Handle<Object> byte_offset_obj,
1276 bool is_little_endian,
1277 T data) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001278 size_t byte_offset = 0;
1279 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
1280 return false;
1281 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001282 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
1283
1284 size_t data_view_byte_offset =
1285 NumberToSize(isolate, data_view->byte_offset());
1286 size_t data_view_byte_length =
1287 NumberToSize(isolate, data_view->byte_length());
1288 if (byte_offset + sizeof(T) > data_view_byte_length ||
1289 byte_offset + sizeof(T) < byte_offset) { // overflow
1290 return false;
1291 }
1292
1293 union Value {
1294 T data;
1295 uint8_t bytes[sizeof(T)];
1296 };
1297
1298 Value value;
1299 value.data = data;
1300 size_t buffer_offset = data_view_byte_offset + byte_offset;
1301 ASSERT(
1302 NumberToSize(isolate, buffer->byte_length())
1303 >= buffer_offset + sizeof(T));
1304 uint8_t* target =
1305 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
1306 if (NeedToFlipBytes(is_little_endian)) {
1307 FlipBytes<sizeof(T)>(target, value.bytes);
1308 } else {
1309 CopyBytes<sizeof(T)>(target, value.bytes);
1310 }
1311 return true;
1312}
1313
1314
1315#define DATA_VIEW_GETTER(TypeName, Type, Converter) \
1316 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \
1317 HandleScope scope(isolate); \
1318 ASSERT(args.length() == 3); \
1319 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1320 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1321 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
1322 Type result; \
1323 if (DataViewGetValue( \
1324 isolate, holder, offset, is_little_endian, &result)) { \
1325 return isolate->heap()->Converter(result); \
1326 } else { \
1327 return isolate->Throw(*isolate->factory()->NewRangeError( \
1328 "invalid_data_view_accessor_offset", \
1329 HandleVector<Object>(NULL, 0))); \
1330 } \
1331 }
1332
1333DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32)
1334DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32)
1335DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32)
1336DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32)
1337DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32)
1338DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32)
1339DATA_VIEW_GETTER(Float32, float, NumberFromDouble)
1340DATA_VIEW_GETTER(Float64, double, NumberFromDouble)
1341
1342#undef DATA_VIEW_GETTER
1343
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001344
1345template <typename T>
1346static T DataViewConvertValue(double value);
1347
1348
1349template <>
1350int8_t DataViewConvertValue<int8_t>(double value) {
1351 return static_cast<int8_t>(DoubleToInt32(value));
1352}
1353
1354
1355template <>
1356int16_t DataViewConvertValue<int16_t>(double value) {
1357 return static_cast<int16_t>(DoubleToInt32(value));
1358}
1359
1360
1361template <>
1362int32_t DataViewConvertValue<int32_t>(double value) {
1363 return DoubleToInt32(value);
1364}
1365
1366
1367template <>
1368uint8_t DataViewConvertValue<uint8_t>(double value) {
1369 return static_cast<uint8_t>(DoubleToUint32(value));
1370}
1371
1372
1373template <>
1374uint16_t DataViewConvertValue<uint16_t>(double value) {
1375 return static_cast<uint16_t>(DoubleToUint32(value));
1376}
1377
1378
1379template <>
1380uint32_t DataViewConvertValue<uint32_t>(double value) {
1381 return DoubleToUint32(value);
1382}
1383
1384
1385template <>
1386float DataViewConvertValue<float>(double value) {
1387 return static_cast<float>(value);
1388}
1389
1390
1391template <>
1392double DataViewConvertValue<double>(double value) {
1393 return value;
1394}
1395
1396
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001397#define DATA_VIEW_SETTER(TypeName, Type) \
1398 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \
1399 HandleScope scope(isolate); \
1400 ASSERT(args.length() == 4); \
1401 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
1402 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \
1403 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \
1404 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001405 Type v = DataViewConvertValue<Type>(value->Number()); \
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001406 if (DataViewSetValue( \
1407 isolate, holder, offset, is_little_endian, v)) { \
1408 return isolate->heap()->undefined_value(); \
1409 } else { \
1410 return isolate->Throw(*isolate->factory()->NewRangeError( \
1411 "invalid_data_view_accessor_offset", \
1412 HandleVector<Object>(NULL, 0))); \
1413 } \
1414 }
1415
1416DATA_VIEW_SETTER(Uint8, uint8_t)
1417DATA_VIEW_SETTER(Int8, int8_t)
1418DATA_VIEW_SETTER(Uint16, uint16_t)
1419DATA_VIEW_SETTER(Int16, int16_t)
1420DATA_VIEW_SETTER(Uint32, uint32_t)
1421DATA_VIEW_SETTER(Int32, int32_t)
1422DATA_VIEW_SETTER(Float32, float)
1423DATA_VIEW_SETTER(Float64, double)
1424
1425#undef DATA_VIEW_SETTER
1426
1427
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001428RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
1429 HandleScope scope(isolate);
1430 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001431 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001432 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
1433 holder->set_table(*table);
1434 return *holder;
1435}
1436
1437
1438RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
1439 HandleScope scope(isolate);
1440 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001441 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001442 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001443 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001444 table = ObjectHashSet::Add(table, key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001445 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001446 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001447}
1448
1449
1450RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
1451 HandleScope scope(isolate);
1452 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001453 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001454 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1456 return isolate->heap()->ToBoolean(table->Contains(*key));
1457}
1458
1459
1460RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
1461 HandleScope scope(isolate);
1462 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001463 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001464 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001465 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001466 table = ObjectHashSet::Remove(table, key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001467 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001468 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001469}
1470
1471
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001472RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
1473 HandleScope scope(isolate);
1474 ASSERT(args.length() == 1);
1475 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
1476 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
1477 return Smi::FromInt(table->NumberOfElements());
1478}
1479
1480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001481RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
1482 HandleScope scope(isolate);
1483 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001484 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001485 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
1486 holder->set_table(*table);
1487 return *holder;
1488}
1489
1490
1491RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
1492 HandleScope scope(isolate);
1493 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001494 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001495 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1496 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001497 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001498 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1499}
1500
1501
1502RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) {
1503 HandleScope scope(isolate);
1504 ASSERT(args.length() == 2);
1505 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1506 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1507 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001508 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001509 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1510}
1511
1512
1513RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) {
1514 HandleScope scope(isolate);
1515 ASSERT(args.length() == 2);
1516 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1517 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1518 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001519 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001520 Handle<ObjectHashTable> new_table =
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001521 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001522 holder->set_table(*new_table);
1523 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001524}
1525
1526
1527RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
1528 HandleScope scope(isolate);
1529 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001530 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001531 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1532 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001533 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001534 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001535 holder->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001536 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001537}
1538
1539
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001540RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
1541 HandleScope scope(isolate);
1542 ASSERT(args.length() == 1);
1543 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
1544 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
1545 return Smi::FromInt(table->NumberOfElements());
1546}
1547
1548
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001549static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate,
1550 Handle<JSWeakCollection> weak_collection) {
1551 ASSERT(weak_collection->map()->inobject_properties() == 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001552 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001553 weak_collection->set_table(*table);
1554 weak_collection->set_next(Smi::FromInt(0));
1555 return *weak_collection;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001556}
1557
1558
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001559RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001560 HandleScope scope(isolate);
1561 ASSERT(args.length() == 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001562 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
1563 return WeakCollectionInitialize(isolate, weak_collection);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001564}
1565
1566
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001567RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001568 HandleScope scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001569 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001570 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001571 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001572 Handle<ObjectHashTable> table(
1573 ObjectHashTable::cast(weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001574 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001575 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
1576}
1577
1578
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001579RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001580 HandleScope scope(isolate);
1581 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001582 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001583 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001584 Handle<ObjectHashTable> table(
1585 ObjectHashTable::cast(weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001586 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001587 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
1588}
1589
1590
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001591RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001592 HandleScope scope(isolate);
1593 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001594 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001595 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001596 Handle<ObjectHashTable> table(ObjectHashTable::cast(
1597 weak_collection->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001598 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001599 Handle<ObjectHashTable> new_table =
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001600 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001601 weak_collection->set_table(*new_table);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00001602 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001603}
1604
1605
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001606RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001607 HandleScope scope(isolate);
1608 ASSERT(args.length() == 3);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001609 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001610 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001611 Handle<Object> value(args[2], isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001612 Handle<ObjectHashTable> table(
1613 ObjectHashTable::cast(weak_collection->table()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001614 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001615 weak_collection->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001616 return isolate->heap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001621 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622 ASSERT(args.length() == 1);
1623 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 return JSObject::cast(obj)->class_name();
1626}
1627
ager@chromium.org7c537e22008-10-16 08:43:32 +00001628
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001629RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001630 HandleScope scope(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001631 ASSERT(args.length() == 1);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001632 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001633 // We don't expect access checks to be needed on JSProxy objects.
1634 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001635 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001636 if (obj->IsAccessCheckNeeded() &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001637 !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj),
1638 isolate->factory()->proto_string(),
1639 v8::ACCESS_GET)) {
1640 isolate->ReportFailedAccessCheck(JSObject::cast(*obj), v8::ACCESS_GET);
danno@chromium.org169691d2013-07-15 08:01:13 +00001641 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001642 return isolate->heap()->undefined_value();
1643 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001644 obj = handle(obj->GetPrototype(isolate), isolate);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001645 } while (obj->IsJSObject() &&
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001646 JSObject::cast(*obj)->map()->is_hidden_prototype());
1647 return *obj;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001648}
1649
1650
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001651static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate,
1652 Object* receiver) {
1653 Object* current = receiver->GetPrototype(isolate);
1654 while (current->IsJSObject() &&
1655 JSObject::cast(current)->map()->is_hidden_prototype()) {
1656 current = current->GetPrototype(isolate);
1657 }
1658 return current;
1659}
1660
1661
ulan@chromium.org750145a2013-03-07 15:14:13 +00001662RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001663 HandleScope scope(isolate);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001664 ASSERT(args.length() == 2);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001665 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1666 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001667 if (FLAG_harmony_observation && obj->map()->is_observed()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001668 Handle<Object> old_value(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001669 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001670
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001671 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001672 RETURN_IF_EMPTY_HANDLE(isolate, result);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001673
1674 Handle<Object> new_value(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001675 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001676 if (!new_value->SameValue(*old_value)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001677 JSObject::EnqueueChangeRecord(obj, "setPrototype",
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001678 isolate->factory()->proto_string(),
1679 old_value);
1680 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001681 return *result;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001682 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001683 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001684 RETURN_IF_EMPTY_HANDLE(isolate, result);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001685 return *result;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001686}
1687
1688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001689RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001690 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 ASSERT(args.length() == 2);
1692 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
1693 Object* O = args[0];
1694 Object* V = args[1];
1695 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001696 Object* prototype = V->GetPrototype(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 if (prototype->IsNull()) return isolate->heap()->false_value();
1698 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 V = prototype;
1700 }
1701}
1702
1703
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001704static bool CheckAccessException(Object* callback,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001705 v8::AccessType access_type) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001706 DisallowHeapAllocation no_gc;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001707 if (callback->IsAccessorInfo()) {
1708 AccessorInfo* info = AccessorInfo::cast(callback);
1709 return
1710 (access_type == v8::ACCESS_HAS &&
1711 (info->all_can_read() || info->all_can_write())) ||
1712 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1713 (access_type == v8::ACCESS_SET && info->all_can_write());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001714 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001715 if (callback->IsAccessorPair()) {
1716 AccessorPair* info = AccessorPair::cast(callback);
1717 return
1718 (access_type == v8::ACCESS_HAS &&
1719 (info->all_can_read() || info->all_can_write())) ||
1720 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1721 (access_type == v8::ACCESS_SET && info->all_can_write());
1722 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001723 return false;
1724}
1725
1726
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001727template<class Key>
1728static bool CheckGenericAccess(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001729 Handle<JSObject> receiver,
1730 Handle<JSObject> holder,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001731 Key key,
1732 v8::AccessType access_type,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001733 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001734 Isolate* isolate = receiver->GetIsolate();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001735 for (Handle<JSObject> current = receiver;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001736 true;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001737 current = handle(JSObject::cast(current->GetPrototype()), isolate)) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001738 if (current->IsAccessCheckNeeded() &&
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001739 !(isolate->*mayAccess)(current, key, access_type)) {
1740 return false;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001741 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001742 if (current.is_identical_to(holder)) break;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001743 }
1744 return true;
1745}
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001746
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001747
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001748enum AccessCheckResult {
1749 ACCESS_FORBIDDEN,
1750 ACCESS_ALLOWED,
1751 ACCESS_ABSENT
1752};
1753
1754
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001755static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj,
1756 Handle<Name> name,
1757 v8::AccessType access_type) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001758 uint32_t index;
1759 if (name->AsArrayIndex(&index)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001760 // TODO(1095): we should traverse hidden prototype hierachy as well.
1761 if (CheckGenericAccess(
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001762 obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001763 return ACCESS_ALLOWED;
1764 }
1765
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001766 obj->GetIsolate()->ReportFailedAccessCheck(*obj, access_type);
danno@chromium.org169691d2013-07-15 08:01:13 +00001767 return ACCESS_FORBIDDEN;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001768 }
1769
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001770 Isolate* isolate = obj->GetIsolate();
1771 LookupResult lookup(isolate);
1772 obj->LocalLookup(*name, &lookup, true);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001773
1774 if (!lookup.IsProperty()) return ACCESS_ABSENT;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001775 Handle<JSObject> holder(lookup.holder(), isolate);
1776 if (CheckGenericAccess<Handle<Object> >(
1777 obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001778 return ACCESS_ALLOWED;
1779 }
1780
1781 // Access check callback denied the access, but some properties
1782 // can have a special permissions which override callbacks descision
1783 // (currently see v8::AccessControl).
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001784 // API callbacks can have per callback access exceptions.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001785 switch (lookup.type()) {
1786 case CALLBACKS:
1787 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1788 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001789 }
1790 break;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001791 case INTERCEPTOR:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001792 // If the object has an interceptor, try real named properties.
1793 // Overwrite the result to fetch the correct property later.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001794 holder->LookupRealNamedProperty(*name, &lookup);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001795 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1796 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1797 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001798 }
1799 }
1800 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001801 default:
1802 break;
1803 }
1804
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001805 isolate->ReportFailedAccessCheck(*obj, access_type);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001806 return ACCESS_FORBIDDEN;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001807}
1808
1809
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001810// Enumerator used as indices into the array returned from GetOwnProperty
1811enum PropertyDescriptorIndices {
1812 IS_ACCESSOR_INDEX,
1813 VALUE_INDEX,
1814 GETTER_INDEX,
1815 SETTER_INDEX,
1816 WRITABLE_INDEX,
1817 ENUMERABLE_INDEX,
1818 CONFIGURABLE_INDEX,
1819 DESCRIPTOR_SIZE
1820};
1821
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001822
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001823static Handle<Object> GetOwnProperty(Isolate* isolate,
1824 Handle<JSObject> obj,
1825 Handle<Name> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 Heap* heap = isolate->heap();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001827 Factory* factory = isolate->factory();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001828 // Due to some WebKit tests, we want to make sure that we do not log
1829 // more than one access failure here.
danno@chromium.org169691d2013-07-15 08:01:13 +00001830 AccessCheckResult access_check_result =
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001831 CheckPropertyAccess(obj, name, v8::ACCESS_HAS);
1832 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
danno@chromium.org169691d2013-07-15 08:01:13 +00001833 switch (access_check_result) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001834 case ACCESS_FORBIDDEN: return factory->false_value();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001835 case ACCESS_ALLOWED: break;
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001836 case ACCESS_ABSENT: return factory->undefined_value();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001837 }
1838
1839 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name);
danno@chromium.org169691d2013-07-15 08:01:13 +00001840 if (attrs == ABSENT) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001841 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
1842 return factory->undefined_value();
danno@chromium.org169691d2013-07-15 08:01:13 +00001843 }
1844 ASSERT(!isolate->has_scheduled_exception());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001845 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name);
1846 Handle<AccessorPair> accessors(raw_accessors, isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001848 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1849 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001850 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001851
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001852 if (raw_accessors == NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001853 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1854 // GetProperty does access check.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001855 Handle<Object> value = GetProperty(isolate, obj, name);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001856 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001857 elms->set(VALUE_INDEX, *value);
1858 } else {
1859 // Access checks are performed for both accessors separately.
1860 // When they fail, the respective field is not set in the descriptor.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001861 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
1862 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
1863
1864 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001865 ASSERT(!isolate->has_scheduled_exception());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001866 elms->set(GETTER_INDEX, *getter);
danno@chromium.org169691d2013-07-15 08:01:13 +00001867 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001868 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001869 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001870
1871 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001872 ASSERT(!isolate->has_scheduled_exception());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001873 elms->set(SETTER_INDEX, *setter);
danno@chromium.org169691d2013-07-15 08:01:13 +00001874 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001875 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001876 }
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001877 }
1878
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001879 return isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001880}
1881
1882
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001883// Returns an array with the property description:
1884// if args[1] is not a property on args[0]
1885// returns undefined
1886// if args[1] is a data property on args[0]
1887// [false, value, Writeable, Enumerable, Configurable]
1888// if args[1] is an accessor on args[0]
1889// [true, GetFunction, SetFunction, Enumerable, Configurable]
1890RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001891 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001892 ASSERT(args.length() == 2);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001893 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001894 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001895 Handle<Object> result = GetOwnProperty(isolate, obj, name);
1896 RETURN_IF_EMPTY_HANDLE(isolate, result);
1897 return *result;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001902 HandleScope scope(isolate);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001903 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001904 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1905 Handle<Object> result = JSObject::PreventExtensions(obj);
1906 RETURN_IF_EMPTY_HANDLE(isolate, result);
1907 return *result;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001908}
1909
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001912 SealHandleScope shs(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001913 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001914 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001915 if (obj->IsJSGlobalProxy()) {
1916 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001918 ASSERT(proto->IsJSGlobalObject());
1919 obj = JSObject::cast(proto);
1920 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001921 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001928 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1929 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1930 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001931 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001932 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001933 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001938 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001940 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942}
1943
1944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001946 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 ASSERT(args.length() == 1);
1948 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001949 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001950 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951}
1952
1953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001954RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001955 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001957 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1958 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001959 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1960 InstanceType type = templ->map()->instance_type();
1961 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1962 type == OBJECT_TEMPLATE_INFO_TYPE);
1963 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001964 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001965 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1966 } else {
1967 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1968 }
1969 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970}
1971
1972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001973RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001974 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001975 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001976 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001977 Map* old_map = object->map();
1978 bool needs_access_checks = old_map->is_access_check_needed();
1979 if (needs_access_checks) {
1980 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001981 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001982 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001983 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00001984
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001985 new_map->set_is_access_check_needed(false);
1986 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00001987 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001988 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001989}
1990
1991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001992RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001993 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001994 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001995 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001996 Map* old_map = object->map();
1997 if (!old_map->is_access_check_needed()) {
1998 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001999 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00002000 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002001 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00002002
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002003 new_map->set_is_access_check_needed(true);
2004 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00002005 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002006 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00002007}
2008
2009
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002010// Transform getter or setter into something DefineAccessor can handle.
2011static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
2012 Handle<Object> component) {
2013 if (component->IsUndefined()) return isolate->factory()->null_value();
2014 Handle<FunctionTemplateInfo> info =
2015 Handle<FunctionTemplateInfo>::cast(component);
2016 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
2017}
2018
2019
2020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) {
2021 HandleScope scope(isolate);
2022 ASSERT(args.length() == 6);
2023 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2024 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2025 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
2026 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
2027 CONVERT_SMI_ARG_CHECKED(attribute, 4);
2028 CONVERT_SMI_ARG_CHECKED(access_control, 5);
2029 JSObject::DefineAccessor(object,
2030 name,
2031 InstantiateAccessorComponent(isolate, getter),
2032 InstantiateAccessorComponent(isolate, setter),
2033 static_cast<PropertyAttributes>(attribute),
2034 static_cast<v8::AccessControl>(access_control));
2035 return isolate->heap()->undefined_value();
2036}
2037
2038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039static Failure* ThrowRedeclarationError(Isolate* isolate,
2040 const char* type,
2041 Handle<String> name) {
2042 HandleScope scope(isolate);
2043 Handle<Object> type_handle =
2044 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 Handle<Object> args[2] = { type_handle, name };
2046 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002047 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
2048 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049}
2050
2051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002052RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002054 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 Handle<GlobalObject> global = Handle<GlobalObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002056 isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057
ager@chromium.org3811b432009-10-28 14:53:37 +00002058 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002059 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002060 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 // Traverse the name/value pairs and set the properties.
2063 int length = pairs->length();
2064 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002066 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002067 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068
2069 // We have to declare a global const property. To capture we only
2070 // assign to it when evaluating the assignment for "const x =
2071 // <expr>" the initial value is the hole.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002072 bool is_var = value->IsUndefined();
2073 bool is_const = value->IsTheHole();
2074 bool is_function = value->IsSharedFunctionInfo();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002075 ASSERT(is_var + is_const + is_function == 1);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002076
2077 if (is_var || is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 // Lookup the property in the global object, and don't set the
2079 // value of the variable if the property is already there.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002080 // Do the lookup locally only, see ES5 erratum.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002081 LookupResult lookup(isolate);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002082 if (FLAG_es52_globals) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002083 global->LocalLookup(*name, &lookup, true);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002084 } else {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002085 global->Lookup(*name, &lookup);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002086 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002087 if (lookup.IsFound()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002088 // We found an existing property. Unless it was an interceptor
2089 // that claims the property is absent, skip this declaration.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002090 if (!lookup.IsInterceptor()) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002091 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002092 if (attributes != ABSENT) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002093 // Fall-through and introduce the absent property by using
2094 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002095 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002096 } else if (is_function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002097 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002098 Handle<SharedFunctionInfo> shared =
2099 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002100 Handle<JSFunction> function =
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002101 isolate->factory()->NewFunctionFromSharedFunctionInfo(
2102 shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002103 value = function;
2104 }
2105
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002106 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002107 global->LocalLookup(*name, &lookup, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002108
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002109 // Compute the property attributes. According to ECMA-262,
2110 // the property must be non-configurable except in eval.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002111 int attr = NONE;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002112 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002113 if (!is_eval) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002114 attr |= DONT_DELETE;
2115 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002116 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002117 if (is_const || (is_native && is_function)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002118 attr |= READ_ONLY;
2119 }
2120
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002121 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
2122
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002123 if (!lookup.IsFound() || is_function) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002124 // If the local property exists, check that we can reconfigure it
2125 // as required for function declarations.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002126 if (lookup.IsFound() && lookup.IsDontDelete()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002127 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002128 lookup.IsPropertyCallbacks()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002129 return ThrowRedeclarationError(isolate, "function", name);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002130 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002131 // If the existing property is not configurable, keep its attributes.
2132 attr = lookup.GetAttributes();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002133 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002134 // Define or redefine own property.
2135 RETURN_IF_EMPTY_HANDLE(isolate,
2136 JSObject::SetLocalPropertyIgnoreAttributes(
2137 global, name, value, static_cast<PropertyAttributes>(attr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002138 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002139 // Do a [[Put]] on the existing (own) property.
2140 RETURN_IF_EMPTY_HANDLE(isolate,
2141 JSObject::SetProperty(
2142 global, name, value, static_cast<PropertyAttributes>(attr),
2143 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 }
2145 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002147 ASSERT(!isolate->has_pending_exception());
2148 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149}
2150
2151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002152RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002153 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002154 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002156 // Declarations are always made in a function or native context. In the
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002157 // case of eval code, the context passed is the context of the caller,
2158 // which may be some nested context and not the declaration context.
2159 RUNTIME_ASSERT(args[0]->IsContext());
2160 Handle<Context> context(Context::cast(args[0])->declaration_context());
2161
ager@chromium.org7c537e22008-10-16 08:43:32 +00002162 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002163 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002164 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002165 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 int index;
2168 PropertyAttributes attributes;
2169 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002170 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002171 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002172 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173
2174 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002175 // The name was declared before; check for conflicting re-declarations.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002176 // Note: this is actually inconsistent with what happens for globals (where
2177 // we silently ignore such declarations).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
2179 // Functions are not read-only.
2180 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
2181 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002182 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 }
2184
2185 // Initialize it if necessary.
2186 if (*initial_value != NULL) {
2187 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188 ASSERT(holder.is_identical_to(context));
2189 if (((attributes & READ_ONLY) == 0) ||
2190 context->get(index)->IsTheHole()) {
2191 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 }
2193 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002194 // Slow case: The property is in the context extension object of a
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002195 // function context or the global object of a native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002196 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002197 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002199 JSReceiver::SetProperty(object, name, initial_value, mode,
2200 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201 }
2202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002204 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002205 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002206 // "declared" in the function context's extension context or as a
2207 // property of the the global object.
2208 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002209 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002210 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002211 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002212 // Context extension objects are allocated lazily.
2213 ASSERT(context->IsFunctionContext());
2214 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002215 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002216 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002217 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002218 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219
ager@chromium.org7c537e22008-10-16 08:43:32 +00002220 // Declare the property by setting it to the initial value if provided,
2221 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
2222 // constant declarations).
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002223 ASSERT(!JSReceiver::HasLocalProperty(object, name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002224 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002225 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002226 // Declaring a const context slot is a conflicting declaration if
2227 // there is a callback with that name in a prototype. It is
2228 // allowed to introduce const variables in
2229 // JSContextExtensionObjects. They are treated specially in
2230 // SetProperty and no setters are invoked for those since they are
2231 // not real JSObjects.
2232 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002233 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002234 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002235 object->Lookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002236 if (lookup.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002237 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002238 }
2239 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002240 if (object->IsJSGlobalObject()) {
2241 // Define own property on the global object.
2242 RETURN_IF_EMPTY_HANDLE(isolate,
2243 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
2244 } else {
2245 RETURN_IF_EMPTY_HANDLE(isolate,
2246 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
2247 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002248 }
2249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002250 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251}
2252
2253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002254RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002255 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002256 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002257 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002258 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259
2260 // Determine if we need to assign to the variable if it already
2261 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002262 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
2263 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002265 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002266 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002267 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
2268 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
2269 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270
2271 // According to ECMA-262, section 12.2, page 62, the property must
2272 // not be deletable.
2273 PropertyAttributes attributes = DONT_DELETE;
2274
2275 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002276 // there, there is a property with this name in the prototype chain.
2277 // We follow Safari and Firefox behavior and only set the property
2278 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002279 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002280 // Note that objects can have hidden prototypes, so we need to traverse
2281 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002282 LookupResult lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002283 isolate->context()->global_object()->LocalLookup(*name, &lookup, true);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002284 if (lookup.IsInterceptor()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002285 PropertyAttributes intercepted =
2286 lookup.holder()->GetPropertyAttribute(*name);
2287 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
2288 // Found an interceptor that's not read only.
2289 if (assign) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002290 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2291 Handle<Object> result = JSObject::SetPropertyForResult(
2292 handle(lookup.holder()), &lookup, name, value, attributes,
2293 strict_mode_flag);
2294 RETURN_IF_EMPTY_HANDLE(isolate, result);
2295 return *result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002296 } else {
2297 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002298 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002300 }
2301
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002302 if (assign) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002303 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
2304 Handle<GlobalObject> global(isolate->context()->global_object());
2305 Handle<Object> result = JSReceiver::SetProperty(
2306 global, name, value, attributes, strict_mode_flag);
2307 RETURN_IF_EMPTY_HANDLE(isolate, result);
2308 return *result;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002309 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002311}
2312
2313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002315 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002316 // All constants are declared with an initial value. The name
2317 // of the constant is the first argument and the initial value
2318 // is the second.
2319 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002320 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002321 Handle<Object> value = args.at<Object>(1);
2322
2323 // Get the current global object from top.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002324 GlobalObject* global = isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002325
2326 // According to ECMA-262, section 12.2, page 62, the property must
2327 // not be deletable. Since it's a const, it must be READ_ONLY too.
2328 PropertyAttributes attributes =
2329 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
2330
2331 // Lookup the property locally in the global object. If it isn't
2332 // there, we add the property and take special precautions to always
2333 // add it as a local property even in case of callbacks in the
2334 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002335 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002336 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002337 global->LocalLookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002338 if (!lookup.IsFound()) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002339 HandleScope handle_scope(isolate);
2340 Handle<GlobalObject> global(isolate->context()->global_object());
2341 RETURN_IF_EMPTY_HANDLE(
2342 isolate,
2343 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
2344 attributes));
2345 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 }
2347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002349 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002350 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002351 HandleScope handle_scope(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002352 Handle<GlobalObject> global(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002353
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002354 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002355 // property through an interceptor and only do it if it's
2356 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002357 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002358 RETURN_IF_EMPTY_HANDLE(
2359 isolate,
2360 JSReceiver::SetProperty(global, name, value, attributes,
2361 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002362 return *value;
2363 }
2364
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002365 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002366 // constant. For now, we determine this by checking if the
2367 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368 // Strict mode handling not needed (const is disallowed in strict mode).
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002369 if (lookup.IsField()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370 FixedArray* properties = global->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002371 int index = lookup.GetFieldIndex().field_index();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002373 properties->set(index, *value);
2374 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002375 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
2377 !lookup.IsReadOnly()) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002378 HandleScope scope(isolate);
2379 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002380 }
2381 } else {
2382 // Ignore re-initialization of constants that have already been
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002383 // assigned a constant value.
2384 ASSERT(lookup.IsReadOnly() && lookup.IsConstant());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385 }
2386
2387 // Use the set value as the result of the operation.
2388 return *value;
2389}
2390
2391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002392RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002393 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002394 ASSERT(args.length() == 3);
2395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002396 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002397 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002398
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002399 // Initializations are always done in a function or native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002400 RUNTIME_ASSERT(args[1]->IsContext());
2401 Handle<Context> context(Context::cast(args[1])->declaration_context());
2402
2403 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002404
2405 int index;
2406 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002407 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002408 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002409 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002410 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002412 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002413 ASSERT(holder->IsContext());
2414 // Property was found in a context. Perform the assignment if we
2415 // found some non-constant or an uninitialized constant.
2416 Handle<Context> context = Handle<Context>::cast(holder);
2417 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
2418 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002419 }
2420 return *value;
2421 }
2422
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002423 // The property could not be found, we introduce it as a property of the
2424 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002425 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002426 Handle<JSObject> global = Handle<JSObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002427 isolate->context()->global_object());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002428 // Strict mode not needed (const disallowed in strict mode).
2429 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002430 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002431 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002432 return *value;
2433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002434
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002435 // The property was present in some function's context extension object,
2436 // as a property on the subject of a with, or as a property of the global
2437 // object.
2438 //
2439 // In most situations, eval-introduced consts should still be present in
2440 // the context extension object. However, because declaration and
2441 // initialization are separate, the property might have been deleted
2442 // before we reach the initialization point.
2443 //
2444 // Example:
2445 //
2446 // function f() { eval("delete x; const x;"); }
2447 //
2448 // In that case, the initialization behaves like a normal assignment.
2449 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002451 if (*object == context->extension()) {
2452 // This is the property that was introduced by the const declaration.
2453 // Set it if it hasn't been set before. NOTE: We cannot use
2454 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002455 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002456 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002457 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002458 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
2459
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002460 if (lookup.IsField()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002461 FixedArray* properties = object->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002462 int index = lookup.GetFieldIndex().field_index();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002463 if (properties->get(index)->IsTheHole()) {
2464 properties->set(index, *value);
2465 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002466 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002467 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002468 JSObject::SetNormalizedProperty(object, &lookup, value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002469 }
2470 } else {
2471 // We should not reach here. Any real, named property should be
2472 // either a field or a dictionary slot.
2473 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002474 }
2475 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002476 // The property was found on some other object. Set it if it is not a
2477 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002478 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002479 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002480 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002481 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002482 JSReceiver::SetProperty(object, name, value, attributes,
2483 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002485 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002487 return *value;
2488}
2489
2490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002491RUNTIME_FUNCTION(MaybeObject*,
2492 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002493 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002494 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002495 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002496 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002497 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002498 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002499 }
2500 return *object;
2501}
2502
2503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002504RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002505 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002506 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002507 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2508 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002509 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002510 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002511 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002512 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002513 RUNTIME_ASSERT(index >= 0);
2514 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002515 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002516 Handle<Object> result = RegExpImpl::Exec(regexp,
2517 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002518 index,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002519 last_match_info);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002520 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002521 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002522}
2523
2524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002525RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002526 SealHandleScope shs(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002527 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002528 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002529 if (elements_count < 0 ||
2530 elements_count > FixedArray::kMaxLength ||
2531 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002533 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002534 Object* new_object;
2535 { MaybeObject* maybe_new_object =
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002536 isolate->heap()->AllocateFixedArray(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002537 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2538 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002539 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002540 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
2541 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002542 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
2543 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002544 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002545 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002546 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002547 reinterpret_cast<HeapObject*>(new_object)->
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002548 set_map(isolate->native_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002549 }
2550 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002551 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00002552 array->set_elements(elements);
2553 array->set_length(Smi::FromInt(elements_count));
2554 // Write in-object properties after the length of the array.
2555 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
2556 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
2557 return array;
2558}
2559
2560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002561RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002562 HandleScope scope(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002563 DisallowHeapAllocation no_allocation;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002564 ASSERT(args.length() == 5);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002565 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
2566 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00002567 // If source is the empty string we set it to "(?:)" instead as
2568 // suggested by ECMA-262, 5th, section 15.10.4.1.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002569 if (source->length() == 0) source = isolate->factory()->query_colon_string();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002570
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002571 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
2572 if (!global->IsTrue()) global = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002573
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002574 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
2575 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002576
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002577 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
2578 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002579
2580 Map* map = regexp->map();
2581 Object* constructor = map->constructor();
2582 if (constructor->IsJSFunction() &&
2583 JSFunction::cast(constructor)->initial_map() == map) {
2584 // If we still have the original map, set in-object properties directly.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002585 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
erikcorry0ad885c2011-11-21 13:51:57 +00002586 // Both true and false are immovable immortal objects so no need for write
2587 // barrier.
2588 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002589 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
erikcorry0ad885c2011-11-21 13:51:57 +00002590 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002591 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
erikcorry0ad885c2011-11-21 13:51:57 +00002592 regexp->InObjectPropertyAtPut(
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002593 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00002594 regexp->InObjectPropertyAtPut(
2595 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002596 return *regexp;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002597 }
2598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002599 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002600 PropertyAttributes final =
2601 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
2602 PropertyAttributes writable =
2603 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002604 Handle<Object> zero(Smi::FromInt(0), isolate);
2605 Factory* factory = isolate->factory();
2606 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2607 regexp, factory->source_string(), source, final));
2608 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2609 regexp, factory->global_string(), global, final));
2610 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2611 regexp, factory->ignore_case_string(), ignoreCase, final));
2612 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2613 regexp, factory->multiline_string(), multiline, final));
2614 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
2615 regexp, factory->last_index_string(), zero, writable));
2616 return *regexp;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002617}
2618
2619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002620RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002621 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002622 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002623 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002624 // This is necessary to enable fast checks for absence of elements
2625 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002626 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002627 return Smi::FromInt(0);
2628}
2629
2630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002631static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
2632 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002633 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002634 Builtins::Name builtin_name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002635 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002636 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
2637 Handle<JSFunction> optimized =
2638 isolate->factory()->NewFunction(key,
2639 JS_OBJECT_TYPE,
2640 JSObject::kHeaderSize,
2641 code,
2642 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002643 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002644 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002645 return optimized;
2646}
2647
2648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002649RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002650 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002651 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002652 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002653
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002654 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
2655 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
2656 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
2657 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
2658 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
2659 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
2660 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00002661
2662 return *holder;
2663}
2664
2665
machenbach@chromium.org9f18d912013-11-28 13:42:41 +00002666RUNTIME_FUNCTION(MaybeObject*, Runtime_IsCallable) {
2667 SealHandleScope shs(isolate);
2668 ASSERT(args.length() == 1);
2669 CONVERT_ARG_CHECKED(Object, obj, 0);
2670 return isolate->heap()->ToBoolean(obj->IsCallable());
2671}
2672
2673
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002674RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002675 SealHandleScope shs(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002676 ASSERT(args.length() == 1);
2677 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
2678 if (!callable->IsJSFunction()) {
2679 HandleScope scope(isolate);
2680 bool threw = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002681 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2682 isolate, Handle<JSReceiver>(callable), &threw);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002683 if (threw) return Failure::Exception();
2684 callable = JSFunction::cast(*delegate);
2685 }
2686 JSFunction* function = JSFunction::cast(callable);
2687 SharedFunctionInfo* shared = function->shared();
2688 return isolate->heap()->ToBoolean(shared->is_classic_mode());
2689}
2690
2691
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002693 SealHandleScope shs(isolate);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002694 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002695 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002696
2697 if (!callable->IsJSFunction()) {
2698 HandleScope scope(isolate);
2699 bool threw = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002700 Handle<Object> delegate = Execution::TryGetFunctionDelegate(
2701 isolate, Handle<JSReceiver>(callable), &threw);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002702 if (threw) return Failure::Exception();
2703 callable = JSFunction::cast(*delegate);
2704 }
2705 JSFunction* function = JSFunction::cast(callable);
2706
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002707 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002708 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00002709 return isolate->heap()->undefined_value();
2710 }
2711 // Returns undefined for strict or native functions, or
2712 // the associated global receiver for "normal" functions.
2713
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002714 Context* native_context =
2715 function->context()->global_object()->native_context();
2716 return native_context->global_object()->global_receiver();
ager@chromium.org357bf652010-04-12 11:30:10 +00002717}
2718
2719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002720RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002721 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002722 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002723 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002724 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725 Handle<String> pattern = args.at<String>(2);
2726 Handle<String> flags = args.at<String>(3);
2727
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002728 // Get the RegExp function from the context in the literals array.
2729 // This is the RegExp function from the context in which the
2730 // function was created. We do not use the RegExp function from the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002731 // current native context because this might be the RegExp function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002732 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002733 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00002734 Handle<JSFunction>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002735 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002736 // Compute the regular expression literal.
2737 bool has_pending_exception;
2738 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002739 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
2740 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002742 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 return Failure::Exception();
2744 }
2745 literals->set(index, *regexp);
2746 return *regexp;
2747}
2748
2749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002750RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002751 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 ASSERT(args.length() == 1);
2753
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002754 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755 return f->shared()->name();
2756}
2757
2758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002759RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002760 SealHandleScope shs(isolate);
ager@chromium.org236ad962008-09-25 09:45:57 +00002761 ASSERT(args.length() == 2);
2762
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002763 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2764 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00002765 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002766 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00002767}
2768
2769
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002770RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002771 SealHandleScope shs(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002772 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002773 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002774 return isolate->heap()->ToBoolean(
2775 f->shared()->name_should_print_as_anonymous());
2776}
2777
2778
2779RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002780 SealHandleScope shs(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002781 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002782 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002783 f->shared()->set_name_should_print_as_anonymous(true);
2784 return isolate->heap()->undefined_value();
2785}
2786
2787
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002788RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002789 SealHandleScope shs(isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002790 ASSERT(args.length() == 1);
2791 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2792 return isolate->heap()->ToBoolean(f->shared()->is_generator());
2793}
2794
2795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002796RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002797 SealHandleScope shs(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002798 ASSERT(args.length() == 1);
2799
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002800 CONVERT_ARG_CHECKED(JSFunction, f, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002801 f->RemovePrototype();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002803 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002804}
2805
2806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002807RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809 ASSERT(args.length() == 1);
2810
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002811 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002812 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2813 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814
2815 return *GetScriptWrapper(Handle<Script>::cast(script));
2816}
2817
2818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002819RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002820 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821 ASSERT(args.length() == 1);
2822
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002823 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002824 Handle<SharedFunctionInfo> shared(f->shared());
2825 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002826}
2827
2828
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002829RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002830 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002831 ASSERT(args.length() == 1);
2832
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002833 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002834 int pos = fun->shared()->start_position();
2835 return Smi::FromInt(pos);
2836}
2837
2838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002839RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002840 SealHandleScope shs(isolate);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002841 ASSERT(args.length() == 2);
2842
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002843 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002844 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2845
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002846 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2847
2848 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002849 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002850}
2851
2852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002853RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002854 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855 ASSERT(args.length() == 2);
2856
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002857 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2858 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002861}
2862
2863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002864RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002865 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866 ASSERT(args.length() == 2);
2867
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002868 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2869 CONVERT_SMI_ARG_CHECKED(length, 1);
2870 fun->shared()->set_length(length);
2871 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872}
2873
2874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002875RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002876 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877 ASSERT(args.length() == 2);
2878
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002879 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
2880 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002881 ASSERT(fun->should_have_prototype());
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00002882 Accessors::FunctionSetPrototype(fun, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883 return args[0]; // return TOS
2884}
2885
2886
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002888 SealHandleScope shs(isolate);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002889 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002890 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002891
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002892 String* name = isolate->heap()->prototype_string();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002893
2894 if (function->HasFastProperties()) {
2895 // Construct a new field descriptor with updated attributes.
2896 DescriptorArray* instance_desc = function->map()->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002897
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002898 int index = instance_desc->SearchWithCache(name, function->map());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002899 ASSERT(index != DescriptorArray::kNotFound);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002900 PropertyDetails details = instance_desc->GetDetails(index);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002901
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002902 CallbacksDescriptor new_desc(name,
2903 instance_desc->GetValue(index),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002904 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002905
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002906 // Create a new map featuring the new field descriptors array.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002907 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002908 MaybeObject* maybe_map =
2909 function->map()->CopyReplaceDescriptor(
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002910 instance_desc, &new_desc, index, OMIT_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002911 if (!maybe_map->To(&new_map)) return maybe_map;
2912
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002913 function->set_map(new_map);
2914 } else { // Dictionary properties.
2915 // Directly manipulate the property details.
2916 int entry = function->property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002917 ASSERT(entry != NameDictionary::kNotFound);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002918 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2919 PropertyDetails new_details(
2920 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2921 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002922 details.dictionary_index());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002923 function->property_dictionary()->DetailsAtPut(entry, new_details);
2924 }
2925 return function;
2926}
2927
2928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002929RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002930 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002931 ASSERT(args.length() == 1);
2932
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002933 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002934 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002935}
2936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002939 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002940 ASSERT(args.length() == 1);
2941
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002942 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002943 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002944}
2945
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002947RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002948 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002949 ASSERT(args.length() == 2);
2950
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002951 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002952 Handle<Object> code = args.at<Object>(1);
2953
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002954 if (code->IsNull()) return *target;
2955 RUNTIME_ASSERT(code->IsJSFunction());
2956 Handle<JSFunction> source = Handle<JSFunction>::cast(code);
2957 Handle<SharedFunctionInfo> target_shared(target->shared());
2958 Handle<SharedFunctionInfo> source_shared(source->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959
yangguo@chromium.org49546742013-12-23 16:17:49 +00002960 if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002961 return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002962 }
2963
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002964 // Mark both, the source and the target, as un-flushable because the
2965 // shared unoptimized code makes them impossible to enqueue in a list.
2966 ASSERT(target_shared->code()->gc_metadata() == NULL);
2967 ASSERT(source_shared->code()->gc_metadata() == NULL);
2968 target_shared->set_dont_flush(true);
2969 source_shared->set_dont_flush(true);
2970
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002971 // Set the code, scope info, formal parameter count, and the length
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002972 // of the target shared function info.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002973 target_shared->ReplaceCode(source_shared->code());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002974 target_shared->set_scope_info(source_shared->scope_info());
2975 target_shared->set_length(source_shared->length());
2976 target_shared->set_formal_parameter_count(
2977 source_shared->formal_parameter_count());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002978 target_shared->set_script(source_shared->script());
2979 target_shared->set_start_position_and_type(
2980 source_shared->start_position_and_type());
2981 target_shared->set_end_position(source_shared->end_position());
2982 bool was_native = target_shared->native();
2983 target_shared->set_compiler_hints(source_shared->compiler_hints());
2984 target_shared->set_native(was_native);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002985
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002986 // Set the code of the target function.
2987 target->ReplaceCode(source_shared->code());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002988 ASSERT(target->next_function_link()->IsUndefined());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002989
2990 // Make sure we get a fresh copy of the literal vector to avoid cross
2991 // context contamination.
2992 Handle<Context> context(source->context());
2993 int number_of_literals = source->NumberOfLiterals();
2994 Handle<FixedArray> literals =
2995 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
2996 if (number_of_literals > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002997 literals->set(JSFunction::kLiteralNativeContextIndex,
2998 context->native_context());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 target->set_context(*context);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003001 target->set_literals(*literals);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003002
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003003 if (isolate->logger()->is_logging_code_events() ||
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003004 isolate->cpu_profiler()->is_profiling()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003005 isolate->logger()->LogExistingFunction(
3006 source_shared, Handle<Code>(source_shared->code()));
3007 }
3008
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009 return *target;
3010}
3011
3012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003013RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003015 ASSERT(args.length() == 2);
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00003016 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003017 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003018 RUNTIME_ASSERT(num >= 0);
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00003019 // If objects constructed from this function exist then changing
3020 // 'estimated_nof_properties' is dangerous since the previous value might
3021 // have been compiled into the fast construct stub. Moreover, the inobject
3022 // slack tracking logic might have adjusted the previous value, so even
3023 // passing the same value is risky.
3024 if (!func->shared()->live_objects_may_exist()) {
3025 func->shared()->set_expected_nof_properties(num);
3026 if (func->has_initial_map()) {
3027 Handle<Map> new_initial_map =
3028 func->GetIsolate()->factory()->CopyMap(
3029 Handle<Map>(func->initial_map()));
3030 new_initial_map->set_unused_property_fields(num);
3031 func->set_initial_map(*new_initial_map);
3032 }
3033 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003035}
3036
3037
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003038RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003039 HandleScope scope(isolate);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003040 ASSERT(args.length() == 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003041
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003042 JavaScriptFrameIterator it(isolate);
3043 JavaScriptFrame* frame = it.frame();
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003044 Handle<JSFunction> function(frame->function());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003045 RUNTIME_ASSERT(function->shared()->is_generator());
3046
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003047 Handle<JSGeneratorObject> generator;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003048 if (frame->IsConstructor()) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003049 generator = handle(JSGeneratorObject::cast(frame->receiver()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003050 } else {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003051 generator = isolate->factory()->NewJSGeneratorObject(function);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003052 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003053 generator->set_function(*function);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003054 generator->set_context(Context::cast(frame->context()));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003055 generator->set_receiver(frame->receiver());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003056 generator->set_continuation(0);
3057 generator->set_operand_stack(isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003058 generator->set_stack_handler_index(-1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003059
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003060 return *generator;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003061}
3062
3063
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003064RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003065 SealHandleScope shs(isolate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003066 ASSERT(args.length() == 1);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003067 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003068
3069 JavaScriptFrameIterator stack_iterator(isolate);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003070 JavaScriptFrame* frame = stack_iterator.frame();
danno@chromium.org169691d2013-07-15 08:01:13 +00003071 RUNTIME_ASSERT(frame->function()->shared()->is_generator());
3072 ASSERT_EQ(frame->function(), generator_object->function());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003073
3074 // The caller should have saved the context and continuation already.
3075 ASSERT_EQ(generator_object->context(), Context::cast(frame->context()));
3076 ASSERT_LT(0, generator_object->continuation());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003077
danno@chromium.orgf005df62013-04-30 16:36:45 +00003078 // We expect there to be at least two values on the operand stack: the return
3079 // value of the yield expression, and the argument to this runtime call.
3080 // Neither of those should be saved.
3081 int operands_count = frame->ComputeOperandsCount();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003082 ASSERT_GE(operands_count, 2);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003083 operands_count -= 2;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003084
danno@chromium.orgf005df62013-04-30 16:36:45 +00003085 if (operands_count == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003086 // Although it's semantically harmless to call this function with an
3087 // operands_count of zero, it is also unnecessary.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003088 ASSERT_EQ(generator_object->operand_stack(),
3089 isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003090 ASSERT_EQ(generator_object->stack_handler_index(), -1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003091 // If there are no operands on the stack, there shouldn't be a handler
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003092 // active either.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003093 ASSERT(!frame->HasHandler());
3094 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003095 int stack_handler_index = -1;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003096 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003097 FixedArray* operand_stack;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003098 if (!alloc->To(&operand_stack)) return alloc;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003099 frame->SaveOperandStack(operand_stack, &stack_handler_index);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003100 generator_object->set_operand_stack(operand_stack);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003101 generator_object->set_stack_handler_index(stack_handler_index);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003102 }
3103
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003104 return isolate->heap()->undefined_value();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003105}
3106
3107
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003108// Note that this function is the slow path for resuming generators. It is only
3109// called if the suspended activation had operands on the stack, stack handlers
3110// needing rewinding, or if the resume should throw an exception. The fast path
3111// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003112// inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
3113// called in any case, as it needs to reconstruct the stack frame and make space
3114// for arguments and operands.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003115RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003116 SealHandleScope shs(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003117 ASSERT(args.length() == 3);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003118 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
3119 CONVERT_ARG_CHECKED(Object, value, 1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003120 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
3121 JavaScriptFrameIterator stack_iterator(isolate);
danno@chromium.orgf005df62013-04-30 16:36:45 +00003122 JavaScriptFrame* frame = stack_iterator.frame();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003123
3124 ASSERT_EQ(frame->function(), generator_object->function());
danno@chromium.org59400602013-08-13 17:09:37 +00003125 ASSERT(frame->function()->is_compiled());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003126
3127 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0);
3128 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0);
3129
3130 Address pc = generator_object->function()->code()->instruction_start();
3131 int offset = generator_object->continuation();
3132 ASSERT(offset > 0);
3133 frame->set_pc(pc + offset);
3134 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
3135
danno@chromium.orgf005df62013-04-30 16:36:45 +00003136 FixedArray* operand_stack = generator_object->operand_stack();
3137 int operands_count = operand_stack->length();
3138 if (operands_count != 0) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003139 frame->RestoreOperandStack(operand_stack,
3140 generator_object->stack_handler_index());
danno@chromium.orgf005df62013-04-30 16:36:45 +00003141 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003142 generator_object->set_stack_handler_index(-1);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003143 }
3144
3145 JSGeneratorObject::ResumeMode resume_mode =
3146 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
3147 switch (resume_mode) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00003148 case JSGeneratorObject::NEXT:
danno@chromium.orgf005df62013-04-30 16:36:45 +00003149 return value;
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003150 case JSGeneratorObject::THROW:
danno@chromium.orgf005df62013-04-30 16:36:45 +00003151 return isolate->Throw(value);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003152 }
3153
3154 UNREACHABLE();
3155 return isolate->ThrowIllegalOperation();
3156}
3157
3158
3159RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) {
3160 HandleScope scope(isolate);
3161 ASSERT(args.length() == 1);
3162 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
3163 int continuation = generator->continuation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003164 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ?
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003165 "generator_finished" : "generator_running";
3166 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0);
3167 Handle<Object> error = isolate->factory()->NewError(message, argv);
3168 return isolate->Throw(*error);
3169}
3170
3171
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003172RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003173 HandleScope scope(isolate);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003174 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003175 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
3176 Handle<Object> result = JSObject::Freeze(object);
3177 RETURN_IF_EMPTY_HANDLE(isolate, result);
3178 return *result;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003179}
3180
3181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
3183 Object* char_code) {
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00003184 if (char_code->IsNumber()) {
3185 return isolate->heap()->LookupSingleCharacterStringFromCode(
3186 NumberToUint32(char_code) & 0xffff);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003188 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003189}
3190
3191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003192RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003193 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003194 ASSERT(args.length() == 2);
3195
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003196 CONVERT_ARG_CHECKED(String, subject, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003197 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003198
3199 // Flatten the string. If someone wants to get a char at an index
3200 // in a cons string, it is likely that more indices will be
3201 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003202 Object* flat;
3203 { MaybeObject* maybe_flat = subject->TryFlatten();
3204 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
3205 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003206 subject = String::cast(flat);
3207
3208 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003209 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003210 }
3211
3212 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003213}
3214
3215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003216RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003217 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003218 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003220}
3221
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223class FixedArrayBuilder {
3224 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003225 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
3226 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003227 length_(0),
3228 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003229 // Require a non-zero initial size. Ensures that doubling the size to
3230 // extend the array will work.
3231 ASSERT(initial_capacity > 0);
3232 }
3233
3234 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
3235 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003236 length_(0),
3237 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003238 // Require a non-zero initial size. Ensures that doubling the size to
3239 // extend the array will work.
3240 ASSERT(backing_store->length() > 0);
3241 }
3242
3243 bool HasCapacity(int elements) {
3244 int length = array_->length();
3245 int required_length = length_ + elements;
3246 return (length >= required_length);
3247 }
3248
3249 void EnsureCapacity(int elements) {
3250 int length = array_->length();
3251 int required_length = length_ + elements;
3252 if (length < required_length) {
3253 int new_length = length;
3254 do {
3255 new_length *= 2;
3256 } while (new_length < required_length);
3257 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003258 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 array_->CopyTo(0, *extended_array, 0, length_);
3260 array_ = extended_array;
3261 }
3262 }
3263
3264 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003265 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003266 ASSERT(length_ < capacity());
3267 array_->set(length_, value);
3268 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003269 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003270 }
3271
3272 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003273 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 ASSERT(length_ < capacity());
3275 array_->set(length_, value);
3276 length_++;
3277 }
3278
3279 Handle<FixedArray> array() {
3280 return array_;
3281 }
3282
3283 int length() {
3284 return length_;
3285 }
3286
3287 int capacity() {
3288 return array_->length();
3289 }
3290
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003292 Factory* factory = target_array->GetIsolate()->factory();
3293 factory->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003294 target_array->set_length(Smi::FromInt(length_));
3295 return target_array;
3296 }
3297
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003298
lrn@chromium.org25156de2010-04-06 13:10:27 +00003299 private:
3300 Handle<FixedArray> array_;
3301 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003302 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003303};
3304
3305
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003306// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307const int kStringBuilderConcatHelperLengthBits = 11;
3308const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003309
3310template <typename schar>
3311static inline void StringBuilderConcatHelper(String*,
3312 schar*,
3313 FixedArray*,
3314 int);
3315
lrn@chromium.org25156de2010-04-06 13:10:27 +00003316typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
3317 StringBuilderSubstringLength;
3318typedef BitField<int,
3319 kStringBuilderConcatHelperLengthBits,
3320 kStringBuilderConcatHelperPositionBits>
3321 StringBuilderSubstringPosition;
3322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003323
3324class ReplacementStringBuilder {
3325 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003326 ReplacementStringBuilder(Heap* heap,
3327 Handle<String> subject,
3328 int estimated_part_count)
3329 : heap_(heap),
3330 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00003331 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003332 character_count_(0),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003333 is_ascii_(subject->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003334 // Require a non-zero initial size. Ensures that doubling the size to
3335 // extend the array will work.
3336 ASSERT(estimated_part_count > 0);
3337 }
3338
lrn@chromium.org25156de2010-04-06 13:10:27 +00003339 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
3340 int from,
3341 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003342 ASSERT(from >= 0);
3343 int length = to - from;
3344 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003345 if (StringBuilderSubstringLength::is_valid(length) &&
3346 StringBuilderSubstringPosition::is_valid(from)) {
3347 int encoded_slice = StringBuilderSubstringLength::encode(length) |
3348 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003349 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003350 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003351 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00003352 builder->Add(Smi::FromInt(-length));
3353 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003354 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003355 }
3356
3357
3358 void EnsureCapacity(int elements) {
3359 array_builder_.EnsureCapacity(elements);
3360 }
3361
3362
3363 void AddSubjectSlice(int from, int to) {
3364 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003365 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003366 }
3367
3368
3369 void AddString(Handle<String> string) {
3370 int length = string->length();
3371 ASSERT(length > 0);
3372 AddElement(*string);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003373 if (!string->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003374 is_ascii_ = false;
3375 }
3376 IncrementCharacterCount(length);
3377 }
3378
3379
3380 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003381 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003383 }
3384
3385 Handle<String> joined_string;
3386 if (is_ascii_) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003387 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003388 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003389 uint8_t* char_buffer = seq->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003390 StringBuilderConcatHelper(*subject_,
3391 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003392 *array_builder_.array(),
3393 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003394 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003395 } else {
3396 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00003397 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003398 DisallowHeapAllocation no_gc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003399 uc16* char_buffer = seq->GetChars();
3400 StringBuilderConcatHelper(*subject_,
3401 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003402 *array_builder_.array(),
3403 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003404 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003405 }
3406 return joined_string;
3407 }
3408
3409
3410 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003411 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 V8::FatalProcessOutOfMemory("String.replace result too large.");
3413 }
3414 character_count_ += by;
3415 }
3416
lrn@chromium.org25156de2010-04-06 13:10:27 +00003417 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003418 Handle<SeqOneByteString> NewRawOneByteString(int length) {
3419 return heap_->isolate()->factory()->NewRawOneByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003420 }
3421
3422
ager@chromium.org04921a82011-06-27 13:21:41 +00003423 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
3424 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003425 }
3426
3427
3428 void AddElement(Object* element) {
3429 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003430 ASSERT(array_builder_.capacity() > array_builder_.length());
3431 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003432 }
3433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003435 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003436 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003437 int character_count_;
3438 bool is_ascii_;
3439};
3440
3441
3442class CompiledReplacement {
3443 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003444 explicit CompiledReplacement(Zone* zone)
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003445 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003446
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003447 // Return whether the replacement is simple.
3448 bool Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003449 int capture_count,
3450 int subject_length);
3451
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003452 // Use Apply only if Compile returned false.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003453 void Apply(ReplacementStringBuilder* builder,
3454 int match_from,
3455 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003456 int32_t* match);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003457
3458 // Number of distinct parts of the replacement pattern.
3459 int parts() {
3460 return parts_.length();
3461 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003462
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003463 Zone* zone() const { return zone_; }
3464
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003465 private:
3466 enum PartType {
3467 SUBJECT_PREFIX = 1,
3468 SUBJECT_SUFFIX,
3469 SUBJECT_CAPTURE,
3470 REPLACEMENT_SUBSTRING,
3471 REPLACEMENT_STRING,
3472
3473 NUMBER_OF_PART_TYPES
3474 };
3475
3476 struct ReplacementPart {
3477 static inline ReplacementPart SubjectMatch() {
3478 return ReplacementPart(SUBJECT_CAPTURE, 0);
3479 }
3480 static inline ReplacementPart SubjectCapture(int capture_index) {
3481 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
3482 }
3483 static inline ReplacementPart SubjectPrefix() {
3484 return ReplacementPart(SUBJECT_PREFIX, 0);
3485 }
3486 static inline ReplacementPart SubjectSuffix(int subject_length) {
3487 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
3488 }
3489 static inline ReplacementPart ReplacementString() {
3490 return ReplacementPart(REPLACEMENT_STRING, 0);
3491 }
3492 static inline ReplacementPart ReplacementSubString(int from, int to) {
3493 ASSERT(from >= 0);
3494 ASSERT(to > from);
3495 return ReplacementPart(-from, to);
3496 }
3497
3498 // If tag <= 0 then it is the negation of a start index of a substring of
3499 // the replacement pattern, otherwise it's a value from PartType.
3500 ReplacementPart(int tag, int data)
3501 : tag(tag), data(data) {
3502 // Must be non-positive or a PartType value.
3503 ASSERT(tag < NUMBER_OF_PART_TYPES);
3504 }
3505 // Either a value of PartType or a non-positive number that is
3506 // the negation of an index into the replacement string.
3507 int tag;
3508 // The data value's interpretation depends on the value of tag:
3509 // tag == SUBJECT_PREFIX ||
3510 // tag == SUBJECT_SUFFIX: data is unused.
3511 // tag == SUBJECT_CAPTURE: data is the number of the capture.
3512 // tag == REPLACEMENT_SUBSTRING ||
3513 // tag == REPLACEMENT_STRING: data is index into array of substrings
3514 // of the replacement string.
3515 // tag <= 0: Temporary representation of the substring of the replacement
3516 // string ranging over -tag .. data.
3517 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
3518 // substring objects.
3519 int data;
3520 };
3521
3522 template<typename Char>
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003523 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
3524 Vector<Char> characters,
3525 int capture_count,
3526 int subject_length,
3527 Zone* zone) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003528 int length = characters.length();
3529 int last = 0;
3530 for (int i = 0; i < length; i++) {
3531 Char c = characters[i];
3532 if (c == '$') {
3533 int next_index = i + 1;
3534 if (next_index == length) { // No next character!
3535 break;
3536 }
3537 Char c2 = characters[next_index];
3538 switch (c2) {
3539 case '$':
3540 if (i > last) {
3541 // There is a substring before. Include the first "$".
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003542 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
3543 zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003544 last = next_index + 1; // Continue after the second "$".
3545 } else {
3546 // Let the next substring start with the second "$".
3547 last = next_index;
3548 }
3549 i = next_index;
3550 break;
3551 case '`':
3552 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003553 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003554 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003555 parts->Add(ReplacementPart::SubjectPrefix(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003556 i = next_index;
3557 last = i + 1;
3558 break;
3559 case '\'':
3560 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003561 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003562 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003563 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003564 i = next_index;
3565 last = i + 1;
3566 break;
3567 case '&':
3568 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003569 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003570 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003571 parts->Add(ReplacementPart::SubjectMatch(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003572 i = next_index;
3573 last = i + 1;
3574 break;
3575 case '0':
3576 case '1':
3577 case '2':
3578 case '3':
3579 case '4':
3580 case '5':
3581 case '6':
3582 case '7':
3583 case '8':
3584 case '9': {
3585 int capture_ref = c2 - '0';
3586 if (capture_ref > capture_count) {
3587 i = next_index;
3588 continue;
3589 }
3590 int second_digit_index = next_index + 1;
3591 if (second_digit_index < length) {
3592 // Peek ahead to see if we have two digits.
3593 Char c3 = characters[second_digit_index];
3594 if ('0' <= c3 && c3 <= '9') { // Double digits.
3595 int double_digit_ref = capture_ref * 10 + c3 - '0';
3596 if (double_digit_ref <= capture_count) {
3597 next_index = second_digit_index;
3598 capture_ref = double_digit_ref;
3599 }
3600 }
3601 }
3602 if (capture_ref > 0) {
3603 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003604 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003605 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003606 ASSERT(capture_ref <= capture_count);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003607 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003608 last = next_index + 1;
3609 }
3610 i = next_index;
3611 break;
3612 }
3613 default:
3614 i = next_index;
3615 break;
3616 }
3617 }
3618 }
3619 if (length > last) {
3620 if (last == 0) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003621 // Replacement is simple. Do not use Apply to do the replacement.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003622 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003623 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003624 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003625 }
3626 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003627 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003628 }
3629
3630 ZoneList<ReplacementPart> parts_;
3631 ZoneList<Handle<String> > replacement_substrings_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003632 Zone* zone_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003633};
3634
3635
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003636bool CompiledReplacement::Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 int capture_count,
3638 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003639 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003640 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003641 String::FlatContent content = replacement->GetFlatContent();
3642 ASSERT(content.IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003643 bool simple = false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003644 if (content.IsAscii()) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003645 simple = ParseReplacementPattern(&parts_,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003646 content.ToOneByteVector(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003647 capture_count,
3648 subject_length,
3649 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003650 } else {
3651 ASSERT(content.IsTwoByte());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003652 simple = ParseReplacementPattern(&parts_,
3653 content.ToUC16Vector(),
3654 capture_count,
3655 subject_length,
3656 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003657 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003658 if (simple) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003659 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003660
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003661 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003662 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003663 int substring_index = 0;
3664 for (int i = 0, n = parts_.length(); i < n; i++) {
3665 int tag = parts_[i].tag;
3666 if (tag <= 0) { // A replacement string slice.
3667 int from = -tag;
3668 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 replacement_substrings_.Add(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003670 isolate->factory()->NewSubString(replacement, from, to), zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003671 parts_[i].tag = REPLACEMENT_SUBSTRING;
3672 parts_[i].data = substring_index;
3673 substring_index++;
3674 } else if (tag == REPLACEMENT_STRING) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003675 replacement_substrings_.Add(replacement, zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003676 parts_[i].data = substring_index;
3677 substring_index++;
3678 }
3679 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003680 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003681}
3682
3683
3684void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
3685 int match_from,
3686 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003687 int32_t* match) {
3688 ASSERT_LT(0, parts_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003689 for (int i = 0, n = parts_.length(); i < n; i++) {
3690 ReplacementPart part = parts_[i];
3691 switch (part.tag) {
3692 case SUBJECT_PREFIX:
3693 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
3694 break;
3695 case SUBJECT_SUFFIX: {
3696 int subject_length = part.data;
3697 if (match_to < subject_length) {
3698 builder->AddSubjectSlice(match_to, subject_length);
3699 }
3700 break;
3701 }
3702 case SUBJECT_CAPTURE: {
3703 int capture = part.data;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003704 int from = match[capture * 2];
3705 int to = match[capture * 2 + 1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003706 if (from >= 0 && to > from) {
3707 builder->AddSubjectSlice(from, to);
3708 }
3709 break;
3710 }
3711 case REPLACEMENT_SUBSTRING:
3712 case REPLACEMENT_STRING:
3713 builder->AddString(replacement_substrings_[part.data]);
3714 break;
3715 default:
3716 UNREACHABLE();
3717 }
3718 }
3719}
3720
3721
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003722void FindAsciiStringIndices(Vector<const uint8_t> subject,
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003723 char pattern,
3724 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003725 unsigned int limit,
3726 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003727 ASSERT(limit > 0);
3728 // Collect indices of pattern in subject using memchr.
3729 // Stop after finding at most limit values.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003730 const uint8_t* subject_start = subject.start();
3731 const uint8_t* subject_end = subject_start + subject.length();
3732 const uint8_t* pos = subject_start;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003733 while (limit > 0) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003734 pos = reinterpret_cast<const uint8_t*>(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003735 memchr(pos, pattern, subject_end - pos));
3736 if (pos == NULL) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003737 indices->Add(static_cast<int>(pos - subject_start), zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003738 pos++;
3739 limit--;
3740 }
3741}
3742
3743
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003744void FindTwoByteStringIndices(const Vector<const uc16> subject,
3745 uc16 pattern,
3746 ZoneList<int>* indices,
3747 unsigned int limit,
3748 Zone* zone) {
3749 ASSERT(limit > 0);
3750 const uc16* subject_start = subject.start();
3751 const uc16* subject_end = subject_start + subject.length();
3752 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
3753 if (*pos == pattern) {
3754 indices->Add(static_cast<int>(pos - subject_start), zone);
3755 limit--;
3756 }
3757 }
3758}
3759
3760
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003761template <typename SubjectChar, typename PatternChar>
3762void FindStringIndices(Isolate* isolate,
3763 Vector<const SubjectChar> subject,
3764 Vector<const PatternChar> pattern,
3765 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003766 unsigned int limit,
3767 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003768 ASSERT(limit > 0);
3769 // Collect indices of pattern in subject.
3770 // Stop after finding at most limit values.
3771 int pattern_length = pattern.length();
3772 int index = 0;
3773 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
3774 while (limit > 0) {
3775 index = search.Search(subject, index);
3776 if (index < 0) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003777 indices->Add(index, zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003778 index += pattern_length;
3779 limit--;
3780 }
3781}
3782
3783
3784void FindStringIndicesDispatch(Isolate* isolate,
3785 String* subject,
3786 String* pattern,
3787 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003788 unsigned int limit,
3789 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003790 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003791 DisallowHeapAllocation no_gc;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003792 String::FlatContent subject_content = subject->GetFlatContent();
3793 String::FlatContent pattern_content = pattern->GetFlatContent();
3794 ASSERT(subject_content.IsFlat());
3795 ASSERT(pattern_content.IsFlat());
3796 if (subject_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003797 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003798 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003799 Vector<const uint8_t> pattern_vector =
3800 pattern_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003801 if (pattern_vector.length() == 1) {
3802 FindAsciiStringIndices(subject_vector,
3803 pattern_vector[0],
3804 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003805 limit,
3806 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003807 } else {
3808 FindStringIndices(isolate,
3809 subject_vector,
3810 pattern_vector,
3811 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003812 limit,
3813 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003814 }
3815 } else {
3816 FindStringIndices(isolate,
3817 subject_vector,
3818 pattern_content.ToUC16Vector(),
3819 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003820 limit,
3821 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003822 }
3823 } else {
3824 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003825 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003826 Vector<const uint8_t> pattern_vector =
3827 pattern_content.ToOneByteVector();
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003828 if (pattern_vector.length() == 1) {
3829 FindTwoByteStringIndices(subject_vector,
3830 pattern_vector[0],
3831 indices,
3832 limit,
3833 zone);
3834 } else {
3835 FindStringIndices(isolate,
3836 subject_vector,
3837 pattern_vector,
3838 indices,
3839 limit,
3840 zone);
3841 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003842 } else {
mmassi@chromium.org49a44672012-12-04 13:52:03 +00003843 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
3844 if (pattern_vector.length() == 1) {
3845 FindTwoByteStringIndices(subject_vector,
3846 pattern_vector[0],
3847 indices,
3848 limit,
3849 zone);
3850 } else {
3851 FindStringIndices(isolate,
3852 subject_vector,
3853 pattern_vector,
3854 indices,
3855 limit,
3856 zone);
3857 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003858 }
3859 }
3860 }
3861}
3862
3863
3864template<typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003865MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003866 Isolate* isolate,
3867 Handle<String> subject,
3868 Handle<JSRegExp> pattern_regexp,
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003869 Handle<String> replacement,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003870 Handle<JSArray> last_match_info) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003871 ASSERT(subject->IsFlat());
3872 ASSERT(replacement->IsFlat());
3873
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003874 ZoneScope zone_scope(isolate->runtime_zone());
3875 ZoneList<int> indices(8, zone_scope.zone());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003876 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
3877 String* pattern =
3878 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
3879 int subject_len = subject->length();
3880 int pattern_len = pattern->length();
3881 int replacement_len = replacement->length();
3882
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003883 FindStringIndicesDispatch(
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003884 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003885
3886 int matches = indices.length();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003887 if (matches == 0) return *subject;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003888
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003889 // Detect integer overflow.
3890 int64_t result_len_64 =
3891 (static_cast<int64_t>(replacement_len) -
3892 static_cast<int64_t>(pattern_len)) *
3893 static_cast<int64_t>(matches) +
3894 static_cast<int64_t>(subject_len);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003895 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003896 int result_len = static_cast<int>(result_len_64);
3897
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003898 int subject_pos = 0;
3899 int result_pos = 0;
3900
3901 Handle<ResultSeqString> result;
3902 if (ResultSeqString::kHasAsciiEncoding) {
3903 result = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003904 isolate->factory()->NewRawOneByteString(result_len));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003905 } else {
3906 result = Handle<ResultSeqString>::cast(
3907 isolate->factory()->NewRawTwoByteString(result_len));
3908 }
3909
3910 for (int i = 0; i < matches; i++) {
3911 // Copy non-matched subject content.
3912 if (subject_pos < indices.at(i)) {
3913 String::WriteToFlat(*subject,
3914 result->GetChars() + result_pos,
3915 subject_pos,
3916 indices.at(i));
3917 result_pos += indices.at(i) - subject_pos;
3918 }
3919
3920 // Replace match.
3921 if (replacement_len > 0) {
3922 String::WriteToFlat(*replacement,
3923 result->GetChars() + result_pos,
3924 0,
3925 replacement_len);
3926 result_pos += replacement_len;
3927 }
3928
3929 subject_pos = indices.at(i) + pattern_len;
3930 }
3931 // Add remaining subject content at the end.
3932 if (subject_pos < subject_len) {
3933 String::WriteToFlat(*subject,
3934 result->GetChars() + result_pos,
3935 subject_pos,
3936 subject_len);
3937 }
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003938
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003939 int32_t match_indices[] = { indices.at(matches - 1),
3940 indices.at(matches - 1) + pattern_len };
3941 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003942
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003943 return *result;
3944}
3945
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003946
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003947MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003948 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003949 Handle<String> subject,
3950 Handle<JSRegExp> regexp,
3951 Handle<String> replacement,
3952 Handle<JSArray> last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003953 ASSERT(subject->IsFlat());
3954 ASSERT(replacement->IsFlat());
3955
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003956 int capture_count = regexp->CaptureCount();
3957 int subject_length = subject->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003958
3959 // CompiledReplacement uses zone allocation.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00003960 ZoneScope zone_scope(isolate->runtime_zone());
3961 CompiledReplacement compiled_replacement(zone_scope.zone());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003962 bool simple_replace = compiled_replacement.Compile(replacement,
3963 capture_count,
3964 subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003965
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003966 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003967 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003968 if (subject->HasOnlyOneByteChars() &&
3969 replacement->HasOnlyOneByteChars()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003970 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003971 isolate, subject, regexp, replacement, last_match_info);
3972 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003973 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003974 isolate, subject, regexp, replacement, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003975 }
3976 }
3977
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003978 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003979 if (global_cache.HasException()) return Failure::Exception();
3980
3981 int32_t* current_match = global_cache.FetchNext();
3982 if (current_match == NULL) {
3983 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003984 return *subject;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003985 }
3986
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003987 // Guessing the number of parts that the final result string is built
3988 // from. Global regexps can match any number of times, so we guess
3989 // conservatively.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003990 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991 ReplacementStringBuilder builder(isolate->heap(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003992 subject,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003994
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003995 // Number of parts added by compiled replacement plus preceeding
3996 // string and possibly suffix after last match. It is possible for
3997 // all components to use two elements when encoded as two smis.
3998 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003999
4000 int prev = 0;
4001
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004002 do {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004003 builder.EnsureCapacity(parts_added_per_loop);
4004
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004005 int start = current_match[0];
4006 int end = current_match[1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004007
4008 if (prev < start) {
4009 builder.AddSubjectSlice(prev, start);
4010 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004011
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004012 if (simple_replace) {
4013 builder.AddString(replacement);
4014 } else {
4015 compiled_replacement.Apply(&builder,
4016 start,
4017 end,
4018 current_match);
4019 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004020 prev = end;
4021
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004022 current_match = global_cache.FetchNext();
4023 } while (current_match != NULL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004024
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004025 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004026
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004027 if (prev < subject_length) {
4028 builder.EnsureCapacity(2);
4029 builder.AddSubjectSlice(prev, subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004030 }
4031
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004032 RegExpImpl::SetLastMatchInfo(last_match_info,
4033 subject,
4034 capture_count,
4035 global_cache.LastSuccessfulMatch());
4036
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004037 return *(builder.ToString());
4038}
4039
4040
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004041template <typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004042MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004043 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004044 Handle<String> subject,
4045 Handle<JSRegExp> regexp,
4046 Handle<JSArray> last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004047 ASSERT(subject->IsFlat());
4048
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004049 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004050 if (regexp->TypeTag() == JSRegExp::ATOM) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004051 Handle<String> empty_string = isolate->factory()->empty_string();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004052 if (subject->IsOneByteRepresentation()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004053 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
4054 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004055 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004056 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
4057 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004058 }
4059 }
4060
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004061 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004062 if (global_cache.HasException()) return Failure::Exception();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004063
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004064 int32_t* current_match = global_cache.FetchNext();
4065 if (current_match == NULL) {
4066 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004067 return *subject;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004068 }
4069
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004070 int start = current_match[0];
4071 int end = current_match[1];
4072 int capture_count = regexp->CaptureCount();
4073 int subject_length = subject->length();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004074
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004075 int new_length = subject_length - (end - start);
4076 if (new_length == 0) return isolate->heap()->empty_string();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004078 Handle<ResultSeqString> answer;
4079 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 answer = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004081 isolate->factory()->NewRawOneByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004082 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 answer = Handle<ResultSeqString>::cast(
4084 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004085 }
4086
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004087 int prev = 0;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004088 int position = 0;
4089
4090 do {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004091 start = current_match[0];
4092 end = current_match[1];
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004093 if (prev < start) {
4094 // Add substring subject[prev;start] to answer string.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004095 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004096 position += start - prev;
4097 }
4098 prev = end;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004099
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004100 current_match = global_cache.FetchNext();
4101 } while (current_match != NULL);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004102
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004103 if (global_cache.HasException()) return Failure::Exception();
4104
4105 RegExpImpl::SetLastMatchInfo(last_match_info,
4106 subject,
4107 capture_count,
4108 global_cache.LastSuccessfulMatch());
4109
4110 if (prev < subject_length) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004111 // Add substring subject[prev;length] to answer string.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004112 String::WriteToFlat(
4113 *subject, answer->GetChars() + position, prev, subject_length);
4114 position += subject_length - prev;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004115 }
4116
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004117 if (position == 0) return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004118
4119 // Shorten string and fill
4120 int string_size = ResultSeqString::SizeFor(position);
4121 int allocated_string_size = ResultSeqString::SizeFor(new_length);
4122 int delta = allocated_string_size - string_size;
4123
4124 answer->set_length(position);
4125 if (delta == 0) return *answer;
4126
4127 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004129 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004130 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004132
4133 return *answer;
4134}
4135
4136
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004137RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004138 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004139 ASSERT(args.length() == 4);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004140
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004141 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4142 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
4143 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4144 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004145
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004146 ASSERT(regexp->GetFlags().is_global());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004147
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004148 if (!subject->IsFlat()) subject = FlattenGetString(subject);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004150 if (replacement->length() == 0) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004151 if (subject->HasOnlyOneByteChars()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004152 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004153 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004154 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004155 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004156 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00004157 }
4158 }
4159
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004160 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
4161
4162 return StringReplaceGlobalRegExpWithString(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004163 isolate, subject, regexp, replacement, last_match_info);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004164}
4165
4166
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004167Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
4168 Handle<String> subject,
4169 Handle<String> search,
4170 Handle<String> replace,
4171 bool* found,
4172 int recursion_limit) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004173 if (recursion_limit == 0) return Handle<String>::null();
4174 if (subject->IsConsString()) {
4175 ConsString* cons = ConsString::cast(*subject);
4176 Handle<String> first = Handle<String>(cons->first());
4177 Handle<String> second = Handle<String>(cons->second());
4178 Handle<String> new_first =
4179 StringReplaceOneCharWithString(isolate,
4180 first,
4181 search,
4182 replace,
4183 found,
4184 recursion_limit - 1);
4185 if (*found) return isolate->factory()->NewConsString(new_first, second);
4186 if (new_first.is_null()) return new_first;
4187
4188 Handle<String> new_second =
4189 StringReplaceOneCharWithString(isolate,
4190 second,
4191 search,
4192 replace,
4193 found,
4194 recursion_limit - 1);
4195 if (*found) return isolate->factory()->NewConsString(first, new_second);
4196 if (new_second.is_null()) return new_second;
4197
4198 return subject;
4199 } else {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004200 int index = Runtime::StringMatch(isolate, subject, search, 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004201 if (index == -1) return subject;
4202 *found = true;
4203 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
4204 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
4205 Handle<String> second =
4206 isolate->factory()->NewSubString(subject, index + 1, subject->length());
4207 return isolate->factory()->NewConsString(cons1, second);
4208 }
4209}
4210
4211
4212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004213 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004214 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004215 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4216 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
4217 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004218
4219 // If the cons string tree is too deep, we simply abort the recursion and
4220 // retry with a flattened subject string.
4221 const int kRecursionLimit = 0x1000;
4222 bool found = false;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004223 Handle<String> result = StringReplaceOneCharWithString(isolate,
4224 subject,
4225 search,
4226 replace,
4227 &found,
4228 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004229 if (!result.is_null()) return *result;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004230 return *StringReplaceOneCharWithString(isolate,
4231 FlattenGetString(subject),
4232 search,
4233 replace,
4234 &found,
4235 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004236}
4237
4238
ager@chromium.org7c537e22008-10-16 08:43:32 +00004239// Perform string match of pattern on subject, starting at start index.
4240// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004241// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004242int Runtime::StringMatch(Isolate* isolate,
4243 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00004244 Handle<String> pat,
4245 int start_index) {
4246 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004247 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004248
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004249 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004250 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004252 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004253 if (start_index + pattern_length > subject_length) return -1;
4254
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004255 if (!sub->IsFlat()) FlattenString(sub);
4256 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00004257
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004258 DisallowHeapAllocation no_gc; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00004259 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004260 String::FlatContent seq_sub = sub->GetFlatContent();
4261 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00004262
ager@chromium.org7c537e22008-10-16 08:43:32 +00004263 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004264 if (seq_pat.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004265 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004266 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004267 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004268 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004269 pat_vector,
4270 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00004271 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004272 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004273 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004274 pat_vector,
4275 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00004276 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004277 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
4278 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004279 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004280 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004281 pat_vector,
4282 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004283 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004284 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004285 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004286 pat_vector,
4287 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004288}
4289
4290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004292 HandleScope scope(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004293 ASSERT(args.length() == 3);
4294
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004295 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4296 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004297
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004298 Object* index = args[2];
4299 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004300 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004301
ager@chromium.org870a0b62008-11-04 11:43:05 +00004302 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004303 int position =
4304 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004305 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306}
4307
4308
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004309template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004310static int StringMatchBackwards(Vector<const schar> subject,
4311 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004312 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004313 int pattern_length = pattern.length();
4314 ASSERT(pattern_length >= 1);
4315 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004316
4317 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004318 for (int i = 0; i < pattern_length; i++) {
4319 uc16 c = pattern[i];
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004320 if (c > String::kMaxOneByteCharCode) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004321 return -1;
4322 }
4323 }
4324 }
4325
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004326 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004327 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004328 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004329 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004330 while (j < pattern_length) {
4331 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004332 break;
4333 }
4334 j++;
4335 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004336 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004337 return i;
4338 }
4339 }
4340 return -1;
4341}
4342
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004344RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004345 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 ASSERT(args.length() == 3);
4347
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004348 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
4349 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004350
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004353 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004355 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004356 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004357
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004358 if (start_index + pat_length > sub_length) {
4359 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004361
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004362 if (pat_length == 0) {
4363 return Smi::FromInt(start_index);
4364 }
4365
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004366 if (!sub->IsFlat()) FlattenString(sub);
4367 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004368
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004369 int position = -1;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004370 DisallowHeapAllocation no_gc; // ensure vectors stay valid
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004371
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004372 String::FlatContent sub_content = sub->GetFlatContent();
4373 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004374
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004375 if (pat_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004376 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004377 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004378 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004379 pat_vector,
4380 start_index);
4381 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004382 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004383 pat_vector,
4384 start_index);
4385 }
4386 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004387 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
4388 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004389 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004390 pat_vector,
4391 start_index);
4392 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00004393 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00004394 pat_vector,
4395 start_index);
4396 }
4397 }
4398
4399 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400}
4401
4402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004403RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004404 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004405 ASSERT(args.length() == 2);
4406
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004407 CONVERT_ARG_CHECKED(String, str1, 0);
4408 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409
4410 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004411 int str1_length = str1->length();
4412 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413
4414 // Decide trivial cases without flattening.
4415 if (str1_length == 0) {
4416 if (str2_length == 0) return Smi::FromInt(0); // Equal.
4417 return Smi::FromInt(-str2_length);
4418 } else {
4419 if (str2_length == 0) return Smi::FromInt(str1_length);
4420 }
4421
4422 int end = str1_length < str2_length ? str1_length : str2_length;
4423
4424 // No need to flatten if we are going to find the answer on the first
4425 // character. At this point we know there is at least one character
4426 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004427 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004428 if (d != 0) return Smi::FromInt(d);
4429
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004430 str1->TryFlatten();
4431 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00004433 ConsStringIteratorOp* op1 =
4434 isolate->runtime_state()->string_locale_compare_it1();
4435 ConsStringIteratorOp* op2 =
4436 isolate->runtime_state()->string_locale_compare_it2();
4437 // TODO(dcarney) Can do array compares here more efficiently.
4438 StringCharacterStream stream1(str1, op1);
4439 StringCharacterStream stream2(str2, op2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440
4441 for (int i = 0; i < end; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00004442 uint16_t char1 = stream1.GetNext();
4443 uint16_t char2 = stream2.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 if (char1 != char2) return Smi::FromInt(char1 - char2);
4445 }
4446
4447 return Smi::FromInt(str1_length - str2_length);
4448}
4449
4450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004451RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00004452 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 ASSERT(args.length() == 3);
4454
yangguo@chromium.org49546742013-12-23 16:17:49 +00004455 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004456 int start, end;
4457 // We have a fast integer-only case here to avoid a conversion to double in
4458 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004459 if (args[1]->IsSmi() && args[2]->IsSmi()) {
4460 CONVERT_SMI_ARG_CHECKED(from_number, 1);
4461 CONVERT_SMI_ARG_CHECKED(to_number, 2);
4462 start = from_number;
4463 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004464 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004465 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
4466 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004467 start = FastD2IChecked(from_number);
4468 end = FastD2IChecked(to_number);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 RUNTIME_ASSERT(end >= start);
4471 RUNTIME_ASSERT(start >= 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +00004472 RUNTIME_ASSERT(end <= string->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004473 isolate->counters()->sub_string_runtime()->Increment();
yangguo@chromium.org49546742013-12-23 16:17:49 +00004474
4475 return *isolate->factory()->NewSubString(string, start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476}
4477
4478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004479RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004480 HandleScope handles(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00004481 ASSERT_EQ(3, args.length());
4482
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004483 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
4484 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
4485 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00004486
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004487 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4488 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.org41826e72009-03-30 13:30:57 +00004489
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004490 int capture_count = regexp->CaptureCount();
ager@chromium.org41826e72009-03-30 13:30:57 +00004491
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00004492 ZoneScope zone_scope(isolate->runtime_zone());
4493 ZoneList<int> offsets(8, zone_scope.zone());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004494
4495 while (true) {
4496 int32_t* match = global_cache.FetchNext();
4497 if (match == NULL) break;
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00004498 offsets.Add(match[0], zone_scope.zone()); // start
4499 offsets.Add(match[1], zone_scope.zone()); // end
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004500 }
4501
4502 if (global_cache.HasException()) return Failure::Exception();
4503
4504 if (offsets.length() == 0) {
4505 // Not a single match.
4506 return isolate->heap()->null_value();
4507 }
4508
4509 RegExpImpl::SetLastMatchInfo(regexp_info,
4510 subject,
4511 capture_count,
4512 global_cache.LastSuccessfulMatch());
4513
ager@chromium.org41826e72009-03-30 13:30:57 +00004514 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004516 Handle<String> substring =
4517 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
ager@chromium.org04921a82011-06-27 13:21:41 +00004518 elements->set(0, *substring);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004519 for (int i = 1; i < matches; i++) {
4520 HandleScope temp_scope(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00004521 int from = offsets.at(i * 2);
4522 int to = offsets.at(i * 2 + 1);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004523 Handle<String> substring =
4524 isolate->factory()->NewProperSubString(subject, from, to);
ager@chromium.org04921a82011-06-27 13:21:41 +00004525 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00004526 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004527 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00004528 result->set_length(Smi::FromInt(matches));
4529 return *result;
4530}
4531
4532
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004533// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
4534// separate last match info. See comment on that function.
4535template<bool has_capture>
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004536static MaybeObject* SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004538 Handle<String> subject,
4539 Handle<JSRegExp> regexp,
4540 Handle<JSArray> last_match_array,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004541 Handle<JSArray> result_array) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004542 ASSERT(subject->IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004543 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004544
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004545 int capture_count = regexp->CaptureCount();
4546 int subject_length = subject->length();
4547
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004548 static const int kMinLengthToCache = 0x1000;
4549
4550 if (subject_length > kMinLengthToCache) {
4551 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
4552 isolate->heap(),
4553 *subject,
4554 regexp->data(),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004555 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004556 if (*cached_answer != Smi::FromInt(0)) {
4557 Handle<FixedArray> cached_fixed_array =
4558 Handle<FixedArray>(FixedArray::cast(*cached_answer));
4559 // The cache FixedArray is a COW-array and can therefore be reused.
4560 isolate->factory()->SetContent(result_array, cached_fixed_array);
4561 // The actual length of the result array is stored in the last element of
4562 // the backing store (the backing FixedArray may have a larger capacity).
4563 Object* cached_fixed_array_last_element =
4564 cached_fixed_array->get(cached_fixed_array->length() - 1);
4565 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
4566 result_array->set_length(js_array_length);
4567 RegExpImpl::SetLastMatchInfo(
4568 last_match_array, subject, capture_count, NULL);
4569 return *result_array;
4570 }
4571 }
4572
4573 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
4574 if (global_cache.HasException()) return Failure::Exception();
4575
4576 Handle<FixedArray> result_elements;
4577 if (result_array->HasFastObjectElements()) {
4578 result_elements =
4579 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4580 }
4581 if (result_elements.is_null() || result_elements->length() < 16) {
4582 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4583 }
4584
4585 FixedArrayBuilder builder(result_elements);
4586
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004587 // Position to search from.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004588 int match_start = -1;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004589 int match_end = 0;
4590 bool first = true;
4591
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004592 // Two smis before and after the match, for very long strings.
4593 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004594
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004595 while (true) {
4596 int32_t* current_match = global_cache.FetchNext();
4597 if (current_match == NULL) break;
4598 match_start = current_match[0];
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004599 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004600 if (match_end < match_start) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004601 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004602 match_end,
4603 match_start);
4604 }
4605 match_end = current_match[1];
4606 {
4607 // Avoid accumulating new handles inside loop.
4608 HandleScope temp_scope(isolate);
4609 Handle<String> match;
4610 if (!first) {
4611 match = isolate->factory()->NewProperSubString(subject,
4612 match_start,
4613 match_end);
4614 } else {
4615 match = isolate->factory()->NewSubString(subject,
4616 match_start,
4617 match_end);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004618 first = false;
4619 }
4620
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004621 if (has_capture) {
4622 // Arguments array to replace function is match, captures, index and
4623 // subject, i.e., 3 + capture count in total.
4624 Handle<FixedArray> elements =
4625 isolate->factory()->NewFixedArray(3 + capture_count);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004626
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004627 elements->set(0, *match);
4628 for (int i = 1; i <= capture_count; i++) {
4629 int start = current_match[i * 2];
4630 if (start >= 0) {
4631 int end = current_match[i * 2 + 1];
4632 ASSERT(start <= end);
4633 Handle<String> substring =
4634 isolate->factory()->NewSubString(subject, start, end);
4635 elements->set(i, *substring);
4636 } else {
4637 ASSERT(current_match[i * 2 + 1] < 0);
4638 elements->set(i, isolate->heap()->undefined_value());
4639 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004640 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004641 elements->set(capture_count + 1, Smi::FromInt(match_start));
4642 elements->set(capture_count + 2, *subject);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004643 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004644 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004645 builder.Add(*match);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004646 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004647 }
4648 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004649
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004650 if (global_cache.HasException()) return Failure::Exception();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004651
4652 if (match_start >= 0) {
4653 // Finished matching, with at least one match.
4654 if (match_end < subject_length) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004655 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004656 match_end,
4657 subject_length);
4658 }
4659
4660 RegExpImpl::SetLastMatchInfo(
4661 last_match_array, subject, capture_count, NULL);
4662
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004663 if (subject_length > kMinLengthToCache) {
4664 // Store the length of the result array into the last element of the
4665 // backing FixedArray.
4666 builder.EnsureCapacity(1);
4667 Handle<FixedArray> fixed_array = builder.array();
4668 fixed_array->set(fixed_array->length() - 1,
4669 Smi::FromInt(builder.length()));
4670 // Cache the result and turn the FixedArray into a COW array.
4671 RegExpResultsCache::Enter(isolate->heap(),
4672 *subject,
4673 regexp->data(),
4674 *fixed_array,
4675 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
4676 }
4677 return *builder.ToJSArray(result_array);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004678 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004679 return isolate->heap()->null_value(); // No matches at all.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00004680 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004681}
4682
4683
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00004684// This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4685// lastMatchInfoOverride to maintain the last match info, so we don't need to
4686// set any other last match array info.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004688 HandleScope handles(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004689 ASSERT(args.length() == 4);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004690
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004691 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004692 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004693 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4694 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4695 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004696
lrn@chromium.org25156de2010-04-06 13:10:27 +00004697 ASSERT(regexp->GetFlags().is_global());
lrn@chromium.org25156de2010-04-06 13:10:27 +00004698
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004699 if (regexp->CaptureCount() == 0) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004700 return SearchRegExpMultiple<false>(
4701 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004702 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004703 return SearchRegExpMultiple<true>(
4704 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00004705 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00004706}
4707
4708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004709RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004710 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004712 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004713 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004715 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004716 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004717 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004718 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004719 // Character array used for conversion.
4720 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 return isolate->heap()->
4722 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004723 }
4724 }
4725
4726 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004727 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004728 if (std::isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004729 return *isolate->factory()->nan_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004731 if (std::isinf(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 if (value < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004733 return *isolate->factory()->minus_infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004735 return *isolate->factory()->infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004737 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004738 MaybeObject* result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004739 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 DeleteArray(str);
4741 return result;
4742}
4743
4744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004745RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004746 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 ASSERT(args.length() == 2);
4748
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004749 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004750 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004751 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 RUNTIME_ASSERT(f >= 0);
4753 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004754 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004755 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004757 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758}
4759
4760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004761RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004762 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 ASSERT(args.length() == 2);
4764
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004765 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004766 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004767 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768 RUNTIME_ASSERT(f >= -1 && f <= 20);
4769 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004770 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004771 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004773 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774}
4775
4776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004778 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 ASSERT(args.length() == 2);
4780
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004781 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004782 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00004783 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 RUNTIME_ASSERT(f >= 1 && f <= 21);
4785 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004786 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004787 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004789 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004793RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) {
4794 HandleScope shs(isolate);
4795 ASSERT(args.length() == 1);
4796
4797 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]);
4798 if (Smi::IsValid(number)) {
4799 return isolate->heap()->true_value();
4800 } else {
4801 return isolate->heap()->false_value();
4802 }
4803}
4804
4805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806// Returns a single character string where first character equals
4807// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004808static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004809 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004810 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004811 return LookupSingleCharacterStringFromCode(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004812 string->GetIsolate(),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004813 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004815 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816}
4817
4818
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004819MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate,
4820 Handle<Object> object,
4821 uint32_t index) {
4822 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4823 GetElementOrCharAt(isolate, object, index));
4824}
4825
4826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004827MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4828 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004829 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 // Handle [] indexing on Strings
4831 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004832 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4833 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 }
4835
4836 // Handle [] indexing on String objects
4837 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004838 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4839 Handle<Object> result =
4840 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4841 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 }
4843
4844 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004845 return object->GetPrototype(isolate)->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 }
4847
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004848 return object->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849}
4850
4851
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004852static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) {
4853 if (key->IsName()) {
4854 return Handle<Name>::cast(key);
4855 } else {
4856 bool has_pending_exception = false;
4857 Handle<Object> converted =
4858 Execution::ToString(isolate, key, &has_pending_exception);
4859 if (has_pending_exception) return Handle<Name>();
4860 return Handle<Name>::cast(converted);
4861 }
4862}
4863
4864
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004865MaybeObject* Runtime::HasObjectProperty(Isolate* isolate,
4866 Handle<JSReceiver> object,
4867 Handle<Object> key) {
4868 HandleScope scope(isolate);
4869
4870 // Check if the given key is an array index.
4871 uint32_t index;
4872 if (key->ToArrayIndex(&index)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004873 return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004874 }
4875
4876 // Convert the key to a name - possibly by calling back into JavaScript.
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004877 Handle<Name> name = ToName(isolate, key);
4878 RETURN_IF_EMPTY_HANDLE(isolate, name);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004879
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004880 return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004881}
4882
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00004883MaybeObject* Runtime::GetObjectPropertyOrFail(
4884 Isolate* isolate,
4885 Handle<Object> object,
4886 Handle<Object> key) {
4887 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate,
4888 GetObjectProperty(isolate, object, key));
4889}
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4892 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004893 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004895
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004897 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 isolate->factory()->NewTypeError("non_object_property_load",
4900 HandleVector(args, 2));
4901 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902 }
4903
4904 // Check if the given key is an array index.
4905 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004906 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004907 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 }
4909
ulan@chromium.org750145a2013-03-07 15:14:13 +00004910 // Convert the key to a name - possibly by calling back into JavaScript.
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004911 Handle<Name> name = ToName(isolate, key);
4912 RETURN_IF_EMPTY_HANDLE(isolate, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913
ager@chromium.org32912102009-01-16 10:38:43 +00004914 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 // the element if so.
4916 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004919 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 }
4921}
4922
4923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004924RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004925 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926 ASSERT(args.length() == 2);
4927
4928 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004929 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932}
4933
4934
ulan@chromium.org750145a2013-03-07 15:14:13 +00004935// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004936RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00004937 SealHandleScope shs(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004938 ASSERT(args.length() == 2);
4939
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004940 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004941 // itself.
4942 //
4943 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004944 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004945 // global proxy object never has properties. This is the case
4946 // because the global proxy object forwards everything to its hidden
4947 // prototype including local lookups.
4948 //
4949 // Additionally, we need to make sure that we do not cache results
4950 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004951 if (args[0]->IsJSObject()) {
4952 if (!args[0]->IsJSGlobalProxy() &&
4953 !args[0]->IsAccessCheckNeeded() &&
ulan@chromium.org750145a2013-03-07 15:14:13 +00004954 args[1]->IsName()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004955 JSObject* receiver = JSObject::cast(args[0]);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004956 Name* key = Name::cast(args[1]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004957 if (receiver->HasFastProperties()) {
4958 // Attempt to use lookup cache.
4959 Map* receiver_map = receiver->map();
4960 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4961 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4962 if (offset != -1) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004963 // Doubles are not cached, so raw read the value.
4964 Object* value = receiver->RawFastPropertyAt(offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004965 return value->IsTheHole()
4966 ? isolate->heap()->undefined_value()
4967 : value;
4968 }
4969 // Lookup cache miss. Perform lookup and update the cache if
4970 // appropriate.
4971 LookupResult result(isolate);
4972 receiver->LocalLookup(key, &result);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00004973 if (result.IsField()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004974 int offset = result.GetFieldIndex().field_index();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004975 // Do not track double fields in the keyed lookup cache. Reading
4976 // double values requires boxing.
4977 if (!FLAG_track_double_fields ||
4978 !result.representation().IsDouble()) {
4979 keyed_lookup_cache->Update(receiver_map, key, offset);
4980 }
4981 return receiver->FastPropertyAt(result.representation(), offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004982 }
4983 } else {
4984 // Attempt dictionary lookup.
ulan@chromium.org750145a2013-03-07 15:14:13 +00004985 NameDictionary* dictionary = receiver->property_dictionary();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004986 int entry = dictionary->FindEntry(key);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004987 if ((entry != NameDictionary::kNotFound) &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004988 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4989 Object* value = dictionary->ValueAt(entry);
4990 if (!receiver->IsGlobalObject()) return value;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00004991 value = PropertyCell::cast(value)->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004992 if (!value->IsTheHole()) return value;
4993 // If value is the hole do the general lookup.
4994 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004995 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004996 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004997 // JSObject without a name key. If the key is a Smi, check for a
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004998 // definite out-of-bounds access to elements, which is a strong indicator
4999 // that subsequent accesses will also call the runtime. Proactively
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005000 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005001 // doubles for those future calls in the case that the elements would
5002 // become FAST_DOUBLE_ELEMENTS.
5003 Handle<JSObject> js_object(args.at<JSObject>(0));
5004 ElementsKind elements_kind = js_object->GetElementsKind();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005005 if (IsFastDoubleElementsKind(elements_kind)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005006 FixedArrayBase* elements = js_object->elements();
5007 if (args.at<Smi>(1)->value() >= elements->length()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005008 if (IsFastHoleyElementsKind(elements_kind)) {
5009 elements_kind = FAST_HOLEY_ELEMENTS;
5010 } else {
5011 elements_kind = FAST_ELEMENTS;
5012 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005013 MaybeObject* maybe_object = TransitionElements(js_object,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005014 elements_kind,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005015 isolate);
5016 if (maybe_object->IsFailure()) return maybe_object;
5017 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005018 } else {
5019 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
5020 !IsFastElementsKind(elements_kind));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005021 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005022 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005023 } else if (args[0]->IsString() && args[1]->IsSmi()) {
5024 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005025 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005026 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005027 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005028 if (index >= 0 && index < str->length()) {
5029 Handle<Object> result = GetCharAt(str, index);
5030 return *result;
5031 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005032 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005033
5034 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 return Runtime::GetObjectProperty(isolate,
5036 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00005037 args.at<Object>(1));
5038}
5039
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005040
5041static bool IsValidAccessor(Handle<Object> obj) {
5042 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
5043}
5044
5045
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005046// Implements part of 8.12.9 DefineOwnProperty.
5047// There are 3 cases that lead here:
5048// Step 4b - define a new accessor property.
5049// Steps 9c & 12 - replace an existing data property with an accessor property.
5050// Step 12 - update an existing accessor property with an accessor or generic
5051// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005052RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005054 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005055 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005056 RUNTIME_ASSERT(!obj->IsNull());
ulan@chromium.org750145a2013-03-07 15:14:13 +00005057 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005058 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
5059 RUNTIME_ASSERT(IsValidAccessor(getter));
5060 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
5061 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005062 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00005063 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00005064 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00005065
danno@chromium.org88aa0582012-03-23 15:11:57 +00005066 bool fast = obj->HasFastProperties();
5067 JSObject::DefineAccessor(obj, name, getter, setter, attr);
danno@chromium.org169691d2013-07-15 08:01:13 +00005068 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005069 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005070 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00005071}
5072
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00005073
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005074// Implements part of 8.12.9 DefineOwnProperty.
5075// There are 3 cases that lead here:
5076// Step 4a - define a new data property.
5077// Steps 9b & 12 - replace an existing accessor property with a data property.
5078// Step 12 - update an existing data property with a data or generic
5079// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005080RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005082 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005083 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005084 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005085 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005086 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00005087 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00005088 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
5089
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005090 LookupResult lookup(isolate);
5091 js_object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.org5c838252010-02-19 08:53:10 +00005092
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005093 // Special case for callback properties.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005094 if (lookup.IsPropertyCallbacks()) {
5095 Handle<Object> callback(lookup.GetCallbackObject(), isolate);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005096 // To be compatible with Safari we do not change the value on API objects
5097 // in Object.defineProperty(). Firefox disagrees here, and actually changes
5098 // the value.
5099 if (callback->IsAccessorInfo()) {
5100 return isolate->heap()->undefined_value();
5101 }
5102 // Avoid redefining foreign callback as data property, just use the stored
5103 // setter to update the value instead.
5104 // TODO(mstarzinger): So far this only works if property attributes don't
5105 // change, this should be fixed once we cleanup the underlying code.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005106 if (callback->IsForeign() && lookup.GetAttributes() == attr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005107 Handle<Object> result_object =
5108 JSObject::SetPropertyWithCallback(js_object,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005109 callback,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005110 name,
5111 obj_value,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005112 handle(lookup.holder()),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005113 kStrictMode);
5114 RETURN_IF_EMPTY_HANDLE(isolate, result_object);
5115 return *result_object;
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00005116 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00005117 }
5118
ager@chromium.org5c838252010-02-19 08:53:10 +00005119 // Take special care when attributes are different and there is already
5120 // a property. For simplicity we normalize the property which enables us
5121 // to not worry about changing the instance_descriptor and creating a new
5122 // map. The current version of SetObjectProperty does not handle attributes
5123 // correctly in the case where a property is a field and is reset with
5124 // new attributes.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005125 if (lookup.IsFound() &&
5126 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) {
ager@chromium.org5c838252010-02-19 08:53:10 +00005127 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005128 if (js_object->IsJSGlobalProxy()) {
5129 // Since the result is a property, the prototype will exist so
5130 // we don't have to check for null.
5131 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005132 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005133 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00005134 // Use IgnoreAttributes version since a readonly property may be
5135 // overridden and SetProperty does not allow this.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005136 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5137 js_object, name, obj_value, attr);
5138 RETURN_IF_EMPTY_HANDLE(isolate, result);
5139 return *result;
ager@chromium.org5c838252010-02-19 08:53:10 +00005140 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00005141
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005142 Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object,
5143 name,
5144 obj_value,
5145 attr);
5146 RETURN_IF_EMPTY_HANDLE(isolate, result);
5147 return *result;
ager@chromium.org5c838252010-02-19 08:53:10 +00005148}
5149
5150
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005151// Return property without being observable by accessors or interceptors.
5152RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005153 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005154 ASSERT(args.length() == 2);
5155 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005156 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005157 LookupResult lookup(isolate);
5158 object->LookupRealNamedProperty(*key, &lookup);
5159 if (!lookup.IsFound()) return isolate->heap()->undefined_value();
5160 switch (lookup.type()) {
5161 case NORMAL:
5162 return lookup.holder()->GetNormalizedProperty(&lookup);
5163 case FIELD:
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005164 return lookup.holder()->FastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005165 lookup.representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005166 lookup.GetFieldIndex().field_index());
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00005167 case CONSTANT:
5168 return lookup.GetConstant();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005169 case CALLBACKS:
5170 case HANDLER:
5171 case INTERCEPTOR:
5172 case TRANSITION:
5173 return isolate->heap()->undefined_value();
5174 case NONEXISTENT:
5175 UNREACHABLE();
5176 }
5177 return isolate->heap()->undefined_value();
5178}
5179
5180
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005181Handle<Object> Runtime::SetObjectProperty(Isolate* isolate,
5182 Handle<Object> object,
5183 Handle<Object> key,
5184 Handle<Object> value,
5185 PropertyAttributes attr,
5186 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005187 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005190 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 isolate->factory()->NewTypeError("non_object_property_store",
5193 HandleVector(args, 2));
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005194 isolate->Throw(*error);
5195 return Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 }
5197
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005198 if (object->IsJSProxy()) {
5199 bool has_pending_exception = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005200 Handle<Object> name_object = key->IsSymbol()
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005201 ? key : Execution::ToString(isolate, key, &has_pending_exception);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005202 if (has_pending_exception) return Handle<Object>(); // exception
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005203 Handle<Name> name = Handle<Name>::cast(name_object);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005204 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
5205 attr,
5206 strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005207 }
5208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 // If the object isn't a JavaScript object, we ignore the store.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005210 if (!object->IsJSObject()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005212 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
5213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 // Check if the given key is an array index.
5215 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005216 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005217 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5218 // of a string using [] notation. We need to support this too in
5219 // JavaScript.
5220 // In the case of a String object we just need to redirect the assignment to
5221 // the underlying string if the index is in range. Since the underlying
5222 // string does nothing with the assignment then we can ignore such
5223 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005224 if (js_object->IsStringObjectWithCharacterAt(index)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005225 return value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005227
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005228 js_object->ValidateElements();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005229 if (js_object->HasExternalArrayElements()) {
5230 if (!value->IsNumber() && !value->IsUndefined()) {
5231 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005232 Handle<Object> number =
5233 Execution::ToNumber(isolate, value, &has_exception);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005234 if (has_exception) return Handle<Object>(); // exception
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005235 value = number;
5236 }
5237 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005238 Handle<Object> result = JSObject::SetElement(js_object, index, value, attr,
5239 strict_mode,
5240 true,
5241 set_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005242 js_object->ValidateElements();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005243 return result.is_null() ? result : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005244 }
5245
ulan@chromium.org750145a2013-03-07 15:14:13 +00005246 if (key->IsName()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005247 Handle<Name> name = Handle<Name>::cast(key);
5248 if (name->AsArrayIndex(&index)) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005249 if (js_object->HasExternalArrayElements()) {
5250 if (!value->IsNumber() && !value->IsUndefined()) {
5251 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005252 Handle<Object> number =
5253 Execution::ToNumber(isolate, value, &has_exception);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005254 if (has_exception) return Handle<Object>(); // exception
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005255 value = number;
5256 }
5257 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005258 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5259 true,
5260 set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005262 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005263 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005265 }
5266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005269 Handle<Object> converted =
5270 Execution::ToString(isolate, key, &has_pending_exception);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005271 if (has_pending_exception) return Handle<Object>(); // exception
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005272 Handle<String> name = Handle<String>::cast(converted);
5273
5274 if (name->AsArrayIndex(&index)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005275 return JSObject::SetElement(js_object, index, value, attr, strict_mode,
5276 true,
5277 set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005278 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005279 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005280 }
5281}
5282
5283
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005284Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate,
5285 Handle<JSObject> js_object,
5286 Handle<Object> key,
5287 Handle<Object> value,
5288 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005289 // Check if the given key is an array index.
5290 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005291 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005292 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
5293 // of a string using [] notation. We need to support this too in
5294 // JavaScript.
5295 // In the case of a String object we just need to redirect the assignment to
5296 // the underlying string if the index is in range. Since the underlying
5297 // string does nothing with the assignment then we can ignore such
5298 // assignments.
5299 if (js_object->IsStringObjectWithCharacterAt(index)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005300 return value;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005301 }
5302
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005303 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5304 false,
5305 DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005306 }
5307
ulan@chromium.org750145a2013-03-07 15:14:13 +00005308 if (key->IsName()) {
5309 Handle<Name> name = Handle<Name>::cast(key);
5310 if (name->AsArrayIndex(&index)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005311 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5312 false,
5313 DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005314 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005315 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005316 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name,
5317 value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005318 }
5319 }
5320
5321 // Call-back into JavaScript to convert the key to a string.
5322 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005323 Handle<Object> converted =
5324 Execution::ToString(isolate, key, &has_pending_exception);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005325 if (has_pending_exception) return Handle<Object>(); // exception
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005326 Handle<String> name = Handle<String>::cast(converted);
5327
5328 if (name->AsArrayIndex(&index)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005329 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode,
5330 false,
5331 DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005332 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005333 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value,
5334 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005335 }
5336}
5337
5338
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005339MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate,
5340 Handle<JSReceiver> receiver,
5341 Handle<Object> key,
5342 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005343 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005344
5345 // Check if the given key is an array index.
5346 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005347 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00005348 // In Firefox/SpiderMonkey, Safari and Opera you can access the
5349 // characters of a string using [] notation. In the case of a
5350 // String object we just need to redirect the deletion to the
5351 // underlying string if the index is in range. Since the
5352 // underlying string does nothing with the deletion, we can ignore
5353 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00005354 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005355 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00005356 }
5357
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005358 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode);
5359 RETURN_IF_EMPTY_HANDLE(isolate, result);
5360 return *result;
ager@chromium.orge2902be2009-06-08 12:21:35 +00005361 }
5362
ulan@chromium.org750145a2013-03-07 15:14:13 +00005363 Handle<Name> name;
5364 if (key->IsName()) {
5365 name = Handle<Name>::cast(key);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005366 } else {
5367 // Call-back into JavaScript to convert the key to a string.
5368 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005369 Handle<Object> converted = Execution::ToString(
5370 isolate, key, &has_pending_exception);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005371 if (has_pending_exception) return Failure::Exception();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005372 name = Handle<String>::cast(converted);
ager@chromium.orge2902be2009-06-08 12:21:35 +00005373 }
5374
ulan@chromium.org750145a2013-03-07 15:14:13 +00005375 if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005376 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode);
5377 RETURN_IF_EMPTY_HANDLE(isolate, result);
5378 return *result;
ager@chromium.orge2902be2009-06-08 12:21:35 +00005379}
5380
5381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005382RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005383 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005384 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005386 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
5387 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
5388 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005389 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005390 RUNTIME_ASSERT(
5391 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005393 PropertyAttributes attributes =
5394 static_cast<PropertyAttributes>(unchecked_attributes);
5395
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005396 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005397 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005398 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005399 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005400 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00005401
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005402 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
5403 value,
5404 attributes,
5405 strict_mode);
5406 RETURN_IF_EMPTY_HANDLE(isolate, result);
5407 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408}
5409
5410
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005411RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) {
5412 HandleScope scope(isolate);
5413 RUNTIME_ASSERT(args.length() == 2);
5414 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
5415 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
5416 JSObject::TransitionElementsKind(array, map->elements_kind());
5417 return *array;
5418}
5419
5420
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005421// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005422// This is used to decide if we should transform null and undefined
5423// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005424RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005425 SealHandleScope shs(isolate);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005426 RUNTIME_ASSERT(args.length() == 1);
5427
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005428 CONVERT_ARG_CHECKED(Object, object, 0);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005429
5430 if (object->IsJSFunction()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005431 JSFunction* func = JSFunction::cast(object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005432 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00005433 }
5434 return isolate->heap()->undefined_value();
5435}
5436
5437
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00005438RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) {
5439 SealHandleScope shs(isolate);
5440 RUNTIME_ASSERT(args.length() == 1);
5441
5442 Handle<Object> object = args.at<Object>(0);
5443
5444 if (object->IsJSFunction()) {
5445 JSFunction* func = JSFunction::cast(*object);
5446 func->shared()->set_inline_builtin(true);
5447 }
5448 return isolate->heap()->undefined_value();
5449}
5450
5451
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005452RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005453 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005454 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005455 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005456 CONVERT_SMI_ARG_CHECKED(store_index, 1);
5457 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005458 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005459 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005460
danno@chromium.orgbee51992013-07-10 14:57:15 +00005461 Object* raw_literal_cell = literals->get(literal_index);
5462 JSArray* boilerplate = NULL;
5463 if (raw_literal_cell->IsAllocationSite()) {
5464 AllocationSite* site = AllocationSite::cast(raw_literal_cell);
5465 boilerplate = JSArray::cast(site->transition_info());
5466 } else {
5467 boilerplate = JSArray::cast(raw_literal_cell);
5468 }
5469 Handle<JSArray> boilerplate_object(boilerplate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005470 ElementsKind elements_kind = object->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005471 ASSERT(IsFastElementsKind(elements_kind));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005472 // Smis should never trigger transitions.
5473 ASSERT(!value->IsSmi());
5474
5475 if (value->IsNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005476 ASSERT(IsFastSmiElementsKind(elements_kind));
5477 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5478 ? FAST_HOLEY_DOUBLE_ELEMENTS
5479 : FAST_DOUBLE_ELEMENTS;
5480 if (IsMoreGeneralElementsKindTransition(
5481 boilerplate_object->GetElementsKind(),
5482 transitioned_kind)) {
5483 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005484 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005485 JSObject::TransitionElementsKind(object, transitioned_kind);
5486 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005487 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005488 HeapNumber* number = HeapNumber::cast(*value);
5489 double_array->set(store_index, number->Number());
5490 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005491 ASSERT(IsFastSmiElementsKind(elements_kind) ||
5492 IsFastDoubleElementsKind(elements_kind));
5493 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
5494 ? FAST_HOLEY_ELEMENTS
5495 : FAST_ELEMENTS;
5496 JSObject::TransitionElementsKind(object, transitioned_kind);
5497 if (IsMoreGeneralElementsKindTransition(
5498 boilerplate_object->GetElementsKind(),
5499 transitioned_kind)) {
5500 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005501 }
5502 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005503 object_array->set(store_index, *value);
5504 }
5505 return *object;
5506}
5507
5508
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005509// Check whether debugger and is about to step into the callback that is passed
5510// to a built-in function such as Array.forEach.
5511RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005512 SealHandleScope shs(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005513#ifdef ENABLE_DEBUGGER_SUPPORT
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005514 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
5515 return isolate->heap()->false_value();
5516 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005517 CONVERT_ARG_CHECKED(Object, callback, 0);
5518 // We do not step into the callback if it's a builtin or not even a function.
5519 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
5520 return isolate->heap()->false_value();
5521 }
5522 return isolate->heap()->true_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005523#else
5524 return isolate->heap()->false_value();
5525#endif // ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005526}
5527
5528
5529// Set one shot breakpoints for the callback function that is passed to a
5530// built-in function such as Array.forEach to enable stepping into the callback.
5531RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005532 SealHandleScope shs(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005533#ifdef ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005534 Debug* debug = isolate->debug();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005535 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005536 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005537 HandleScope scope(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005538 // When leaving the callback, step out has been activated, but not performed
5539 // if we do not leave the builtin. To be able to step into the callback
5540 // again, we need to clear the step out at this point.
5541 debug->ClearStepOut();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005542 debug->FloodWithOneShot(callback);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005543#endif // ENABLE_DEBUGGER_SUPPORT
5544 return isolate->heap()->undefined_value();
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00005545}
5546
5547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548// Set a local property, even if it is READ_ONLY. If the property does not
5549// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005550RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005551 HandleScope scope(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005552 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005553 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
5554 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
5555 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005556 // Compute attributes.
5557 PropertyAttributes attributes = NONE;
5558 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005559 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005560 // Only attribute bits should be set.
5561 RUNTIME_ASSERT(
5562 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
5563 attributes = static_cast<PropertyAttributes>(unchecked_value);
5564 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005565 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
5566 object, name, value, attributes);
5567 RETURN_IF_EMPTY_HANDLE(isolate, result);
5568 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569}
5570
5571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005572RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005573 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005574 ASSERT(args.length() == 3);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005575 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
5576 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005577 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005578 JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode)
5579 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION;
5580 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode);
5581 RETURN_IF_EMPTY_HANDLE(isolate, result);
5582 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583}
5584
5585
danno@chromium.org169691d2013-07-15 08:01:13 +00005586static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate,
5587 Handle<JSObject> object,
5588 Handle<Name> key) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005589 if (JSReceiver::HasLocalProperty(object, key)) {
5590 return isolate->heap()->true_value();
5591 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005592 // Handle hidden prototypes. If there's a hidden prototype above this thing
5593 // then we have to check it for properties, because they are supposed to
5594 // look like they are on this object.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005595 Handle<Object> proto(object->GetPrototype(), isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +00005596 if (proto->IsJSObject() &&
5597 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 return HasLocalPropertyImplementation(isolate,
5599 Handle<JSObject>::cast(proto),
5600 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00005601 }
danno@chromium.org169691d2013-07-15 08:01:13 +00005602 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005603 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00005604}
5605
5606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005607RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005608 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609 ASSERT(args.length() == 2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005610 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
5611 Handle<Object> object = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005613 uint32_t index;
5614 const bool key_is_array_index = key->AsArrayIndex(&index);
5615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005616 // Only JS objects can have properties.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005617 if (object->IsJSObject()) {
5618 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005619 // Fast case: either the key is a real named property or it is not
5620 // an array index and there are no interceptors or hidden
5621 // prototypes.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005622 if (JSObject::HasRealNamedProperty(js_obj, key)) {
danno@chromium.org169691d2013-07-15 08:01:13 +00005623 ASSERT(!isolate->has_scheduled_exception());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005624 return isolate->heap()->true_value();
danno@chromium.org169691d2013-07-15 08:01:13 +00005625 } else {
5626 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5627 }
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005628 Map* map = js_obj->map();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005629 if (!key_is_array_index &&
5630 !map->has_named_interceptor() &&
5631 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
5632 return isolate->heap()->false_value();
5633 }
5634 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 return HasLocalPropertyImplementation(isolate,
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005636 Handle<JSObject>(js_obj),
ulan@chromium.org750145a2013-03-07 15:14:13 +00005637 Handle<Name>(key));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005638 } else if (object->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 // Well, there is one exception: Handle [] on strings.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005640 Handle<String> string = Handle<String>::cast(object);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00005641 if (index < static_cast<uint32_t>(string->length())) {
5642 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 }
5644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005645 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005646}
5647
5648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005649RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005650 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 ASSERT(args.length() == 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005652 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
5653 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005655 bool result = JSReceiver::HasProperty(receiver, key);
danno@chromium.org169691d2013-07-15 08:01:13 +00005656 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005657 if (isolate->has_pending_exception()) return Failure::Exception();
5658 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659}
5660
5661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005662RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005663 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 ASSERT(args.length() == 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005665 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005666 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005668 bool result = JSReceiver::HasElement(receiver, index);
danno@chromium.org169691d2013-07-15 08:01:13 +00005669 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005670 if (isolate->has_pending_exception()) return Failure::Exception();
5671 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672}
5673
5674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005675RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005676 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 ASSERT(args.length() == 2);
5678
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005679 CONVERT_ARG_CHECKED(JSObject, object, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005680 CONVERT_ARG_CHECKED(Name, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005681
ager@chromium.org870a0b62008-11-04 11:43:05 +00005682 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
danno@chromium.org169691d2013-07-15 08:01:13 +00005683 if (att == ABSENT || (att & DONT_ENUM) != 0) {
5684 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
5685 return isolate->heap()->false_value();
5686 }
5687 ASSERT(!isolate->has_scheduled_exception());
5688 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689}
5690
5691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005693 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005694 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005695 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005696 bool threw = false;
5697 Handle<JSArray> result = GetKeysFor(object, &threw);
5698 if (threw) return Failure::Exception();
5699 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005700}
5701
5702
5703// Returns either a FixedArray as Runtime_GetPropertyNames,
5704// or, if the given object has an enum cache that contains
5705// all enumerable properties of the object and its prototypes
5706// have none, the map of the object. This is used to speed up
5707// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005709 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005710 ASSERT(args.length() == 1);
5711
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005712 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005713
5714 if (raw_object->IsSimpleEnum()) return raw_object->map();
5715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005716 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005717 Handle<JSReceiver> object(raw_object);
5718 bool threw = false;
5719 Handle<FixedArray> content =
5720 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
5721 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722
5723 // Test again, since cache may have been built by preceding call.
5724 if (object->IsSimpleEnum()) return object->map();
5725
5726 return *content;
5727}
5728
5729
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005730// Find the length of the prototype chain that is to to handled as one. If a
5731// prototype object is hidden it is to be viewed as part of the the object it
5732// is prototype for.
5733static int LocalPrototypeChainLength(JSObject* obj) {
5734 int count = 1;
5735 Object* proto = obj->GetPrototype();
5736 while (proto->IsJSObject() &&
5737 JSObject::cast(proto)->map()->is_hidden_prototype()) {
5738 count++;
5739 proto = JSObject::cast(proto)->GetPrototype();
5740 }
5741 return count;
5742}
5743
5744
5745// Return the names of the local named properties.
5746// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005747RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 HandleScope scope(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005749 ASSERT(args.length() == 2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005750 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005751 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005752 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005753 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005754 CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1);
5755 PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005756
5757 // Skip the global proxy as it has no properties and always delegates to the
5758 // real global object.
5759 if (obj->IsJSGlobalProxy()) {
5760 // Only collect names if access is permitted.
5761 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 !isolate->MayNamedAccess(*obj,
5763 isolate->heap()->undefined_value(),
5764 v8::ACCESS_KEYS)) {
5765 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005766 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005767 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005768 }
5769 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5770 }
5771
5772 // Find the number of objects making up this.
5773 int length = LocalPrototypeChainLength(*obj);
5774
5775 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005776 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005777 int total_property_count = 0;
5778 Handle<JSObject> jsproto = obj;
5779 for (int i = 0; i < length; i++) {
5780 // Only collect names if access is permitted.
5781 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005782 !isolate->MayNamedAccess(*jsproto,
5783 isolate->heap()->undefined_value(),
5784 v8::ACCESS_KEYS)) {
5785 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005786 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005788 }
5789 int n;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005790 n = jsproto->NumberOfLocalProperties(filter);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005791 local_property_count[i] = n;
5792 total_property_count += n;
5793 if (i < length - 1) {
5794 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5795 }
5796 }
5797
5798 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005799 Handle<FixedArray> names =
5800 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005801
5802 // Get the property names.
5803 jsproto = obj;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005804 int next_copy_index = 0;
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005805 int hidden_strings = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005806 for (int i = 0; i < length; i++) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005807 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter);
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005808 if (i > 0) {
5809 // Names from hidden prototypes may already have been added
5810 // for inherited function template instances. Count the duplicates
5811 // and stub them out; the final copy pass at the end ignores holes.
5812 for (int j = next_copy_index;
5813 j < next_copy_index + local_property_count[i];
5814 j++) {
5815 Object* name_from_hidden_proto = names->get(j);
5816 for (int k = 0; k < next_copy_index; k++) {
5817 if (names->get(k) != isolate->heap()->hidden_string()) {
5818 Object* name = names->get(k);
5819 if (name_from_hidden_proto == name) {
5820 names->set(j, isolate->heap()->hidden_string());
5821 hidden_strings++;
5822 break;
5823 }
5824 }
5825 }
5826 }
5827 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005828 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005829 if (jsproto->HasHiddenProperties()) {
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005830 hidden_strings++;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005831 }
5832 if (i < length - 1) {
5833 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5834 }
5835 }
5836
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005837 // Filter out name of hidden properties object and
5838 // hidden prototype duplicates.
5839 if (hidden_strings > 0) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005840 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005841 names = isolate->factory()->NewFixedArray(
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005842 names->length() - hidden_strings);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005843 int dest_pos = 0;
5844 for (int i = 0; i < total_property_count; i++) {
5845 Object* name = old_names->get(i);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005846 if (name == isolate->heap()->hidden_string()) {
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005847 hidden_strings--;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005848 continue;
5849 }
5850 names->set(dest_pos++, name);
5851 }
ulan@chromium.org0f13e742014-01-03 15:51:11 +00005852 ASSERT_EQ(0, hidden_strings);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005853 }
5854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005855 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005856}
5857
5858
5859// Return the names of the local indexed properties.
5860// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005861RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005863 ASSERT(args.length() == 1);
5864 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005865 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005866 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005867 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005868
5869 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005870 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005871 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005873}
5874
5875
5876// Return information on whether an object has a named or indexed interceptor.
5877// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005880 ASSERT(args.length() == 1);
5881 if (!args[0]->IsJSObject()) {
5882 return Smi::FromInt(0);
5883 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005884 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005885
5886 int result = 0;
5887 if (obj->HasNamedInterceptor()) result |= 2;
5888 if (obj->HasIndexedInterceptor()) result |= 1;
5889
5890 return Smi::FromInt(result);
5891}
5892
5893
5894// Return property names from named interceptor.
5895// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005896RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005897 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005898 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005899 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005900
5901 if (obj->HasNamedInterceptor()) {
5902 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5903 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5904 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005905 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005906}
5907
5908
5909// Return element names from indexed interceptor.
5910// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005911RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005913 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005914 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005915
5916 if (obj->HasIndexedInterceptor()) {
5917 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5918 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5919 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005921}
5922
5923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005924RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005925 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005926 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005927 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005928 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005929
5930 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005931 // Do access checks before going to the global object.
5932 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005933 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005934 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005935 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005936 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005937 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005938 }
5939
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005940 Handle<Object> proto(object->GetPrototype(), isolate);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005941 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005943 object = Handle<JSObject>::cast(proto);
5944 }
5945
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005946 bool threw = false;
5947 Handle<FixedArray> contents =
5948 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5949 if (threw) return Failure::Exception();
5950
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005951 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5952 // property array and since the result is mutable we have to create
5953 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005954 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005955 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005956 for (int i = 0; i < length; i++) {
5957 Object* entry = contents->get(i);
5958 if (entry->IsString()) {
5959 copy->set(i, entry);
5960 } else {
5961 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005962 HandleScope scope(isolate);
5963 Handle<Object> entry_handle(entry, isolate);
5964 Handle<Object> entry_str =
5965 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005966 copy->set(i, *entry_str);
5967 }
5968 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005970}
5971
5972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005973RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005974 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 ASSERT(args.length() == 1);
5976
5977 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005978 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 it.AdvanceToArgumentsFrame();
5980 JavaScriptFrame* frame = it.frame();
5981
5982 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005983 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984
5985 // Try to convert the key to an index. If successful and within
5986 // index return the the argument from the frame.
5987 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005988 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 return frame->GetParameter(index);
5990 }
5991
ulan@chromium.org750145a2013-03-07 15:14:13 +00005992 if (args[0]->IsSymbol()) {
5993 // Lookup in the initial Object.prototype object.
5994 return isolate->initial_object_prototype()->GetProperty(
5995 Symbol::cast(args[0]));
5996 }
5997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 bool exception = false;
6001 Handle<Object> converted =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00006002 Execution::ToString(isolate, args.at<Object>(0), &exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 if (exception) return Failure::Exception();
6004 Handle<String> key = Handle<String>::cast(converted);
6005
6006 // Try to convert the string key into an array index.
6007 if (key->AsArrayIndex(&index)) {
6008 if (index < n) {
6009 return frame->GetParameter(index);
6010 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006011 return isolate->initial_object_prototype()->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 }
6013 }
6014
6015 // Handle special arguments properties.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006016 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
6017 if (key->Equals(isolate->heap()->callee_string())) {
danno@chromium.org169691d2013-07-15 08:01:13 +00006018 JSFunction* function = frame->function();
6019 if (!function->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(*isolate->factory()->NewTypeError(
6021 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
6022 }
6023 return function;
6024 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025
6026 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028}
6029
6030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006031RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006032 HandleScope scope(isolate);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00006033 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006034 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6035 if (object->IsJSObject() && !object->IsGlobalObject()) {
6036 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
6037 }
6038 return *object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00006039}
6040
6041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006042RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006043 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006044 ASSERT(args.length() == 1);
6045
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00006046 return isolate->heap()->ToBoolean(args[0]->BooleanValue());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047}
6048
6049
6050// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
6051// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006052RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006053 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054
6055 Object* obj = args[0];
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006056 if (obj->IsNumber()) return isolate->heap()->number_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 HeapObject* heap_obj = HeapObject::cast(obj);
6058
6059 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006060 if (heap_obj->map()->is_undetectable()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006061 return isolate->heap()->undefined_string();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063
6064 InstanceType instance_type = heap_obj->map()->instance_type();
6065 if (instance_type < FIRST_NONSTRING_TYPE) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006066 return isolate->heap()->string_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 }
6068
6069 switch (instance_type) {
6070 case ODDBALL_TYPE:
6071 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006072 return isolate->heap()->boolean_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006073 }
6074 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006075 return FLAG_harmony_typeof
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006076 ? isolate->heap()->null_string()
6077 : isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 }
6079 ASSERT(heap_obj->IsUndefined());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006080 return isolate->heap()->undefined_string();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006081 case SYMBOL_TYPE:
6082 return isolate->heap()->symbol_string();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006083 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00006084 case JS_FUNCTION_PROXY_TYPE:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006085 return isolate->heap()->function_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086 default:
6087 // For any kind of object not handled above, the spec rule for
6088 // host objects gives that it is okay to return "object"
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006089 return isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090 }
6091}
6092
6093
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006094static bool AreDigits(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006095 for (int i = from; i < to; i++) {
6096 if (s[i] < '0' || s[i] > '9') return false;
6097 }
6098
6099 return true;
6100}
6101
6102
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006103static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006104 ASSERT(to - from < 10); // Overflow is not possible.
6105 ASSERT(from < to);
6106 int d = s[from] - '0';
6107
6108 for (int i = from + 1; i < to; i++) {
6109 d = 10 * d + (s[i] - '0');
6110 }
6111
6112 return d;
6113}
6114
6115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006116RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006117 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006119 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006121
6122 // Fast case: short integer or some sorts of junk values.
6123 int len = subject->length();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006124 if (subject->IsSeqOneByteString()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006125 if (len == 0) return Smi::FromInt(0);
6126
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006127 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006128 bool minus = (data[0] == '-');
6129 int start_pos = (minus ? 1 : 0);
6130
6131 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006132 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006133 } else if (data[start_pos] > '9') {
6134 // Fast check for a junk value. A valid string may start from a
6135 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
6136 // the 'I' character ('Infinity'). All of that have codes not greater than
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00006137 // '9' except 'I' and &nbsp;.
6138 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006139 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006140 }
6141 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6142 // The maximal/minimal smi has 10 digits. If the string has less digits we
6143 // know it will fit into the smi-data type.
6144 int d = ParseDecimalInteger(data, start_pos, len);
6145 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006146 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006147 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006148 } else if (!subject->HasHashCode() &&
6149 len <= String::kMaxArrayIndexSize &&
6150 (len == 1 || data[0] != '0')) {
6151 // String hash is not calculated yet but all the data are present.
6152 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006153 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006154#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006155 subject->Hash(); // Force hash calculation.
6156 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6157 static_cast<int>(hash));
6158#endif
6159 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00006160 }
6161 return Smi::FromInt(d);
6162 }
6163 }
6164
6165 // Slower case.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006166 int flags = ALLOW_HEX;
6167 if (FLAG_harmony_numeric_literals) {
6168 // The current spec draft has not updated "ToNumber Applied to the String
6169 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6170 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6171 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006172 return isolate->heap()->NumberFromDouble(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006173 StringToDouble(isolate->unicode_cache(), subject, flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174}
6175
6176
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006177RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006178 SealHandleScope shs(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006179 CONVERT_SMI_ARG_CHECKED(length, 0);
6180 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6181 if (length == 0) return isolate->heap()->empty_string();
6182 if (is_one_byte) {
6183 return isolate->heap()->AllocateRawOneByteString(length);
6184 } else {
6185 return isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006187}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006190RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006191 HandleScope scope(isolate);
6192 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006193 CONVERT_SMI_ARG_CHECKED(new_length, 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006194 return *SeqString::Truncate(string, new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195}
6196
6197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006198RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006199 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006200 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006201 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6202 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006203 ASSERT(string->IsFlat());
6204 Handle<String> result = string->IsOneByteRepresentationUnderneath()
6205 ? URIEscape::Escape<uint8_t>(isolate, source)
6206 : URIEscape::Escape<uc16>(isolate, source);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006207 if (result.is_null()) return Failure::OutOfMemoryException(0x12);
6208 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209}
6210
6211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006212RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006213 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006214 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006215 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6216 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006217 ASSERT(string->IsFlat());
6218 return string->IsOneByteRepresentationUnderneath()
6219 ? *URIUnescape::Unescape<uint8_t>(isolate, source)
6220 : *URIUnescape::Unescape<uc16>(isolate, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006221}
6222
6223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006224RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006225 HandleScope scope(isolate);
6226 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006227 ASSERT(args.length() == 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006228 return BasicJsonStringifier::StringifyString(isolate, string);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006229}
6230
6231
danno@chromium.org72204d52012-10-31 10:02:10 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
danno@chromium.org72204d52012-10-31 10:02:10 +00006233 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006234 ASSERT(args.length() == 1);
danno@chromium.org72204d52012-10-31 10:02:10 +00006235 BasicJsonStringifier stringifier(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006236 return stringifier.Stringify(Handle<Object>(args[0], isolate));
danno@chromium.org72204d52012-10-31 10:02:10 +00006237}
6238
6239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006241 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006243 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006244 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006246 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247
lrn@chromium.org25156de2010-04-06 13:10:27 +00006248 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006249 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251}
6252
6253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006254RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006255 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006256 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006257
6258 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006259 double value = StringToDouble(isolate->unicode_cache(),
6260 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261
6262 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006267template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006268MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006269 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006270 String* s,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006271 String::Encoding result_encoding,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006272 int length,
6273 int input_string_length,
6274 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006275 // We try this twice, once with the assumption that the result is no longer
6276 // than the input and, if that assumption breaks, again with the exact
6277 // length. This may not be pretty, but it is nicer than what was here before
6278 // and I hereby claim my vaffel-is.
6279 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280 // Allocate the resulting string.
6281 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006282 // NOTE: This assumes that the upper/lower case of an ASCII
6283 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284 // might break in the future if we implement more context and locale
6285 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006286 Object* o;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006287 { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006288 ? isolate->heap()->AllocateRawOneByteString(length)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006290 if (!maybe_o->ToObject(&o)) return maybe_o;
6291 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292 String* result = String::cast(o);
6293 bool has_changed_character = false;
6294
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006295 DisallowHeapAllocation no_gc;
6296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006297 // Convert all characters to upper case, assuming that they will fit
6298 // in the buffer
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006299 Access<ConsStringIteratorOp> op(
6300 isolate->runtime_state()->string_iterator());
6301 StringCharacterStream stream(s, op.value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006302 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006303 // We can assume that the string is not empty
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006304 uc32 current = stream.GetNext();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006305 // y with umlauts is the only character that stops fitting into one-byte
6306 // when converting to uppercase.
6307 static const uc32 yuml_code = 0xff;
6308 bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006309 for (int i = 0; i < length;) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006310 bool has_next = stream.HasMore();
6311 uc32 next = has_next ? stream.GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 int char_length = mapping->get(current, next, chars);
6313 if (char_length == 0) {
6314 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006315 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316 i++;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006317 } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318 // Common case: converting the letter resulted in one character.
6319 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006320 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006321 has_changed_character = true;
6322 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006323 } else if (length == input_string_length) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006324 bool found_yuml = (current == yuml_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325 // We've assumed that the result would be as long as the
6326 // input but here is a character that converts to several
6327 // characters. No matter, we calculate the exact length
6328 // of the result and try the whole thing again.
6329 //
6330 // Note that this leaves room for optimization. We could just
6331 // memcpy what we already have to the result string. Also,
6332 // the result string is the last object allocated we could
6333 // "realloc" it and probably, in the vast majority of cases,
6334 // extend the existing string to be able to hold the full
6335 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006336 int next_length = 0;
6337 if (has_next) {
6338 next_length = mapping->get(next, 0, chars);
6339 if (next_length == 0) next_length = 1;
6340 }
6341 int current_length = i + char_length + next_length;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006342 while (stream.HasMore()) {
6343 current = stream.GetNext();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006344 found_yuml |= (current == yuml_code);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006345 // NOTE: we use 0 as the next character here because, while
6346 // the next character may affect what a character converts to,
6347 // it does not in any case affect the length of what it convert
6348 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349 int char_length = mapping->get(current, 0, chars);
6350 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006351 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006352 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006353 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006354 return Failure::OutOfMemoryException(0x13);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006355 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006357 // Try again with the real length. Return signed if we need
6358 // to allocate a two-byte string for y-umlaut to uppercase.
6359 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length)
6360 : Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006361 } else {
6362 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006363 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006364 i++;
6365 }
6366 has_changed_character = true;
6367 }
6368 current = next;
6369 }
6370 if (has_changed_character) {
6371 return result;
6372 } else {
6373 // If we didn't actually change anything in doing the conversion
6374 // we simple return the result and let the converted string
6375 // become garbage; there is no reason to keep two identical strings
6376 // alive.
6377 return s;
6378 }
6379}
6380
6381
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006382namespace {
6383
lrn@chromium.org303ada72010-10-27 09:33:13 +00006384static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006385static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006386
6387// Given a word and two range boundaries returns a word with high bit
6388// set in every byte iff the corresponding input byte was strictly in
6389// the range (m, n). All the other bits in the result are cleared.
6390// This function is only useful when it can be inlined and the
6391// boundaries are statically known.
6392// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006393// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006394static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006395 // Use strict inequalities since in edge cases the function could be
6396 // further simplified.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006397 ASSERT(0 < m && m < n);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006398 // Has high bit set in every w byte less than n.
6399 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6400 // Has high bit set in every w byte greater than m.
6401 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6402 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6403}
6404
6405
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006406#ifdef DEBUG
6407static bool CheckFastAsciiConvert(char* dst,
6408 char* src,
6409 int length,
6410 bool changed,
6411 bool is_to_lower) {
6412 bool expected_changed = false;
6413 for (int i = 0; i < length; i++) {
6414 if (dst[i] == src[i]) continue;
6415 expected_changed = true;
6416 if (is_to_lower) {
6417 ASSERT('A' <= src[i] && src[i] <= 'Z');
6418 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6419 } else {
6420 ASSERT('a' <= src[i] && src[i] <= 'z');
6421 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6422 }
6423 }
6424 return (expected_changed == changed);
6425}
6426#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00006427
6428
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006429template<class Converter>
6430static bool FastAsciiConvert(char* dst,
6431 char* src,
6432 int length,
6433 bool* changed_out) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006434#ifdef DEBUG
6435 char* saved_dst = dst;
6436 char* saved_src = src;
6437#endif
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006438 DisallowHeapAllocation no_gc;
6439 // We rely on the distance between upper and lower case letters
6440 // being a known power of 2.
6441 ASSERT('a' - 'A' == (1 << 5));
6442 // Boundaries for the range of input characters than require conversion.
6443 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
6444 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
6445 bool changed = false;
6446 uintptr_t or_acc = 0;
6447 char* const limit = src + length;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006448#ifdef V8_HOST_CAN_READ_UNALIGNED
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006449 // Process the prefix of the input that requires no conversion one
6450 // (machine) word at a time.
6451 while (src <= limit - sizeof(uintptr_t)) {
6452 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6453 or_acc |= w;
6454 if (AsciiRangeMask(w, lo, hi) != 0) {
6455 changed = true;
6456 break;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006457 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006458 *reinterpret_cast<uintptr_t*>(dst) = w;
6459 src += sizeof(uintptr_t);
6460 dst += sizeof(uintptr_t);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006461 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006462 // Process the remainder of the input performing conversion when
6463 // required one word at a time.
6464 while (src <= limit - sizeof(uintptr_t)) {
6465 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6466 or_acc |= w;
6467 uintptr_t m = AsciiRangeMask(w, lo, hi);
6468 // The mask has high (7th) bit set in every byte that needs
6469 // conversion and we know that the distance between cases is
6470 // 1 << 5.
6471 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6472 src += sizeof(uintptr_t);
6473 dst += sizeof(uintptr_t);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006474 }
6475#endif
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006476 // Process the last few bytes of the input (or the whole input if
6477 // unaligned access is not supported).
6478 while (src < limit) {
6479 char c = *src;
6480 or_acc |= c;
6481 if (lo < c && c < hi) {
6482 c ^= (1 << 5);
6483 changed = true;
6484 }
6485 *dst = c;
6486 ++src;
6487 ++dst;
6488 }
6489 if ((or_acc & kAsciiMask) != 0) {
6490 return false;
6491 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006492
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006493 ASSERT(CheckFastAsciiConvert(
6494 saved_dst, saved_src, length, changed, Converter::kIsToLower));
lrn@chromium.org303ada72010-10-27 09:33:13 +00006495
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006496 *changed_out = changed;
6497 return true;
6498}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006499
6500} // namespace
6501
6502
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006503template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006504MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006505 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006506 Isolate* isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006507 unibrow::Mapping<Converter, 128>* mapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006508 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006509 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006510 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006511
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006512 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006513 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006514 if (length == 0) return s;
6515
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006516 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006517 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006518 // NOTE: This assumes that the upper/lower case of an ASCII
6519 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006520 // might break in the future if we implement more context and locale
6521 // dependent upper/lower conversions.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006522 if (s->IsSeqOneByteString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006523 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006524 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006525 if (!maybe_o->ToObject(&o)) return maybe_o;
6526 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006527 SeqOneByteString* result = SeqOneByteString::cast(o);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006528 bool has_changed_character;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006529 bool is_ascii = FastAsciiConvert<Converter>(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006530 reinterpret_cast<char*>(result->GetChars()),
6531 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
6532 length,
6533 &has_changed_character);
6534 // If not ASCII, we discard the result and take the 2 byte path.
6535 if (is_ascii) {
6536 return has_changed_character ? result : s;
6537 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006538 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006539
machenbach@chromium.org12014a42013-11-11 16:29:16 +00006540 String::Encoding result_encoding = s->IsOneByteRepresentation()
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006541 ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006542 Object* answer;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006543 { MaybeObject* maybe_answer = ConvertCaseHelper(
6544 isolate, s, result_encoding, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006545 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6546 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006547 if (answer->IsSmi()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006548 int new_length = Smi::cast(answer)->value();
6549 if (new_length < 0) {
6550 result_encoding = String::TWO_BYTE_ENCODING;
6551 new_length = -new_length;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006552 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006553 MaybeObject* maybe_answer = ConvertCaseHelper(
6554 isolate, s, result_encoding, new_length, length, mapping);
6555 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006556 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006557 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006558}
6559
6560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006561RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006562 return ConvertCase(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564}
6565
6566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006567RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006568 return ConvertCase(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570}
6571
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006572
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006573static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006574 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006575}
6576
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006578RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006579 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006580 ASSERT(args.length() == 3);
6581
yangguo@chromium.org49546742013-12-23 16:17:49 +00006582 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006583 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6584 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006585
yangguo@chromium.org49546742013-12-23 16:17:49 +00006586 string = FlattenGetString(string);
6587 int length = string->length();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006588
6589 int left = 0;
6590 if (trimLeft) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006591 while (left < length && IsTrimWhiteSpace(string->Get(left))) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006592 left++;
6593 }
6594 }
6595
6596 int right = length;
6597 if (trimRight) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006598 while (right > left && IsTrimWhiteSpace(string->Get(right - 1))) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006599 right--;
6600 }
6601 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00006602
6603 return *isolate->factory()->NewSubString(string, left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006604}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006607RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006609 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006610 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6611 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006612 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6613
6614 int subject_length = subject->length();
6615 int pattern_length = pattern->length();
6616 RUNTIME_ASSERT(pattern_length > 0);
6617
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006618 if (limit == 0xffffffffu) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006619 Handle<Object> cached_answer(
6620 RegExpResultsCache::Lookup(isolate->heap(),
6621 *subject,
6622 *pattern,
6623 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6624 isolate);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006625 if (*cached_answer != Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006626 // The cache FixedArray is a COW-array and can therefore be reused.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006627 Handle<JSArray> result =
6628 isolate->factory()->NewJSArrayWithElements(
6629 Handle<FixedArray>::cast(cached_answer));
6630 return *result;
6631 }
6632 }
6633
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006634 // The limit can be very large (0xffffffffu), but since the pattern
6635 // isn't empty, we can never create more parts than ~half the length
6636 // of the subject.
6637
6638 if (!subject->IsFlat()) FlattenString(subject);
6639
6640 static const int kMaxInitialListCapacity = 16;
6641
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006642 ZoneScope zone_scope(isolate->runtime_zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006643
6644 // Find (up to limit) indices of separator and end-of-string in subject
6645 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006646 ZoneList<int> indices(initial_capacity, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006647 if (!pattern->IsFlat()) FlattenString(pattern);
6648
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006649 FindStringIndicesDispatch(isolate, *subject, *pattern,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006650 &indices, limit, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006651
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006652 if (static_cast<uint32_t>(indices.length()) < limit) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006653 indices.Add(subject_length, zone_scope.zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006654 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006655
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006656 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006657
6658 // Create JSArray of substrings separated by separator.
6659 int part_count = indices.length();
6660
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006662 JSObject::EnsureCanContainHeapObjectElements(result);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006663 result->set_length(Smi::FromInt(part_count));
6664
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006665 ASSERT(result->HasFastObjectElements());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006666
6667 if (part_count == 1 && indices.at(0) == subject_length) {
6668 FixedArray::cast(result->elements())->set(0, *subject);
6669 return *result;
6670 }
6671
6672 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6673 int part_start = 0;
6674 for (int i = 0; i < part_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00006675 HandleScope local_loop_handle(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006676 int part_end = indices.at(i);
6677 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006678 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006679 elements->set(i, *substring);
6680 part_start = part_end + pattern_length;
6681 }
6682
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006683 if (limit == 0xffffffffu) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006684 if (result->HasFastObjectElements()) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006685 RegExpResultsCache::Enter(isolate->heap(),
6686 *subject,
6687 *pattern,
6688 *elements,
6689 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006690 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006691 }
6692
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006693 return *result;
6694}
6695
6696
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006697// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006698// one-char strings in the cache. Gives up on the first char that is
6699// not in the cache and fills the remainder with smi zeros. Returns
6700// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701static int CopyCachedAsciiCharsToArray(Heap* heap,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006702 const uint8_t* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006703 FixedArray* elements,
6704 int length) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006705 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 FixedArray* ascii_cache = heap->single_character_string_cache();
6707 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006708 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006709 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006710 for (i = 0; i < length; ++i) {
6711 Object* value = ascii_cache->get(chars[i]);
6712 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006713 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006714 }
6715 if (i < length) {
6716 ASSERT(Smi::FromInt(0) == 0);
6717 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6718 }
6719#ifdef DEBUG
6720 for (int j = 0; j < length; ++j) {
6721 Object* element = elements->get(j);
6722 ASSERT(element == Smi::FromInt(0) ||
6723 (element->IsString() && String::cast(element)->LooksValid()));
6724 }
6725#endif
6726 return i;
6727}
6728
6729
6730// Converts a String to JSArray.
6731// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006732RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006734 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006735 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006736 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006737
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006738 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006739 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006740
6741 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006742 int position = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006743 if (s->IsFlat() && s->IsOneByteRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006744 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006745 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 { MaybeObject* maybe_obj =
6747 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006748 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6749 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006750 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006751 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006752 String::FlatContent content = s->GetFlatContent();
6753 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006754 Vector<const uint8_t> chars = content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006755 // Note, this will initialize all elements (not only the prefix)
6756 // to prevent GC from seeing partially initialized array.
6757 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6758 chars.start(),
6759 *elements,
6760 length);
6761 } else {
6762 MemsetPointer(elements->data_start(),
6763 isolate->heap()->undefined_value(),
6764 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006765 }
6766 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006767 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006768 }
6769 for (int i = position; i < length; ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006770 Handle<Object> str =
6771 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006772 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006773 }
6774
6775#ifdef DEBUG
6776 for (int i = 0; i < length; ++i) {
6777 ASSERT(String::cast(elements->get(i))->length() == 1);
6778 }
6779#endif
6780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006782}
6783
6784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006785RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006786 SealHandleScope shs(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006787 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006788 CONVERT_ARG_CHECKED(String, value, 0);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006789 return value->ToObject(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006790}
6791
6792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006794 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006796 return char_length == 0;
6797}
6798
6799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006800RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006801 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 ASSERT(args.length() == 1);
6803
6804 Object* number = args[0];
6805 RUNTIME_ASSERT(number->IsNumber());
6806
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808}
6809
6810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006811RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006812 SealHandleScope shs(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00006813 ASSERT(args.length() == 1);
6814
6815 Object* number = args[0];
6816 RUNTIME_ASSERT(number->IsNumber());
6817
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006818 return isolate->heap()->NumberToString(
6819 number, false, isolate->heap()->GetPretenureMode());
ager@chromium.org357bf652010-04-12 11:30:10 +00006820}
6821
6822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006823RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006824 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 ASSERT(args.length() == 1);
6826
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006827 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006828
6829 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6830 if (number > 0 && number <= Smi::kMaxValue) {
6831 return Smi::FromInt(static_cast<int>(number));
6832 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834}
6835
6836
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006837// ES6 draft 9.1.11
6838RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006839 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006840 ASSERT(args.length() == 1);
6841
6842 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6843
6844 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6845 if (number > 0 && number <= Smi::kMaxValue) {
6846 return Smi::FromInt(static_cast<int>(number));
6847 }
6848 if (number <= 0) {
6849 return Smi::FromInt(0);
6850 }
6851 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6852}
6853
6854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006855RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006856 SealHandleScope shs(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006857 ASSERT(args.length() == 1);
6858
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006859 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006860
6861 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6862 if (number > 0 && number <= Smi::kMaxValue) {
6863 return Smi::FromInt(static_cast<int>(number));
6864 }
6865
6866 double double_value = DoubleToInteger(number);
6867 // Map both -0 and +0 to +0.
6868 if (double_value == 0) double_value = 0;
6869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006870 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006871}
6872
6873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006874RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006875 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876 ASSERT(args.length() == 1);
6877
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006878 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880}
6881
6882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006883RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006884 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 ASSERT(args.length() == 1);
6886
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006887 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006888
6889 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6890 if (number > 0 && number <= Smi::kMaxValue) {
6891 return Smi::FromInt(static_cast<int>(number));
6892 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006893 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006894}
6895
6896
ager@chromium.org870a0b62008-11-04 11:43:05 +00006897// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6898// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006899RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006900 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006901 ASSERT(args.length() == 1);
6902
6903 Object* obj = args[0];
6904 if (obj->IsSmi()) {
6905 return obj;
6906 }
6907 if (obj->IsHeapNumber()) {
6908 double value = HeapNumber::cast(obj)->value();
6909 int int_value = FastD2I(value);
6910 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6911 return Smi::FromInt(int_value);
6912 }
6913 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006915}
6916
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006919 SealHandleScope shs(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006920 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006921 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006922}
6923
6924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006925RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006926 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006927 ASSERT(args.length() == 2);
6928
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006929 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6930 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006931 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932}
6933
6934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006935RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006936 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006937 ASSERT(args.length() == 2);
6938
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006939 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6940 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006941 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942}
6943
6944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006945RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006946 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 ASSERT(args.length() == 2);
6948
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006949 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6950 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006951 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952}
6953
6954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006955RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006956 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 ASSERT(args.length() == 1);
6958
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006959 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961}
6962
6963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006964RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006965 SealHandleScope shs(isolate);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006966 ASSERT(args.length() == 0);
6967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006968 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006969}
6970
6971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006972RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006973 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006974 ASSERT(args.length() == 2);
6975
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006976 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6977 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979}
6980
6981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006983 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984 ASSERT(args.length() == 2);
6985
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006986 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6987 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988
ager@chromium.org3811b432009-10-28 14:53:37 +00006989 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006990 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006991 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992}
6993
6994
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006995RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006996 SealHandleScope shs(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006997 ASSERT(args.length() == 2);
6998
6999 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7000 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7001 return isolate->heap()->NumberFromInt32(x * y);
7002}
7003
7004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007005RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00007006 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 ASSERT(args.length() == 2);
yangguo@chromium.org49546742013-12-23 16:17:49 +00007008 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
7009 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 isolate->counters()->string_add_runtime()->Increment();
yangguo@chromium.org49546742013-12-23 16:17:49 +00007011 return *isolate->factory()->NewConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012}
7013
7014
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007015template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007016static inline void StringBuilderConcatHelper(String* special,
7017 sinkchar* sink,
7018 FixedArray* fixed_array,
7019 int array_length) {
7020 int position = 0;
7021 for (int i = 0; i < array_length; i++) {
7022 Object* element = fixed_array->get(i);
7023 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007024 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007025 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007026 int pos;
7027 int len;
7028 if (encoded_slice > 0) {
7029 // Position and length encoded in one smi.
7030 pos = StringBuilderSubstringPosition::decode(encoded_slice);
7031 len = StringBuilderSubstringLength::decode(encoded_slice);
7032 } else {
7033 // Position and length encoded in two smis.
7034 Object* obj = fixed_array->get(++i);
7035 ASSERT(obj->IsSmi());
7036 pos = Smi::cast(obj)->value();
7037 len = -encoded_slice;
7038 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00007039 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00007040 sink + position,
7041 pos,
7042 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007043 position += len;
7044 } else {
7045 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007046 int element_length = string->length();
7047 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007048 position += element_length;
7049 }
7050 }
7051}
7052
7053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007054RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007055 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007056 ASSERT(args.length() == 3);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007057 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007058 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007060 return Failure::OutOfMemoryException(0x14);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007061 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007062 int array_length = args.smi_at(1);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007063 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007064
7065 // This assumption is used by the slice encoding in one or two smis.
7066 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7067
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007068 JSObject::EnsureCanContainHeapObjectElements(array);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007069
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007070 int special_length = special->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007071 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007072 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073 }
7074 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007075 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007076 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007077 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078
7079 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007080 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 } else if (array_length == 1) {
7082 Object* first = fixed_array->get(0);
7083 if (first->IsString()) return first;
7084 }
7085
danno@chromium.orgf005df62013-04-30 16:36:45 +00007086 bool one_byte = special->HasOnlyOneByteChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087 int position = 0;
7088 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007089 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090 Object* elt = fixed_array->get(i);
7091 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007092 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007093 int smi_value = Smi::cast(elt)->value();
7094 int pos;
7095 int len;
7096 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007097 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007098 pos = StringBuilderSubstringPosition::decode(smi_value);
7099 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007100 } else {
7101 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007102 len = -smi_value;
7103 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007104 i++;
7105 if (i >= array_length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007106 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007107 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007108 Object* next_smi = fixed_array->get(i);
7109 if (!next_smi->IsSmi()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007110 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007111 }
7112 pos = Smi::cast(next_smi)->value();
7113 if (pos < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007114 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007115 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007117 ASSERT(pos >= 0);
7118 ASSERT(len >= 0);
7119 if (pos > special_length || len > special_length - pos) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007120 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007121 }
7122 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123 } else if (elt->IsString()) {
7124 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007125 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007126 increment = element_length;
danno@chromium.orgf005df62013-04-30 16:36:45 +00007127 if (one_byte && !element->HasOnlyOneByteChars()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007128 one_byte = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007129 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007131 ASSERT(!elt->IsTheHole());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007132 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007134 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007135 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007136 return Failure::OutOfMemoryException(0x15);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00007137 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007138 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007139 }
7140
7141 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007142 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007143
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007144 if (one_byte) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145 { MaybeObject* maybe_object =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007146 isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007147 if (!maybe_object->ToObject(&object)) return maybe_object;
7148 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007149 SeqOneByteString* answer = SeqOneByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007150 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007151 answer->GetChars(),
7152 fixed_array,
7153 array_length);
7154 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007155 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007156 { MaybeObject* maybe_object =
7157 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007158 if (!maybe_object->ToObject(&object)) return maybe_object;
7159 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007160 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007161 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007162 answer->GetChars(),
7163 fixed_array,
7164 array_length);
7165 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167}
7168
7169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007170RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007171 SealHandleScope shs(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007172 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007173 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007174 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007176 return Failure::OutOfMemoryException(0x16);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007177 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007178 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007179 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007180
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007181 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007182 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007183 }
7184 FixedArray* fixed_array = FixedArray::cast(array->elements());
7185 if (fixed_array->length() < array_length) {
7186 array_length = fixed_array->length();
7187 }
7188
7189 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007191 } else if (array_length == 1) {
7192 Object* first = fixed_array->get(0);
7193 if (first->IsString()) return first;
7194 }
7195
7196 int separator_length = separator->length();
7197 int max_nof_separators =
7198 (String::kMaxLength + separator_length - 1) / separator_length;
7199 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007201 return Failure::OutOfMemoryException(0x17);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007202 }
7203 int length = (array_length - 1) * separator_length;
7204 for (int i = 0; i < array_length; i++) {
7205 Object* element_obj = fixed_array->get(i);
7206 if (!element_obj->IsString()) {
7207 // TODO(1161): handle this case.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007208 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007209 }
7210 String* element = String::cast(element_obj);
7211 int increment = element->length();
7212 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007214 return Failure::OutOfMemoryException(0x18);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007215 }
7216 length += increment;
7217 }
7218
7219 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007220 { MaybeObject* maybe_object =
7221 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007222 if (!maybe_object->ToObject(&object)) return maybe_object;
7223 }
7224 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7225
7226 uc16* sink = answer->GetChars();
7227#ifdef DEBUG
7228 uc16* end = sink + length;
7229#endif
7230
7231 String* first = String::cast(fixed_array->get(0));
7232 int first_length = first->length();
7233 String::WriteToFlat(first, sink, 0, first_length);
7234 sink += first_length;
7235
7236 for (int i = 1; i < array_length; i++) {
7237 ASSERT(sink + separator_length <= end);
7238 String::WriteToFlat(separator, sink, 0, separator_length);
7239 sink += separator_length;
7240
7241 String* element = String::cast(fixed_array->get(i));
7242 int element_length = element->length();
7243 ASSERT(sink + element_length <= end);
7244 String::WriteToFlat(element, sink, 0, element_length);
7245 sink += element_length;
7246 }
7247 ASSERT(sink == end);
7248
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007249 // Use %_FastAsciiArrayJoin instead.
7250 ASSERT(!answer->IsOneByteRepresentation());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007251 return answer;
7252}
7253
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007254template <typename Char>
7255static void JoinSparseArrayWithSeparator(FixedArray* elements,
7256 int elements_length,
7257 uint32_t array_length,
7258 String* separator,
7259 Vector<Char> buffer) {
7260 int previous_separator_position = 0;
7261 int separator_length = separator->length();
7262 int cursor = 0;
7263 for (int i = 0; i < elements_length; i += 2) {
7264 int position = NumberToInt32(elements->get(i));
7265 String* string = String::cast(elements->get(i + 1));
7266 int string_length = string->length();
7267 if (string->length() > 0) {
7268 while (previous_separator_position < position) {
7269 String::WriteToFlat<Char>(separator, &buffer[cursor],
7270 0, separator_length);
7271 cursor += separator_length;
7272 previous_separator_position++;
7273 }
7274 String::WriteToFlat<Char>(string, &buffer[cursor],
7275 0, string_length);
7276 cursor += string->length();
7277 }
7278 }
7279 if (separator_length > 0) {
7280 // Array length must be representable as a signed 32-bit number,
7281 // otherwise the total string length would have been too large.
7282 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7283 int last_array_index = static_cast<int>(array_length - 1);
7284 while (previous_separator_position < last_array_index) {
7285 String::WriteToFlat<Char>(separator, &buffer[cursor],
7286 0, separator_length);
7287 cursor += separator_length;
7288 previous_separator_position++;
7289 }
7290 }
7291 ASSERT(cursor <= buffer.length());
7292}
7293
7294
7295RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007296 SealHandleScope shs(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007297 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007298 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007299 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007300 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007301 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007302 // elements_array is fast-mode JSarray of alternating positions
7303 // (increasing order) and strings.
7304 // array_length is length of original array (used to add separators);
7305 // separator is string to put between elements. Assumed to be non-empty.
7306
7307 // Find total length of join result.
7308 int string_length = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007309 bool is_ascii = separator->IsOneByteRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007310 int max_string_length;
7311 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007312 max_string_length = SeqOneByteString::kMaxLength;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007313 } else {
7314 max_string_length = SeqTwoByteString::kMaxLength;
7315 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007316 bool overflow = false;
7317 CONVERT_NUMBER_CHECKED(int, elements_length,
7318 Int32, elements_array->length());
7319 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7320 FixedArray* elements = FixedArray::cast(elements_array->elements());
7321 for (int i = 0; i < elements_length; i += 2) {
7322 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007323 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7324 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007325 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007326 if (is_ascii && !string->IsOneByteRepresentation()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007327 is_ascii = false;
7328 max_string_length = SeqTwoByteString::kMaxLength;
7329 }
7330 if (length > max_string_length ||
7331 max_string_length - length < string_length) {
7332 overflow = true;
7333 break;
7334 }
7335 string_length += length;
7336 }
7337 int separator_length = separator->length();
7338 if (!overflow && separator_length > 0) {
7339 if (array_length <= 0x7fffffffu) {
7340 int separator_count = static_cast<int>(array_length) - 1;
7341 int remaining_length = max_string_length - string_length;
7342 if ((remaining_length / separator_length) >= separator_count) {
7343 string_length += separator_length * (array_length - 1);
7344 } else {
7345 // Not room for the separators within the maximal string length.
7346 overflow = true;
7347 }
7348 } else {
7349 // Nonempty separator and at least 2^31-1 separators necessary
7350 // means that the string is too large to create.
7351 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7352 overflow = true;
7353 }
7354 }
7355 if (overflow) {
7356 // Throw OutOfMemory exception for creating too large a string.
7357 V8::FatalProcessOutOfMemory("Array join result too large.");
7358 }
7359
7360 if (is_ascii) {
7361 MaybeObject* result_allocation =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007362 isolate->heap()->AllocateRawOneByteString(string_length);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007363 if (result_allocation->IsFailure()) return result_allocation;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007364 SeqOneByteString* result_string =
7365 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007366 JoinSparseArrayWithSeparator<uint8_t>(elements,
7367 elements_length,
7368 array_length,
7369 separator,
7370 Vector<uint8_t>(
7371 result_string->GetChars(),
7372 string_length));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007373 return result_string;
7374 } else {
7375 MaybeObject* result_allocation =
7376 isolate->heap()->AllocateRawTwoByteString(string_length);
7377 if (result_allocation->IsFailure()) return result_allocation;
7378 SeqTwoByteString* result_string =
7379 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7380 JoinSparseArrayWithSeparator<uc16>(elements,
7381 elements_length,
7382 array_length,
7383 separator,
7384 Vector<uc16>(result_string->GetChars(),
7385 string_length));
7386 return result_string;
7387 }
7388}
7389
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007392 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 ASSERT(args.length() == 2);
7394
7395 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7396 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398}
7399
7400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007401RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007402 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403 ASSERT(args.length() == 2);
7404
7405 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7406 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007407 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408}
7409
7410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007411RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007412 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 ASSERT(args.length() == 2);
7414
7415 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7416 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007417 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418}
7419
7420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007421RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007422 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423 ASSERT(args.length() == 2);
7424
7425 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7426 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428}
7429
7430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007432 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433 ASSERT(args.length() == 2);
7434
7435 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7436 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438}
7439
7440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007441RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007442 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443 ASSERT(args.length() == 2);
7444
7445 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7446 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007447 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448}
7449
7450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007451RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007452 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453 ASSERT(args.length() == 2);
7454
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007455 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7456 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007457 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7458 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 if (x == y) return Smi::FromInt(EQUAL);
7460 Object* result;
7461 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7462 result = Smi::FromInt(EQUAL);
7463 } else {
7464 result = Smi::FromInt(NOT_EQUAL);
7465 }
7466 return result;
7467}
7468
7469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007470RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007471 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472 ASSERT(args.length() == 2);
7473
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007474 CONVERT_ARG_CHECKED(String, x, 0);
7475 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007477 bool not_equal = !x->Equals(y);
7478 // This is slightly convoluted because the value that signifies
7479 // equality is 0 and inequality is 1 so we have to negate the result
7480 // from String::Equals.
7481 ASSERT(not_equal == 0 || not_equal == 1);
7482 STATIC_CHECK(EQUAL == 0);
7483 STATIC_CHECK(NOT_EQUAL == 1);
7484 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007485}
7486
7487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007489 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490 ASSERT(args.length() == 3);
7491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007492 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7493 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007494 if (std::isnan(x) || std::isnan(y)) return args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495 if (x == y) return Smi::FromInt(EQUAL);
7496 if (isless(x, y)) return Smi::FromInt(LESS);
7497 return Smi::FromInt(GREATER);
7498}
7499
7500
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007501// Compare two Smis as if they were converted to strings and then
7502// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007503RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007504 SealHandleScope shs(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007505 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007506 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7507 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007508
7509 // If the integers are equal so are the string representations.
7510 if (x_value == y_value) return Smi::FromInt(EQUAL);
7511
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007512 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007513 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007514 if (x_value == 0 || y_value == 0)
7515 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007516
ager@chromium.org32912102009-01-16 10:38:43 +00007517 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007518 // smallest because the char code of '-' is less than the char code
7519 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007520
7521 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7522 // architectures using 32-bit Smis.
7523 uint32_t x_scaled = x_value;
7524 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007525 if (x_value < 0 || y_value < 0) {
7526 if (y_value >= 0) return Smi::FromInt(LESS);
7527 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007528 x_scaled = -x_value;
7529 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007530 }
7531
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007532 static const uint32_t kPowersOf10[] = {
7533 1, 10, 100, 1000, 10*1000, 100*1000,
7534 1000*1000, 10*1000*1000, 100*1000*1000,
7535 1000*1000*1000
7536 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007538 // If the integers have the same number of decimal digits they can be
7539 // compared directly as the numeric order is the same as the
7540 // lexicographic order. If one integer has fewer digits, it is scaled
7541 // by some power of 10 to have the same number of digits as the longer
7542 // integer. If the scaled integers are equal it means the shorter
7543 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007545 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7546 int x_log2 = IntegerLog2(x_scaled);
7547 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7548 x_log10 -= x_scaled < kPowersOf10[x_log10];
7549
7550 int y_log2 = IntegerLog2(y_scaled);
7551 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7552 y_log10 -= y_scaled < kPowersOf10[y_log10];
7553
7554 int tie = EQUAL;
7555
7556 if (x_log10 < y_log10) {
7557 // X has fewer digits. We would like to simply scale up X but that
7558 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7559 // be scaled up to 9_000_000_000. So we scale up by the next
7560 // smallest power and scale down Y to drop one digit. It is OK to
7561 // drop one digit from the longer integer since the final digit is
7562 // past the length of the shorter integer.
7563 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7564 y_scaled /= 10;
7565 tie = LESS;
7566 } else if (y_log10 < x_log10) {
7567 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7568 x_scaled /= 10;
7569 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007570 }
7571
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007572 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7573 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7574 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007575}
7576
7577
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007578static Object* StringCharacterStreamCompare(RuntimeState* state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007579 String* x,
7580 String* y) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007581 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
7582 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
7583 while (stream_x.HasMore() && stream_y.HasMore()) {
7584 int d = stream_x.GetNext() - stream_y.GetNext();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007585 if (d < 0) return Smi::FromInt(LESS);
7586 else if (d > 0) return Smi::FromInt(GREATER);
7587 }
7588
7589 // x is (non-trivial) prefix of y:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007590 if (stream_y.HasMore()) return Smi::FromInt(LESS);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007591 // y is prefix of x:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007592 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007593}
7594
7595
7596static Object* FlatStringCompare(String* x, String* y) {
7597 ASSERT(x->IsFlat());
7598 ASSERT(y->IsFlat());
7599 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7600 int prefix_length = x->length();
7601 if (y->length() < prefix_length) {
7602 prefix_length = y->length();
7603 equal_prefix_result = Smi::FromInt(GREATER);
7604 } else if (y->length() > prefix_length) {
7605 equal_prefix_result = Smi::FromInt(LESS);
7606 }
7607 int r;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007608 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007609 String::FlatContent x_content = x->GetFlatContent();
7610 String::FlatContent y_content = y->GetFlatContent();
7611 if (x_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007612 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007613 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007614 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007615 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007616 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007617 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007618 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7619 }
7620 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007621 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7622 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007623 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007624 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7625 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007626 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007627 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7628 }
7629 }
7630 Object* result;
7631 if (r == 0) {
7632 result = equal_prefix_result;
7633 } else {
7634 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7635 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007636 ASSERT(result ==
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007637 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007638 return result;
7639}
7640
7641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007642RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007643 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007644 ASSERT(args.length() == 2);
7645
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007646 CONVERT_ARG_CHECKED(String, x, 0);
7647 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007649 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007651 // A few fast case tests before we flatten.
7652 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007653 if (y->length() == 0) {
7654 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007655 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007656 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007657 return Smi::FromInt(LESS);
7658 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007659
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007660 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007661 if (d < 0) return Smi::FromInt(LESS);
7662 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007663
lrn@chromium.org303ada72010-10-27 09:33:13 +00007664 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007665 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007666 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007668 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007669 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007672 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007673 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007674}
7675
7676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007677RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007678 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007679 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007681
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007682 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007683 return isolate->heap()->AllocateHeapNumber(acos(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007684}
7685
7686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007687RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007688 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007689 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007690 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007691
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007692 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007693 return isolate->heap()->AllocateHeapNumber(asin(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694}
7695
7696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007697RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007698 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007699 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007701
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007702 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007703 return isolate->heap()->AllocateHeapNumber(atan(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007704}
7705
7706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707static const double kPiDividedBy4 = 0.78539816339744830962;
7708
7709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007710RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007711 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007712 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007713 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007715 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7716 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007717 double result;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007718 if (std::isinf(x) && std::isinf(y)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007719 // Make sure that the result in case of two infinite arguments
7720 // is a multiple of Pi / 4. The sign of the result is determined
7721 // by the first argument (x) and the sign of the second argument
7722 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723 int multiplier = (x < 0) ? -1 : 1;
7724 if (y < 0) multiplier *= 3;
7725 result = multiplier * kPiDividedBy4;
7726 } else {
7727 result = atan2(x, y);
7728 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007729 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730}
7731
7732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007733RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007734 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007736 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007737
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007738 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00007739 lazily_initialize_fast_exp();
7740 return isolate->heap()->NumberFromDouble(fast_exp(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007741}
7742
7743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007744RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007745 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007746 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007749 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007750 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007751}
7752
7753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007754RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007755 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007756 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007757 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007758
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007759 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00007760 return isolate->heap()->AllocateHeapNumber(log(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007761}
7762
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00007763
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007764// Slow version of Math.pow. We check for fast paths for special cases.
7765// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007766RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007767 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007768 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007769 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007770
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007771 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007772
7773 // If the second argument is a smi, it is much faster to call the
7774 // custom powi() function than the generic pow().
7775 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007776 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007778 }
7779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007780 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00007781 double result = power_helper(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007782 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007783 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784}
7785
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00007786
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007787// 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 +00007788// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007789RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007790 SealHandleScope shs(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007791 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007792 isolate->counters()->math_pow()->Increment();
7793
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007794 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7795 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007796 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007797 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007798 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007799 double result = power_double_double(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007800 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007801 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007802 }
7803}
7804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007806RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007807 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007808 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007809 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007810
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007811 if (!args[0]->IsHeapNumber()) {
7812 // Must be smi. Return the argument unchanged for all the other types
7813 // to make fuzz-natives test happy.
7814 return args[0];
7815 }
7816
7817 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7818
7819 double value = number->value();
7820 int exponent = number->get_exponent();
7821 int sign = number->get_sign();
7822
danno@chromium.org160a7b02011-04-18 15:51:38 +00007823 if (exponent < -1) {
7824 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7825 if (sign) return isolate->heap()->minus_zero_value();
7826 return Smi::FromInt(0);
7827 }
7828
7829 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7830 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007831 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007832 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007833 return Smi::FromInt(static_cast<int>(value + 0.5));
7834 }
7835
7836 // If the magnitude is big enough, there's no place for fraction part. If we
7837 // try to add 0.5 to this number, 1.0 will be added instead.
7838 if (exponent >= 52) {
7839 return number;
7840 }
7841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007843
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007844 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007845 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846}
7847
7848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007849RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007850 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007851 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007854 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007855 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007856}
7857
7858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007859RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007860 SealHandleScope shs(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007861 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007863 CONVERT_SMI_ARG_CHECKED(year, 0);
7864 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007865
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007866 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007867}
7868
7869
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007870RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7871 HandleScope scope(isolate);
7872 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007873
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007874 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7875 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7876 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007877
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007878 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007879
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007880 Object* value = NULL;
7881 bool is_value_nan = false;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007882 if (std::isnan(time)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007883 value = isolate->heap()->nan_value();
7884 is_value_nan = true;
7885 } else if (!is_utc &&
7886 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7887 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7888 value = isolate->heap()->nan_value();
7889 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007890 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007891 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7892 if (time < -DateCache::kMaxTimeInMs ||
7893 time > DateCache::kMaxTimeInMs) {
7894 value = isolate->heap()->nan_value();
7895 is_value_nan = true;
7896 } else {
7897 MaybeObject* maybe_result =
7898 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7899 if (!maybe_result->ToObject(&value)) return maybe_result;
7900 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007901 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007902 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007903 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007904}
7905
7906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007907RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007908 HandleScope scope(isolate);
7909 ASSERT(args.length() == 3);
7910
7911 Handle<JSFunction> callee = args.at<JSFunction>(0);
7912 Object** parameters = reinterpret_cast<Object**>(args[1]);
7913 const int argument_count = Smi::cast(args[2])->value();
7914
7915 Handle<JSObject> result =
7916 isolate->factory()->NewArgumentsObject(callee, argument_count);
7917 // Allocate the elements if needed.
7918 int parameter_count = callee->shared()->formal_parameter_count();
7919 if (argument_count > 0) {
7920 if (parameter_count > 0) {
7921 int mapped_count = Min(argument_count, parameter_count);
7922 Handle<FixedArray> parameter_map =
7923 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7924 parameter_map->set_map(
7925 isolate->heap()->non_strict_arguments_elements_map());
7926
7927 Handle<Map> old_map(result->map());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007928 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007929 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007930
7931 result->set_map(*new_map);
7932 result->set_elements(*parameter_map);
7933
7934 // Store the context and the arguments array at the beginning of the
7935 // parameter map.
7936 Handle<Context> context(isolate->context());
7937 Handle<FixedArray> arguments =
7938 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7939 parameter_map->set(0, *context);
7940 parameter_map->set(1, *arguments);
7941
7942 // Loop over the actual parameters backwards.
7943 int index = argument_count - 1;
7944 while (index >= mapped_count) {
7945 // These go directly in the arguments array and have no
7946 // corresponding slot in the parameter map.
7947 arguments->set(index, *(parameters - index - 1));
7948 --index;
7949 }
7950
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007951 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007952 while (index >= 0) {
7953 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007954 Handle<String> name(scope_info->ParameterName(index));
7955 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007956 bool duplicate = false;
7957 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007958 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007959 duplicate = true;
7960 break;
7961 }
7962 }
7963
7964 if (duplicate) {
7965 // This goes directly in the arguments array with a hole in the
7966 // parameter map.
7967 arguments->set(index, *(parameters - index - 1));
7968 parameter_map->set_the_hole(index + 2);
7969 } else {
7970 // The context index goes in the parameter map with a hole in the
7971 // arguments array.
7972 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007973 for (int j = 0; j < context_local_count; ++j) {
7974 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007975 context_index = j;
7976 break;
7977 }
7978 }
7979 ASSERT(context_index >= 0);
7980 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007981 parameter_map->set(index + 2, Smi::FromInt(
7982 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007983 }
7984
7985 --index;
7986 }
7987 } else {
7988 // If there is no aliasing, the arguments object elements are not
7989 // special in any way.
7990 Handle<FixedArray> elements =
7991 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7992 result->set_elements(*elements);
7993 for (int i = 0; i < argument_count; ++i) {
7994 elements->set(i, *(parameters - i - 1));
7995 }
7996 }
7997 }
7998 return *result;
7999}
8000
8001
8002RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008003 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008004 ASSERT(args.length() == 3);
8005
8006 JSFunction* callee = JSFunction::cast(args[0]);
8007 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008008 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008009
lrn@chromium.org303ada72010-10-27 09:33:13 +00008010 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 { MaybeObject* maybe_result =
8012 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008013 if (!maybe_result->ToObject(&result)) return maybe_result;
8014 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008015 // Allocate the elements if needed.
8016 if (length > 0) {
8017 // Allocate the fixed array.
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00008018 FixedArray* array;
8019 { MaybeObject* maybe_obj =
8020 isolate->heap()->AllocateUninitializedFixedArray(length);
8021 if (!maybe_obj->To(&array)) return maybe_obj;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008022 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008023
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008024 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008025 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008026 for (int i = 0; i < length; i++) {
8027 array->set(i, *--parameters, mode);
8028 }
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00008029 JSObject::cast(result)->set_elements(array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008030 }
8031 return result;
8032}
8033
8034
verwaest@chromium.org662436e2013-08-28 08:41:27 +00008035RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) {
8036 HandleScope scope(isolate);
8037 ASSERT(args.length() == 1);
8038 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8039 Handle<Context> context(isolate->context());
8040 PretenureFlag pretenure_flag = NOT_TENURED;
8041 Handle<JSFunction> result =
8042 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8043 context,
8044 pretenure_flag);
8045 return *result;
8046}
8047
8048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008049RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008050 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008051 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008052 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8053 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8054 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055
whesse@chromium.org7b260152011-06-20 15:33:18 +00008056 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008057 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008058 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008060 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8061 context,
8062 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 return *result;
8064}
8065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008067// Find the arguments of the JavaScript function invocation that called
8068// into C++ code. Collect these in a newly allocated array of handles (possibly
8069// prefixed by a number of empty handles).
8070static SmartArrayPointer<Handle<Object> > GetCallerArguments(
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008071 Isolate* isolate,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008072 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008073 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008074 // Find frame containing arguments passed to the caller.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008075 JavaScriptFrameIterator it(isolate);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008076 JavaScriptFrame* frame = it.frame();
8077 List<JSFunction*> functions(2);
8078 frame->GetFunctions(&functions);
8079 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008080 int inlined_jsframe_index = functions.length() - 1;
8081 JSFunction* inlined_function = functions[inlined_jsframe_index];
8082 Vector<SlotRef> args_slots =
8083 SlotRef::ComputeSlotMappingForArguments(
8084 frame,
8085 inlined_jsframe_index,
8086 inlined_function->shared()->formal_parameter_count());
8087
8088 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008089
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008090 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008091 SmartArrayPointer<Handle<Object> > param_data(
8092 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008093 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008094 Handle<Object> val = args_slots[i].GetValue(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008095 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008096 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008097
8098 args_slots.Dispose();
8099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008100 return param_data;
8101 } else {
8102 it.AdvanceToArgumentsFrame();
8103 frame = it.frame();
8104 int args_count = frame->ComputeParametersCount();
8105
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008106 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008107 SmartArrayPointer<Handle<Object> > param_data(
8108 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008109 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008110 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008111 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008112 }
8113 return param_data;
8114 }
8115}
8116
8117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008118RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8119 HandleScope scope(isolate);
8120 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008121 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008122 RUNTIME_ASSERT(args[3]->IsNumber());
8123 Handle<Object> bindee = args.at<Object>(1);
8124
8125 // TODO(lrn): Create bound function in C++ code from premade shared info.
8126 bound_function->shared()->set_bound(true);
8127 // Get all arguments of calling function (Function.prototype.bind).
8128 int argc = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008129 SmartArrayPointer<Handle<Object> > arguments =
8130 GetCallerArguments(isolate, 0, &argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008131 // Don't count the this-arg.
8132 if (argc > 0) {
8133 ASSERT(*arguments[0] == args[2]);
8134 argc--;
8135 } else {
8136 ASSERT(args[2]->IsUndefined());
8137 }
8138 // Initialize array of bindings (function, this, and any existing arguments
8139 // if the function was already bound).
8140 Handle<FixedArray> new_bindings;
8141 int i;
8142 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8143 Handle<FixedArray> old_bindings(
8144 JSFunction::cast(*bindee)->function_bindings());
8145 new_bindings =
8146 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008147 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8148 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008149 i = 0;
8150 for (int n = old_bindings->length(); i < n; i++) {
8151 new_bindings->set(i, old_bindings->get(i));
8152 }
8153 } else {
8154 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8155 new_bindings = isolate->factory()->NewFixedArray(array_size);
8156 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8157 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8158 i = 2;
8159 }
8160 // Copy arguments, skipping the first which is "this_arg".
8161 for (int j = 0; j < argc; j++, i++) {
8162 new_bindings->set(i, *arguments[j + 1]);
8163 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008164 new_bindings->set_map_no_write_barrier(
8165 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008166 bound_function->set_function_bindings(*new_bindings);
8167
8168 // Update length.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008169 Handle<String> length_string = isolate->factory()->length_string();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008170 Handle<Object> new_length(args.at<Object>(3));
8171 PropertyAttributes attr =
8172 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008173 ForceSetProperty(bound_function, length_string, new_length, attr);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008174 return *bound_function;
8175}
8176
8177
8178RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8179 HandleScope handles(isolate);
8180 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008181 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008182 if (callable->IsJSFunction()) {
8183 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8184 if (function->shared()->bound()) {
8185 Handle<FixedArray> bindings(function->function_bindings());
8186 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8187 return *isolate->factory()->NewJSArrayWithElements(bindings);
8188 }
8189 }
8190 return isolate->heap()->undefined_value();
8191}
8192
8193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008194RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008196 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008197 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008198 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008199 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008200
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008201 // The argument is a bound function. Extract its bound arguments
8202 // and callable.
8203 Handle<FixedArray> bound_args =
8204 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8205 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8206 Handle<Object> bound_function(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008207 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8208 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008209 ASSERT(!bound_function->IsJSFunction() ||
8210 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008212 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008213 SmartArrayPointer<Handle<Object> > param_data =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008214 GetCallerArguments(isolate, bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008215 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008216 param_data[i] = Handle<Object>(bound_args->get(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008217 JSFunction::kBoundArgumentsStartIndex + i), isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008218 }
8219
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008220 if (!bound_function->IsJSFunction()) {
8221 bool exception_thrown;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008222 bound_function = Execution::TryGetConstructorDelegate(isolate,
8223 bound_function,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008224 &exception_thrown);
8225 if (exception_thrown) return Failure::Exception();
8226 }
8227 ASSERT(bound_function->IsJSFunction());
8228
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008229 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008230 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008231 Execution::New(Handle<JSFunction>::cast(bound_function),
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008232 total_argc, param_data.get(), &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008233 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008234 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008235 }
8236 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008237 return *result;
8238}
8239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008241RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243 ASSERT(args.length() == 1);
8244
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008245 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008247 // If the constructor isn't a proper function we throw a type error.
8248 if (!constructor->IsJSFunction()) {
8249 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8250 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 isolate->factory()->NewTypeError("not_constructor", arguments);
8252 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008253 }
8254
8255 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008256
8257 // If function should not have prototype, construction is not allowed. In this
8258 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008259 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008260 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8261 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 isolate->factory()->NewTypeError("not_constructor", arguments);
8263 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008264 }
8265
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008266#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008268 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008269 if (debug->StepInActive()) {
8270 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008271 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008272#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008274 if (function->has_initial_map()) {
8275 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008276 // The 'Function' function ignores the receiver object when
8277 // called using 'new' and creates a new JSFunction object that
8278 // is returned. The receiver object is only used for error
8279 // reporting if an error occurs when constructing the new
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00008280 // JSFunction. Factory::NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008281 // allocate JSFunctions since it does not properly initialize
8282 // the shared part of the function. Since the receiver is
8283 // ignored anyway, we use the global object as the receiver
8284 // instead of a new JSFunction object. This way, errors are
8285 // reported the same way whether or not 'Function' is called
8286 // using 'new'.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008287 return isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008289 }
8290
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008291 // The function should be compiled for the optimization hints to be
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008292 // available.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008293 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008294
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008295 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008296 if (!function->has_initial_map() &&
8297 shared->IsInobjectSlackTrackingInProgress()) {
8298 // The tracking is already in progress for another function. We can only
8299 // track one initial_map at a time, so we force the completion before the
8300 // function is called as a constructor for the first time.
8301 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008302 }
8303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008304 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8305 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008306
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 isolate->counters()->constructed_objects()->Increment();
8308 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008309
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008310 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008316 ASSERT(args.length() == 1);
8317
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008318 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008319 function->shared()->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008321 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008322}
8323
8324
yangguo@chromium.org49546742013-12-23 16:17:49 +00008325RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileUnoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327 ASSERT(args.length() == 1);
8328
8329 Handle<JSFunction> function = args.at<JSFunction>(0);
8330#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008331 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008332 PrintF("[unoptimized: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008333 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008334 PrintF("]\n");
8335 }
8336#endif
8337
lrn@chromium.org34e60782011-09-15 07:25:40 +00008338 // Compile the target function.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008339 ASSERT(function->shared()->allows_lazy_compilation());
8340
8341 Handle<Code> code = Compiler::GetUnoptimizedCode(function);
8342 RETURN_IF_EMPTY_HANDLE(isolate, code);
8343 function->ReplaceCode(*code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 // All done. Return the compiled code.
8346 ASSERT(function->is_compiled());
yangguo@chromium.org49546742013-12-23 16:17:49 +00008347 ASSERT(function->code()->kind() == Code::FUNCTION ||
8348 (FLAG_always_opt &&
8349 function->code()->kind() == Code::OPTIMIZED_FUNCTION));
8350 return *code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351}
8352
8353
yangguo@chromium.org49546742013-12-23 16:17:49 +00008354RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileOptimized) {
8355 HandleScope scope(isolate);
8356 ASSERT(args.length() == 2);
8357 Handle<JSFunction> function = args.at<JSFunction>(0);
8358 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008359
yangguo@chromium.org49546742013-12-23 16:17:49 +00008360 Handle<Code> unoptimized(function->shared()->code());
8361 if (!function->shared()->is_compiled()) {
8362 // If the function is not compiled, do not optimize.
8363 // This can happen if the debugger is activated and
8364 // the function is returned to the not compiled state.
8365 // TODO(yangguo): reconsider this.
8366 function->ReplaceCode(function->shared()->code());
8367 } else if (!isolate->use_crankshaft() ||
8368 function->shared()->optimization_disabled() ||
8369 isolate->DebuggerHasBreakPoints()) {
8370 // If the function is not optimizable or debugger is active continue
8371 // using the code from the full compiler.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008372 if (FLAG_trace_opt) {
8373 PrintF("[failed to optimize ");
8374 function->PrintName();
8375 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
ulan@chromium.org750145a2013-03-07 15:14:13 +00008376 function->shared()->optimization_disabled() ? "F" : "T",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008377 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008378 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008379 function->ReplaceCode(*unoptimized);
8380 } else {
8381 Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT
8382 : Compiler::NOT_CONCURRENT;
8383 Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, mode);
8384 function->ReplaceCode(code.is_null() ? *unoptimized : *code);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008385 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00008386
yangguo@chromium.org49546742013-12-23 16:17:49 +00008387 ASSERT(function->code()->kind() == Code::FUNCTION ||
8388 function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
8389 function->IsInOptimizationQueue());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008390 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008391}
8392
8393
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008394class ActivationsFinder : public ThreadVisitor {
8395 public:
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008396 Code* code_;
8397 bool has_code_activations_;
8398
8399 explicit ActivationsFinder(Code* code)
8400 : code_(code),
8401 has_code_activations_(false) { }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008402
8403 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008404 JavaScriptFrameIterator it(isolate, top);
8405 VisitFrames(&it);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008406 }
8407
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008408 void VisitFrames(JavaScriptFrameIterator* it) {
8409 for (; !it->done(); it->Advance()) {
8410 JavaScriptFrame* frame = it->frame();
8411 if (code_->contains(frame->pc())) has_code_activations_ = true;
8412 }
8413 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008414};
8415
8416
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008417RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008418 HandleScope scope(isolate);
8419 ASSERT(args.length() == 0);
8420 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008421 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008422 delete deoptimizer;
8423 return isolate->heap()->undefined_value();
8424}
8425
8426
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008427RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8428 HandleScope scope(isolate);
8429 ASSERT(args.length() == 1);
8430 RUNTIME_ASSERT(args[0]->IsSmi());
8431 Deoptimizer::BailoutType type =
8432 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8433 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008434 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008435
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008436 Handle<JSFunction> function = deoptimizer->function();
8437 Handle<Code> optimized_code = deoptimizer->compiled_code();
8438
8439 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8440 ASSERT(type == deoptimizer->bailout_type());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008441
8442 // Make sure to materialize objects before causing any allocation.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008443 JavaScriptFrameIterator it(isolate);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008444 deoptimizer->MaterializeHeapObjects(&it);
8445 delete deoptimizer;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008446
8447 JavaScriptFrame* frame = it.frame();
8448 RUNTIME_ASSERT(frame->function()->IsJSFunction());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008449 ASSERT(frame->function() == *function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450
8451 // Avoid doing too much work when running with --always-opt and keep
8452 // the optimized code around.
8453 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008454 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 }
8456
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008457 // Search for other activations of the same function and code.
8458 ActivationsFinder activations_finder(*optimized_code);
8459 activations_finder.VisitFrames(&it);
8460 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008461
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008462 if (!activations_finder.has_code_activations_) {
8463 if (function->code() == *optimized_code) {
8464 if (FLAG_trace_deopt) {
8465 PrintF("[removing optimized code for: ");
8466 function->PrintName();
8467 PrintF("]\n");
8468 }
8469 function->ReplaceCode(function->shared()->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008470 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00008471 } else {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008472 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8473 // unconditionally if the code is not already marked for deoptimization.
8474 // If there is an index by shared function info, all the better.
lrn@chromium.org34e60782011-09-15 07:25:40 +00008475 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008476 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008477 // Evict optimized code for this function from the cache so that it doesn't
8478 // get used for new closures.
8479 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8480 "notify deoptimized");
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483}
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008489 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491
8492 Deoptimizer::DeoptimizeFunction(*function);
8493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008494 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495}
8496
8497
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008498RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8499 HandleScope scope(isolate);
8500 ASSERT(args.length() == 1);
8501 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8502 Code* unoptimized = function->shared()->code();
8503 if (unoptimized->kind() == Code::FUNCTION) {
8504 unoptimized->ClearInlineCaches();
8505 unoptimized->ClearTypeFeedbackCells(isolate->heap());
8506 }
8507 return isolate->heap()->undefined_value();
8508}
8509
8510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008511RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008512 SealHandleScope shs(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008513#if defined(USE_SIMULATOR)
8514 return isolate->heap()->true_value();
8515#else
8516 return isolate->heap()->false_value();
8517#endif
8518}
8519
8520
rossberg@chromium.org92597162013-08-23 13:28:00 +00008521RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008522 HandleScope scope(isolate);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00008523 return isolate->concurrent_recompilation_enabled()
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008524 ? isolate->heap()->true_value() : isolate->heap()->false_value();
8525}
8526
8527
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8529 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008530 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008531 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008532
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008533 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008534 function->MarkForOptimization();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008535
8536 Code* unoptimized = function->shared()->code();
8537 if (args.length() == 2 &&
8538 unoptimized->kind() == Code::FUNCTION) {
8539 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008540 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008541 // Start patching from the currently patched loop nesting level.
8542 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008543 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008544 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00008545 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8546 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8547 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008548 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) &&
8549 isolate->concurrent_recompilation_enabled()) {
8550 function->MarkForConcurrentOptimization();
ulan@chromium.org750145a2013-03-07 15:14:13 +00008551 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008552 }
8553
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008554 return isolate->heap()->undefined_value();
8555}
8556
8557
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008558RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008559 HandleScope scope(isolate);
8560 ASSERT(args.length() == 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008561 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8562 ASSERT(!function->IsOptimized());
8563 function->shared()->set_optimization_disabled(true);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008564 return isolate->heap()->undefined_value();
8565}
8566
8567
lrn@chromium.org1c092762011-05-09 09:42:16 +00008568RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8569 HandleScope scope(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008570 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008571 if (!isolate->use_crankshaft()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00008572 return Smi::FromInt(4); // 4 == "never".
8573 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008574 bool sync_with_compiler_thread = true;
8575 if (args.length() == 2) {
8576 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8577 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8578 sync_with_compiler_thread = false;
8579 }
8580 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008581 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00008582 if (isolate->concurrent_recompilation_enabled() &&
8583 sync_with_compiler_thread) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008584 while (function->IsInOptimizationQueue()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008585 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8586 OS::Sleep(50);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008587 }
8588 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00008589 if (FLAG_always_opt) {
8590 // We may have always opt, but that is more best-effort than a real
8591 // promise, so we still say "no" if it is not optimized.
8592 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8593 : Smi::FromInt(2); // 2 == "no".
8594 }
jkummerow@chromium.org10480472013-07-17 08:22:15 +00008595 if (FLAG_deopt_every_n_times) {
8596 return Smi::FromInt(6); // 6 == "maybe deopted".
8597 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00008598 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8599 : Smi::FromInt(2); // 2 == "no".
8600}
8601
8602
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00008603RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
8604 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8605 isolate->optimizing_compiler_thread()->Unblock();
8606 return isolate->heap()->undefined_value();
8607}
8608
8609
lrn@chromium.org1c092762011-05-09 09:42:16 +00008610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8611 HandleScope scope(isolate);
8612 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008613 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008614 return Smi::FromInt(function->shared()->opt_count());
8615}
8616
8617
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008618static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8619 Handle<JSFunction> function,
yangguo@chromium.org49546742013-12-23 16:17:49 +00008620 Handle<Code> current_code) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008621 // Keep track of whether we've succeeded in optimizing.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008622 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008623 // If we are trying to do OSR when there are already optimized
8624 // activations of the function, it means (a) the function is directly or
8625 // indirectly recursive and (b) an optimized invocation has been
8626 // deoptimized so that we are currently in an unoptimized activation.
8627 // Check for optimized activations of this function.
8628 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8629 JavaScriptFrame* frame = it.frame();
8630 if (frame->is_optimized() && frame->function() == *function) return false;
8631 }
8632
8633 return true;
8634}
8635
8636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008637RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008638 HandleScope scope(isolate);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008639 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008640 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +00008641 Handle<Code> caller_code(function->shared()->code());
8642
8643 // We're not prepared to handle a function with arguments object.
8644 ASSERT(!function->shared()->uses_arguments());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008645
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008646 // Passing the PC in the javascript frame from the caller directly is
8647 // not GC safe, so we walk the stack to get it.
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008648 JavaScriptFrameIterator it(isolate);
8649 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008650 if (!caller_code->contains(frame->pc())) {
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008651 // Code on the stack may not be the code object referenced by the shared
8652 // function info. It may have been replaced to include deoptimization data.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008653 caller_code = Handle<Code>(frame->LookupCode());
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008654 }
8655
yangguo@chromium.org49546742013-12-23 16:17:49 +00008656 uint32_t pc_offset = static_cast<uint32_t>(
8657 frame->pc() - caller_code->instruction_start());
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008658
8659#ifdef DEBUG
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008660 ASSERT_EQ(frame->function(), *function);
yangguo@chromium.org49546742013-12-23 16:17:49 +00008661 ASSERT_EQ(frame->LookupCode(), *caller_code);
8662 ASSERT(caller_code->contains(frame->pc()));
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008663#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008664
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008665
yangguo@chromium.org49546742013-12-23 16:17:49 +00008666 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
8667 ASSERT(!ast_id.IsNone());
8668
8669 Compiler::ConcurrencyMode mode = isolate->concurrent_osr_enabled()
8670 ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008671 Handle<Code> result = Handle<Code>::null();
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008672
yangguo@chromium.org49546742013-12-23 16:17:49 +00008673 OptimizedCompileJob* job = NULL;
8674 if (mode == Compiler::CONCURRENT) {
8675 // Gate the OSR entry with a stack check.
8676 BackEdgeTable::AddStackCheck(caller_code, pc_offset);
8677 // Poll already queued compilation jobs.
8678 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
8679 if (thread->IsQueuedForOSR(function, ast_id)) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008680 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008681 PrintF("[OSR - Still waiting for queued: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008682 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008683 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008684 }
8685 return NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008686 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008687
yangguo@chromium.org49546742013-12-23 16:17:49 +00008688 job = thread->FindReadyOSRCandidate(function, ast_id);
8689 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008690
yangguo@chromium.org49546742013-12-23 16:17:49 +00008691 if (job != NULL) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008692 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008693 PrintF("[OSR - Found ready: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008694 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008695 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008696 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008697 result = Compiler::GetConcurrentlyOptimizedCode(job);
8698 } else if (result.is_null() &&
8699 IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
8700 if (FLAG_trace_osr) {
8701 PrintF("[OSR - Compiling: ");
8702 function->PrintName();
8703 PrintF(" at AST id %d]\n", ast_id.ToInt());
8704 }
8705 result = Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
8706 if (result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
8707 // Optimization is queued. Return to check later.
8708 return NULL;
8709 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008710 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008711
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008712 // Revert the patched back edge table, regardless of whether OSR succeeds.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008713 BackEdgeTable::Revert(isolate, *caller_code);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008714
8715 // Check whether we ended up with usable optimized code.
8716 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8717 DeoptimizationInputData* data =
8718 DeoptimizationInputData::cast(result->deoptimization_data());
8719
8720 if (data->OsrPcOffset()->value() >= 0) {
8721 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8722 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008723 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008724 ast_id.ToInt(), data->OsrPcOffset()->value());
8725 }
8726 // TODO(titzer): this is a massive hack to make the deopt counts
8727 // match. Fix heuristics for reenabling optimizations!
8728 function->shared()->increment_deopt_count();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008729
8730 // TODO(titzer): Do not install code into the function.
8731 function->ReplaceCode(*result);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008732 return *result;
8733 }
8734 }
8735
yangguo@chromium.org49546742013-12-23 16:17:49 +00008736 // Failed.
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008737 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008738 PrintF("[OSR - Failed: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008739 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008740 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008741 }
8742
yangguo@chromium.org49546742013-12-23 16:17:49 +00008743 function->ReplaceCode(function->shared()->code());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008744 return NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008745}
8746
8747
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00008748RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) {
8749 SealHandleScope shs(isolate);
8750 ASSERT(args.length() == 2);
8751#ifdef DEBUG
8752 CONVERT_SMI_ARG_CHECKED(interval, 0);
8753 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8754 isolate->heap()->set_allocation_timeout(timeout);
8755 FLAG_gc_interval = interval;
8756#endif
8757 return isolate->heap()->undefined_value();
8758}
8759
8760
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008761RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008762 SealHandleScope shs(isolate);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008763 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8764 return isolate->heap()->undefined_value();
8765}
8766
8767
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008768RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008769 SealHandleScope shs(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008770 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8771 return isolate->heap()->nan_value();
8772}
8773
8774
danno@chromium.orgc612e022011-11-10 11:38:15 +00008775RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8776 HandleScope scope(isolate);
8777 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008778 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008779 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8780 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008781
8782 // If there are too many arguments, allocate argv via malloc.
8783 const int argv_small_size = 10;
8784 Handle<Object> argv_small_buffer[argv_small_size];
8785 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8786 Handle<Object>* argv = argv_small_buffer;
8787 if (argc > argv_small_size) {
8788 argv = new Handle<Object>[argc];
8789 if (argv == NULL) return isolate->StackOverflow();
8790 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8791 }
8792
8793 for (int i = 0; i < argc; ++i) {
8794 MaybeObject* maybe = args[1 + i];
8795 Object* object;
8796 if (!maybe->To<Object>(&object)) return maybe;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008797 argv[i] = Handle<Object>(object, isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008798 }
8799
8800 bool threw;
8801 Handle<JSReceiver> hfun(fun);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008802 Handle<Object> hreceiver(receiver, isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008803 Handle<Object> result = Execution::Call(
8804 isolate, hfun, hreceiver, argc, argv, &threw, true);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008805
8806 if (threw) return Failure::Exception();
8807 return *result;
8808}
8809
8810
lrn@chromium.org34e60782011-09-15 07:25:40 +00008811RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8812 HandleScope scope(isolate);
8813 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008814 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008815 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008816 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008817 CONVERT_SMI_ARG_CHECKED(offset, 3);
8818 CONVERT_SMI_ARG_CHECKED(argc, 4);
danno@chromium.org59400602013-08-13 17:09:37 +00008819 RUNTIME_ASSERT(offset >= 0);
8820 RUNTIME_ASSERT(argc >= 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008821
8822 // If there are too many arguments, allocate argv via malloc.
8823 const int argv_small_size = 10;
8824 Handle<Object> argv_small_buffer[argv_small_size];
8825 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8826 Handle<Object>* argv = argv_small_buffer;
8827 if (argc > argv_small_size) {
8828 argv = new Handle<Object>[argc];
8829 if (argv == NULL) return isolate->StackOverflow();
8830 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8831 }
8832
8833 for (int i = 0; i < argc; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008834 argv[i] = Object::GetElement(isolate, arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008835 }
8836
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008837 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008838 Handle<Object> result = Execution::Call(
8839 isolate, fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008840
8841 if (threw) return Failure::Exception();
8842 return *result;
8843}
8844
8845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008846RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008847 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 ASSERT(args.length() == 1);
8849 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008850 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008851}
8852
8853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008854RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008856 ASSERT(args.length() == 1);
8857 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008858 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0));
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008859}
8860
8861
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008862RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008863 SealHandleScope shs(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008864 ASSERT(args.length() == 2);
8865
8866 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8867 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
8868 Context* result;
8869 MaybeObject* maybe_result =
8870 isolate->heap()->AllocateGlobalContext(function, scope_info);
8871 if (!maybe_result->To(&result)) return maybe_result;
8872
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008873 ASSERT(function->context() == isolate->context());
8874 ASSERT(function->context()->global_object() == result->global_object());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008875 isolate->set_context(result);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008876 result->global_object()->set_global_context(result);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008877
8878 return result; // non-failure
8879}
8880
8881
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008882RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008883 SealHandleScope shs(isolate);
kasper.lund7276f142008-07-30 08:49:36 +00008884 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008885
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008886 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008887 int length = function->shared()->scope_info()->ContextLength();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008888 Context* result;
8889 MaybeObject* maybe_result =
8890 isolate->heap()->AllocateFunctionContext(length, function);
8891 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008892
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008893 isolate->set_context(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894
kasper.lund7276f142008-07-30 08:49:36 +00008895 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896}
8897
lrn@chromium.org303ada72010-10-27 09:33:13 +00008898
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008899RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008900 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008901 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008902 JSReceiver* extension_object;
8903 if (args[0]->IsJSReceiver()) {
8904 extension_object = JSReceiver::cast(args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008905 } else {
8906 // Convert the object to a proper JavaScript object.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008907 MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008908 if (!maybe_js_object->To(&extension_object)) {
8909 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8910 HandleScope scope(isolate);
8911 Handle<Object> handle = args.at<Object>(0);
8912 Handle<Object> result =
8913 isolate->factory()->NewTypeError("with_expression",
8914 HandleVector(&handle, 1));
8915 return isolate->Throw(*result);
8916 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008917 return maybe_js_object;
8918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008919 }
8920 }
8921
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008922 JSFunction* function;
8923 if (args[1]->IsSmi()) {
8924 // A smi sentinel indicates a context nested inside global code rather
8925 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008926 // gotten from the native context.
8927 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008928 } else {
8929 function = JSFunction::cast(args[1]);
8930 }
8931
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008932 Context* context;
8933 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008934 isolate->heap()->AllocateWithContext(function,
8935 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008936 extension_object);
8937 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008939 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008940}
8941
8942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008943RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008944 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008945 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008946 String* name = String::cast(args[0]);
8947 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008948 JSFunction* function;
8949 if (args[2]->IsSmi()) {
8950 // A smi sentinel indicates a context nested inside global code rather
8951 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008952 // gotten from the native context.
8953 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008954 } else {
8955 function = JSFunction::cast(args[2]);
8956 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008957 Context* context;
8958 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008959 isolate->heap()->AllocateCatchContext(function,
8960 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008961 name,
8962 thrown_object);
8963 if (!maybe_context->To(&context)) return maybe_context;
8964 isolate->set_context(context);
8965 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008966}
8967
8968
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008969RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008970 SealHandleScope shs(isolate);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008971 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008972 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008973 JSFunction* function;
8974 if (args[1]->IsSmi()) {
8975 // A smi sentinel indicates a context nested inside global code rather
8976 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008977 // gotten from the native context.
8978 function = isolate->context()->native_context()->closure();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008979 } else {
8980 function = JSFunction::cast(args[1]);
8981 }
8982 Context* context;
8983 MaybeObject* maybe_context =
8984 isolate->heap()->AllocateBlockContext(function,
8985 isolate->context(),
8986 scope_info);
8987 if (!maybe_context->To(&context)) return maybe_context;
8988 isolate->set_context(context);
8989 return context;
8990}
8991
8992
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008993RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008994 SealHandleScope shs(isolate);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008995 ASSERT(args.length() == 1);
8996 Object* obj = args[0];
8997 return isolate->heap()->ToBoolean(obj->IsJSModule());
8998}
8999
9000
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009001RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009002 SealHandleScope shs(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009003 ASSERT(args.length() == 2);
9004 CONVERT_SMI_ARG_CHECKED(index, 0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009005
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009006 if (!args[1]->IsScopeInfo()) {
9007 // Module already initialized. Find hosting context and retrieve context.
9008 Context* host = Context::cast(isolate->context())->global_context();
9009 Context* context = Context::cast(host->get(index));
9010 ASSERT(context->previous() == isolate->context());
9011 isolate->set_context(context);
9012 return context;
9013 }
9014
9015 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
9016
9017 // Allocate module context.
9018 HandleScope scope(isolate);
9019 Factory* factory = isolate->factory();
9020 Handle<Context> context = factory->NewModuleContext(scope_info);
9021 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
9022 context->set_module(*module);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009023 Context* previous = isolate->context();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009024 context->set_previous(previous);
9025 context->set_closure(previous->closure());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009026 context->set_global_object(previous->global_object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009027 isolate->set_context(*context);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009028
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009029 // Find hosting scope and initialize internal variable holding module there.
9030 previous->global_context()->set(index, *context);
9031
9032 return *context;
9033}
9034
9035
9036RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) {
9037 HandleScope scope(isolate);
9038 ASSERT(args.length() == 1);
9039 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9040 Context* host_context = isolate->context();
9041
9042 for (int i = 0; i < descriptions->length(); ++i) {
9043 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9044 int host_index = description->host_index();
9045 Handle<Context> context(Context::cast(host_context->get(host_index)));
9046 Handle<JSModule> module(context->module());
9047
9048 for (int j = 0; j < description->length(); ++j) {
9049 Handle<String> name(description->name(j));
9050 VariableMode mode = description->mode(j);
9051 int index = description->index(j);
9052 switch (mode) {
9053 case VAR:
9054 case LET:
9055 case CONST:
9056 case CONST_HARMONY: {
9057 PropertyAttributes attr =
9058 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9059 Handle<AccessorInfo> info =
9060 Accessors::MakeModuleExport(name, index, attr);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00009061 Handle<Object> result = JSObject::SetAccessor(module, info);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009062 ASSERT(!(result.is_null() || result->IsUndefined()));
9063 USE(result);
9064 break;
9065 }
9066 case MODULE: {
9067 Object* referenced_context = Context::cast(host_context)->get(index);
9068 Handle<JSModule> value(Context::cast(referenced_context)->module());
9069 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode);
9070 break;
9071 }
9072 case INTERNAL:
9073 case TEMPORARY:
9074 case DYNAMIC:
9075 case DYNAMIC_GLOBAL:
9076 case DYNAMIC_LOCAL:
9077 UNREACHABLE();
9078 }
9079 }
9080
9081 JSObject::PreventExtensions(module);
9082 }
9083
9084 ASSERT(!isolate->has_pending_exception());
9085 return isolate->heap()->undefined_value();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009086}
9087
9088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009089RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091 ASSERT(args.length() == 2);
9092
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009093 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9094 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009095
9096 int index;
9097 PropertyAttributes attributes;
9098 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009099 BindingFlags binding_flags;
9100 Handle<Object> holder = context->Lookup(name,
9101 flags,
9102 &index,
9103 &attributes,
9104 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009106 // If the slot was not found the result is true.
9107 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009108 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109 }
9110
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009111 // If the slot was found in a context, it should be DONT_DELETE.
9112 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009114 }
9115
9116 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009117 // the global object, or the subject of a with. Try to delete it
9118 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009119 Handle<JSObject> object = Handle<JSObject>::cast(holder);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009120 Handle<Object> result = JSReceiver::DeleteProperty(object, name);
9121 RETURN_IF_EMPTY_HANDLE(isolate, result);
9122 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123}
9124
9125
ager@chromium.orga1645e22009-09-09 19:27:10 +00009126// A mechanism to return a pair of Object pointers in registers (if possible).
9127// How this is achieved is calling convention-dependent.
9128// All currently supported x86 compiles uses calling conventions that are cdecl
9129// variants where a 64-bit value is returned in two 32-bit registers
9130// (edx:eax on ia32, r1:r0 on ARM).
9131// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9132// In Win64 calling convention, a struct of two pointers is returned in memory,
9133// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009134#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009135struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009136 MaybeObject* x;
9137 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009138};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009139
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009140
lrn@chromium.org303ada72010-10-27 09:33:13 +00009141static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009142 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009143 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9144 // In Win64 they are assigned to a hidden first argument.
9145 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009146}
9147#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009148typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009149static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009151 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009153#endif
9154
9155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156static inline MaybeObject* Unhole(Heap* heap,
9157 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009158 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9160 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162}
9163
9164
danno@chromium.org40cb8782011-05-25 07:58:50 +00009165static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9166 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009167 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009169 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009170 JSFunction* context_extension_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009171 top->native_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009172 // If the holder isn't a context extension object, we just return it
9173 // as the receiver. This allows arguments objects to be used as
9174 // receivers, but only if they are put in the context scope chain
9175 // explicitly via a with-statement.
9176 Object* constructor = holder->map()->constructor();
9177 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009178 // Fall back to using the global object as the implicit receiver if
9179 // the property turns out to be a local variable allocated in a
9180 // context extension object - introduced via eval. Implicit global
9181 // receivers are indicated with the hole value.
9182 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009183}
9184
9185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186static ObjectPair LoadContextSlotHelper(Arguments args,
9187 Isolate* isolate,
9188 bool throw_error) {
9189 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009190 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009192 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009193 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009196 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009197
9198 int index;
9199 PropertyAttributes attributes;
9200 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009201 BindingFlags binding_flags;
9202 Handle<Object> holder = context->Lookup(name,
9203 flags,
9204 &index,
9205 &attributes,
9206 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009207 if (isolate->has_pending_exception()) {
9208 return MakePair(Failure::Exception(), NULL);
9209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009211 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009213 ASSERT(holder->IsContext());
9214 // If the "property" we were looking for is a local variable, the
9215 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009216 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009217 // Use the hole as the receiver to signal that the receiver is implicit
9218 // and that the global receiver should be used (as distinguished from an
9219 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009220 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009221 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009222 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009223 switch (binding_flags) {
9224 case MUTABLE_CHECK_INITIALIZED:
9225 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9226 if (value->IsTheHole()) {
9227 Handle<Object> reference_error =
9228 isolate->factory()->NewReferenceError("not_defined",
9229 HandleVector(&name, 1));
9230 return MakePair(isolate->Throw(*reference_error), NULL);
9231 }
9232 // FALLTHROUGH
9233 case MUTABLE_IS_INITIALIZED:
9234 case IMMUTABLE_IS_INITIALIZED:
9235 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9236 ASSERT(!value->IsTheHole());
9237 return MakePair(value, *receiver);
9238 case IMMUTABLE_CHECK_INITIALIZED:
9239 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9240 case MISSING_BINDING:
9241 UNREACHABLE();
9242 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 }
9245
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009246 // Otherwise, if the slot was found the holder is a context extension
9247 // object, subject of a with, or a global object. We read the named
9248 // property from it.
9249 if (!holder.is_null()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009250 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00009251 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009252 // GetProperty below can cause GC.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009253 Handle<Object> receiver_handle(
9254 object->IsGlobalObject()
9255 ? GlobalObject::cast(*object)->global_receiver()
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009256 : object->IsJSProxy() ? static_cast<Object*>(*object)
9257 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009258 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009259
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009260 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009261 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009262 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009263 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 }
9265
9266 if (throw_error) {
9267 // The property doesn't exist - throw exception.
9268 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 isolate->factory()->NewReferenceError("not_defined",
9270 HandleVector(&name, 1));
9271 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009273 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 return MakePair(isolate->heap()->undefined_value(),
9275 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276 }
9277}
9278
9279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009280RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009281 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282}
9283
9284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009286 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287}
9288
9289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009290RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009292 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009294 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009295 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9296 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009297 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9298 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9299 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300
9301 int index;
9302 PropertyAttributes attributes;
9303 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009304 BindingFlags binding_flags;
9305 Handle<Object> holder = context->Lookup(name,
9306 flags,
9307 &index,
9308 &attributes,
9309 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009310 if (isolate->has_pending_exception()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009311
9312 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009313 // The property was found in a context slot.
9314 Handle<Context> context = Handle<Context>::cast(holder);
9315 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9316 context->get(index)->IsTheHole()) {
9317 Handle<Object> error =
9318 isolate->factory()->NewReferenceError("not_defined",
9319 HandleVector(&name, 1));
9320 return isolate->Throw(*error);
9321 }
9322 // Ignore if read_only variable.
9323 if ((attributes & READ_ONLY) == 0) {
9324 // Context is a fixed array and set cannot fail.
9325 context->set(index, *value);
9326 } else if (strict_mode == kStrictMode) {
9327 // Setting read only property in strict mode.
9328 Handle<Object> error =
9329 isolate->factory()->NewTypeError("strict_cannot_assign",
9330 HandleVector(&name, 1));
9331 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 }
9333 return *value;
9334 }
9335
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009336 // Slow case: The property is not in a context slot. It is either in a
9337 // context extension object, a property of the subject of a with, or a
9338 // property of the global object.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009339 Handle<JSReceiver> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009341 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009342 // The property exists on the holder.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009343 object = Handle<JSReceiver>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009345 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009347
9348 if (strict_mode == kStrictMode) {
9349 // Throw in strict mode (assignment to undefined variable).
9350 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009351 isolate->factory()->NewReferenceError(
9352 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009353 return isolate->Throw(*error);
9354 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009355 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356 attributes = NONE;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009357 object = Handle<JSReceiver>(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358 }
9359
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009360 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009361 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009362 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009363 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009364 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009365 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009366 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009367 // Setting read only property in strict mode.
9368 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009369 isolate->factory()->NewTypeError(
9370 "strict_cannot_assign", HandleVector(&name, 1));
9371 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372 }
9373 return *value;
9374}
9375
9376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009377RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009378 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009379 ASSERT(args.length() == 1);
9380
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009381 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009382}
9383
9384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009385RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009386 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387 ASSERT(args.length() == 1);
9388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009389 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390}
9391
9392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009393RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009394 SealHandleScope shs(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009395 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009396 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009397}
9398
9399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009401 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 ASSERT(args.length() == 1);
9403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 isolate->factory()->NewReferenceError("not_defined",
9407 HandleVector(&name, 1));
9408 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409}
9410
9411
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009412RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) {
9413 HandleScope scope(isolate);
9414 ASSERT(args.length() == 0);
9415 return isolate->Throw(*isolate->factory()->NewTypeError(
9416 "not_date_object", HandleVector<Object>(NULL, 0)));
9417}
9418
9419
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00009420RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
9421 HandleScope scope(isolate);
9422 ASSERT(args.length() == 1);
9423 CONVERT_SMI_ARG_CHECKED(message_id, 0);
9424 const char* message = GetBailoutReason(
9425 static_cast<BailoutReason>(message_id));
9426 Handle<Name> message_handle =
9427 isolate->factory()->NewStringFromAscii(CStrVector(message));
9428 return isolate->Throw(*message_handle);
9429}
9430
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009432RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009433 SealHandleScope shs(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009434 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435
9436 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437 if (isolate->stack_guard()->IsStackOverflow()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009438 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440
ulan@chromium.org812308e2012-02-29 15:58:45 +00009441 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442}
9443
9444
yangguo@chromium.org49546742013-12-23 16:17:49 +00009445RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallOptimizedCode) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00009446 HandleScope scope(isolate);
9447 ASSERT(args.length() == 1);
9448 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9449
9450 // First check if this is a real stack overflow.
9451 if (isolate->stack_guard()->IsStackOverflow()) {
9452 SealHandleScope shs(isolate);
9453 return isolate->StackOverflow();
9454 }
9455
9456 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9457 return (function->IsOptimized()) ? function->code()
9458 : function->shared()->code();
9459}
9460
9461
yangguo@chromium.org56454712012-02-16 15:33:53 +00009462RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009463 SealHandleScope shs(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009464 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009465 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009466}
9467
9468
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009469static int StackSize(Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009470 int n = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009471 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472 return n;
9473}
9474
9475
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009476static void PrintTransition(Isolate* isolate, Object* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477 // indentation
9478 { const int nmax = 80;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009479 int n = StackSize(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480 if (n <= nmax)
9481 PrintF("%4d:%*s", n, n, "");
9482 else
9483 PrintF("%4d:%*s", n, nmax, "...");
9484 }
9485
9486 if (result == NULL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009487 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009488 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009489 } else {
9490 // function result
9491 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009492 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 PrintF("\n");
9494 }
9495}
9496
9497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009498RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009499 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009500 ASSERT(args.length() == 0);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009501 PrintTransition(isolate, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503}
9504
9505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009507 SealHandleScope shs(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009508 PrintTransition(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009509 return args[0]; // return TOS
9510}
9511
9512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009513RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009514 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 ASSERT(args.length() == 1);
9516
9517#ifdef DEBUG
9518 if (args[0]->IsString()) {
9519 // If we have a string, assume it's a code "marker"
9520 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009521 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009523 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9524 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 } else {
9526 PrintF("DebugPrint: ");
9527 }
9528 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009529 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009530 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009531 HeapObject::cast(args[0])->map()->Print();
9532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009534 // ShortPrint is available in release mode. Print is not.
9535 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536#endif
9537 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009538 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539
9540 return args[0]; // return TOS
9541}
9542
9543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009544RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009545 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009546 ASSERT(args.length() == 0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00009547 isolate->PrintStack(stdout);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009549}
9550
9551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009552RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009553 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +00009554 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555
9556 // According to ECMA-262, section 15.9.1, page 117, the precision of
9557 // the number in a Date object representing a particular instant in
9558 // time is milliseconds. Therefore, we floor the result of getting
9559 // the OS time.
9560 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009561 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562}
9563
9564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009565RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009567 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009568
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009569 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009570 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009572 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009573
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009574 JSObject::EnsureCanContainHeapObjectElements(output);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009575 RUNTIME_ASSERT(output->HasFastObjectElements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009576
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009577 DisallowHeapAllocation no_gc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009578
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009579 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009580 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9581 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009582 String::FlatContent str_content = str->GetFlatContent();
9583 if (str_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009584 result = DateParser::Parse(str_content.ToOneByteVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009585 output_array,
9586 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009588 ASSERT(str_content.IsTwoByte());
9589 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009590 output_array,
9591 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009592 }
9593
9594 if (result) {
9595 return *output;
9596 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598 }
9599}
9600
9601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009602RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009603 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009604 ASSERT(args.length() == 1);
9605
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009606 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009607 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9608 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009609 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610}
9611
9612
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009613RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009614 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009615 ASSERT(args.length() == 1);
9616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009618 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9619
9620 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009621}
9622
9623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009624RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009625 SealHandleScope shs(isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009626 ASSERT(args.length() == 1);
9627 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009629 return JSGlobalObject::cast(global)->global_receiver();
9630}
9631
9632
jkummerow@chromium.org113035e2013-12-13 15:13:40 +00009633RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) {
9634 SealHandleScope shs(isolate);
9635 ASSERT(args.length() == 1);
9636 Object* global = args[0];
9637 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
9638 return isolate->heap()->ToBoolean(
9639 !JSGlobalObject::cast(global)->IsDetached());
9640}
9641
9642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009643RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009644 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009645 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009646 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009647
danno@chromium.org59400602013-08-13 17:09:37 +00009648 source = Handle<String>(FlattenGetString(source));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009649 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009650 Handle<Object> result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009651 if (source->IsSeqOneByteString()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009652 result = JsonParser<true>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009653 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009654 result = JsonParser<false>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009655 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009656 if (result.is_null()) {
9657 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009659 return Failure::Exception();
9660 }
9661 return *result;
9662}
9663
9664
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009665bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9666 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009667 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9668 // Check with callback if set.
9669 AllowCodeGenerationFromStringsCallback callback =
9670 isolate->allow_code_gen_callback();
9671 if (callback == NULL) {
9672 // No callback set and code generation disallowed.
9673 return false;
9674 } else {
9675 // Callback set. Let it decide if code generation is allowed.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009676 VMState<EXTERNAL> state(isolate);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009677 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009678 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009679}
9680
9681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009682RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 HandleScope scope(isolate);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009684 ASSERT_EQ(2, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009685 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009686 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009687
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009688 // Extract native context.
9689 Handle<Context> context(isolate->context()->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009690
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009691 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009692 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009693 if (context->allow_code_gen_from_strings()->IsFalse() &&
9694 !CodeGenerationFromStringsAllowed(isolate, context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009695 Handle<Object> error_message =
9696 context->ErrorMessageForCodeGenerationFromStrings();
9697 return isolate->Throw(*isolate->factory()->NewEvalError(
9698 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009699 }
9700
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009701 // Compile source string in the native context.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009702 ParseRestriction restriction = function_literal_only
9703 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
yangguo@chromium.org49546742013-12-23 16:17:49 +00009704 Handle<JSFunction> fun = Compiler::GetFunctionFromEval(
9705 source, context, CLASSIC_MODE, restriction, RelocInfo::kNoPosition);
9706 RETURN_IF_EMPTY_HANDLE(isolate, fun);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009707 return *fun;
9708}
9709
9710
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711static ObjectPair CompileGlobalEval(Isolate* isolate,
9712 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009713 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009714 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009715 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009716 Handle<Context> context = Handle<Context>(isolate->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009717 Handle<Context> native_context = Handle<Context>(context->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009718
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009719 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009720 // strings. Throw an exception if it doesn't.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009721 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9722 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009723 Handle<Object> error_message =
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00009724 native_context->ErrorMessageForCodeGenerationFromStrings();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009725 isolate->Throw(*isolate->factory()->NewEvalError(
9726 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009727 return MakePair(Failure::Exception(), NULL);
9728 }
9729
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009730 // Deal with a normal eval call with a string argument. Compile it
9731 // and return the compiled function bound in the local context.
yangguo@chromium.org49546742013-12-23 16:17:49 +00009732 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
9733 Handle<JSFunction> compiled = Compiler::GetFunctionFromEval(
9734 source, context, language_mode, restriction, scope_position);
9735 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, compiled,
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009736 MakePair(Failure::Exception(), NULL));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009737 return MakePair(*compiled, *receiver);
9738}
9739
9740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009741RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009742 HandleScope scope(isolate);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009743 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009744
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009745 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009746
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009747 // If "eval" didn't refer to the original GlobalEval, it's not a
9748 // direct call to eval.
9749 // (And even if it is, but the first argument isn't a string, just let
9750 // execution default to an indirect call to eval, which will also return
9751 // the first argument without doing anything).
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009752 if (*callee != isolate->native_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009753 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009754 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009755 }
9756
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009757 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009758 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009759 return CompileGlobalEval(isolate,
9760 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009761 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009762 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009763 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009764}
9765
9766
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009767// Allocate a block of memory in the given space (filled with a filler).
9768// Used as a fall-back for generated code when the space is full.
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009769static MaybeObject* Allocate(Isolate* isolate,
9770 int size,
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009771 bool double_align,
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009772 AllocationSpace space) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009773 Heap* heap = isolate->heap();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009774 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9775 RUNTIME_ASSERT(size > 0);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009776 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009777 HeapObject* allocation;
9778 { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space);
9779 if (!maybe_allocation->To(&allocation)) return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009780 }
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009781#ifdef DEBUG
9782 MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address());
9783 ASSERT(chunk->owner()->identity() == space);
9784#endif
9785 heap->CreateFillerObjectAt(allocation->address(), size);
9786 return allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009787}
9788
9789
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009790RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009791 SealHandleScope shs(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009792 ASSERT(args.length() == 1);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009793 CONVERT_SMI_ARG_CHECKED(size, 0);
9794 return Allocate(isolate, size, false, NEW_SPACE);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009795}
9796
9797
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009798RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInTargetSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009799 SealHandleScope shs(isolate);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009800 ASSERT(args.length() == 2);
9801 CONVERT_SMI_ARG_CHECKED(size, 0);
9802 CONVERT_SMI_ARG_CHECKED(flags, 1);
9803 bool double_align = AllocateDoubleAlignFlag::decode(flags);
9804 AllocationSpace space = AllocateTargetSpace::decode(flags);
9805 return Allocate(isolate, size, double_align, space);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009806}
9807
9808
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009809// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009810// array. Returns true if the element was pushed on the stack and
9811// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009812RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009813 HandleScope scope(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009814 ASSERT(args.length() == 2);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009815 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
9816 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009817 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009818 int length = Smi::cast(array->length())->value();
9819 FixedArray* elements = FixedArray::cast(array->elements());
9820 for (int i = 0; i < length; i++) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009821 if (elements->get(i) == *element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009822 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009823
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009824 // Strict not needed. Used for cycle detection in Array join implementation.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009825 RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length,
9826 element,
9827 kNonStrictMode,
9828 true));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009830}
9831
9832
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009833/**
9834 * A simple visitor visits every element of Array's.
9835 * The backend storage can be a fixed array for fast elements case,
9836 * or a dictionary for sparse array. Since Dictionary is a subtype
9837 * of FixedArray, the class can be used by both fast and slow cases.
9838 * The second parameter of the constructor, fast_elements, specifies
9839 * whether the storage is a FixedArray or Dictionary.
9840 *
9841 * An index limit is used to deal with the situation that a result array
9842 * length overflows 32-bit non-negative integer.
9843 */
9844class ArrayConcatVisitor {
9845 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 ArrayConcatVisitor(Isolate* isolate,
9847 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009848 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 isolate_(isolate),
9850 storage_(Handle<FixedArray>::cast(
9851 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009852 index_offset_(0u),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009853 fast_elements_(fast_elements),
9854 exceeds_array_limit_(false) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009855
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009856 ~ArrayConcatVisitor() {
9857 clear_storage();
9858 }
9859
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009860 void visit(uint32_t i, Handle<Object> elm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009861 if (i > JSObject::kMaxElementCount - index_offset_) {
9862 exceeds_array_limit_ = true;
9863 return;
9864 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009865 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009866
9867 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009868 if (index < static_cast<uint32_t>(storage_->length())) {
9869 storage_->set(index, *elm);
9870 return;
9871 }
9872 // Our initial estimate of length was foiled, possibly by
9873 // getters on the arrays increasing the length of later arrays
9874 // during iteration.
9875 // This shouldn't happen in anything but pathological cases.
9876 SetDictionaryMode(index);
9877 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009878 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009880 Handle<SeededNumberDictionary> dict(
9881 SeededNumberDictionary::cast(*storage_));
9882 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009883 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009884 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009885 // Dictionary needed to grow.
9886 clear_storage();
9887 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009889 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009890
9891 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009892 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9893 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009894 } else {
9895 index_offset_ += delta;
9896 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009897 }
9898
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009899 bool exceeds_array_limit() {
9900 return exceeds_array_limit_;
9901 }
9902
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009903 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009904 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009906 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 Handle<Map> map;
9908 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009909 map = isolate_->factory()->GetElementsTransitionMap(array,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009910 FAST_HOLEY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009911 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009912 map = isolate_->factory()->GetElementsTransitionMap(array,
9913 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009914 }
9915 array->set_map(*map);
9916 array->set_length(*length);
9917 array->set_elements(*storage_);
9918 return array;
9919 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009920
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009921 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 // Convert storage to dictionary mode.
9923 void SetDictionaryMode(uint32_t index) {
9924 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009925 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009926 Handle<SeededNumberDictionary> slow_storage(
9927 isolate_->factory()->NewSeededNumberDictionary(
9928 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009929 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9930 for (uint32_t i = 0; i < current_length; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009931 HandleScope loop_scope(isolate_);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009932 Handle<Object> element(current_storage->get(i), isolate_);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009933 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009934 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009936 if (!new_storage.is_identical_to(slow_storage)) {
9937 slow_storage = loop_scope.CloseAndEscape(new_storage);
9938 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009939 }
9940 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009941 clear_storage();
9942 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009943 fast_elements_ = false;
9944 }
9945
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009946 inline void clear_storage() {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00009947 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009948 }
9949
9950 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009951 storage_ = Handle<FixedArray>::cast(
9952 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009953 }
9954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009955 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009956 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009957 // Index after last seen index. Always less than or equal to
9958 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009959 uint32_t index_offset_;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009960 bool fast_elements_ : 1;
9961 bool exceeds_array_limit_ : 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009962};
9963
9964
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009965static uint32_t EstimateElementCount(Handle<JSArray> array) {
9966 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9967 int element_count = 0;
9968 switch (array->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009969 case FAST_SMI_ELEMENTS:
9970 case FAST_HOLEY_SMI_ELEMENTS:
9971 case FAST_ELEMENTS:
9972 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009973 // Fast elements can't have lengths that are not representable by
9974 // a 32-bit signed integer.
9975 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9976 int fast_length = static_cast<int>(length);
9977 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9978 for (int i = 0; i < fast_length; i++) {
9979 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009980 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009981 break;
9982 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009983 case FAST_DOUBLE_ELEMENTS:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009984 case FAST_HOLEY_DOUBLE_ELEMENTS: {
9985 // Fast elements can't have lengths that are not representable by
9986 // a 32-bit signed integer.
9987 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
9988 int fast_length = static_cast<int>(length);
9989 if (array->elements()->IsFixedArray()) {
9990 ASSERT(FixedArray::cast(array->elements())->length() == 0);
9991 break;
9992 }
9993 Handle<FixedDoubleArray> elements(
9994 FixedDoubleArray::cast(array->elements()));
9995 for (int i = 0; i < fast_length; i++) {
9996 if (!elements->is_the_hole(i)) element_count++;
9997 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009998 break;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009999 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010000 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010001 Handle<SeededNumberDictionary> dictionary(
10002 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 int capacity = dictionary->Capacity();
10004 for (int i = 0; i < capacity; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010005 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 if (dictionary->IsKey(*key)) {
10007 element_count++;
10008 }
10009 }
10010 break;
10011 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010012 case NON_STRICT_ARGUMENTS_ELEMENTS:
10013 case EXTERNAL_BYTE_ELEMENTS:
10014 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10015 case EXTERNAL_SHORT_ELEMENTS:
10016 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10017 case EXTERNAL_INT_ELEMENTS:
10018 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
10019 case EXTERNAL_FLOAT_ELEMENTS:
10020 case EXTERNAL_DOUBLE_ELEMENTS:
10021 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 // External arrays are always dense.
10023 return length;
10024 }
10025 // As an estimate, we assume that the prototype doesn't contain any
10026 // inherited elements.
10027 return element_count;
10028}
10029
10030
10031
10032template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010033static void IterateExternalArrayElements(Isolate* isolate,
10034 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010035 bool elements_are_ints,
10036 bool elements_are_guaranteed_smis,
10037 ArrayConcatVisitor* visitor) {
10038 Handle<ExternalArrayClass> array(
10039 ExternalArrayClass::cast(receiver->elements()));
10040 uint32_t len = static_cast<uint32_t>(array->length());
10041
10042 ASSERT(visitor != NULL);
10043 if (elements_are_ints) {
10044 if (elements_are_guaranteed_smis) {
10045 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010046 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010047 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10048 isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 visitor->visit(j, e);
10050 }
10051 } else {
10052 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010053 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010054 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010055 if (Smi::IsValid(static_cast<intptr_t>(val))) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010056 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 visitor->visit(j, e);
10058 } else {
10059 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010060 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010061 visitor->visit(j, e);
10062 }
10063 }
10064 }
10065 } else {
10066 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010068 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 visitor->visit(j, e);
10070 }
10071 }
10072}
10073
10074
10075// Used for sorting indices in a List<uint32_t>.
10076static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10077 uint32_t a = *ap;
10078 uint32_t b = *bp;
10079 return (a == b) ? 0 : (a < b) ? -1 : 1;
10080}
10081
10082
10083static void CollectElementIndices(Handle<JSObject> object,
10084 uint32_t range,
10085 List<uint32_t>* indices) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010086 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010087 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010088 switch (kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010089 case FAST_SMI_ELEMENTS:
10090 case FAST_ELEMENTS:
10091 case FAST_HOLEY_SMI_ELEMENTS:
10092 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010093 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10094 uint32_t length = static_cast<uint32_t>(elements->length());
10095 if (range < length) length = range;
10096 for (uint32_t i = 0; i < length; i++) {
10097 if (!elements->get(i)->IsTheHole()) {
10098 indices->Add(i);
10099 }
10100 }
10101 break;
10102 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010103 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010104 case FAST_DOUBLE_ELEMENTS: {
10105 // TODO(1810): Decide if it's worthwhile to implement this.
10106 UNREACHABLE();
10107 break;
10108 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010109 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010110 Handle<SeededNumberDictionary> dict(
10111 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010112 uint32_t capacity = dict->Capacity();
10113 for (uint32_t j = 0; j < capacity; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010114 HandleScope loop_scope(isolate);
10115 Handle<Object> k(dict->KeyAt(j), isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010116 if (dict->IsKey(*k)) {
10117 ASSERT(k->IsNumber());
10118 uint32_t index = static_cast<uint32_t>(k->Number());
10119 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010120 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010121 }
10122 }
10123 }
10124 break;
10125 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010126 default: {
10127 int dense_elements_length;
10128 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010129 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010130 dense_elements_length =
10131 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010132 break;
10133 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010134 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010135 dense_elements_length =
10136 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010137 break;
10138 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010139 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010140 dense_elements_length =
10141 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010142 break;
10143 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010144 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010145 dense_elements_length =
10146 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010147 break;
10148 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010149 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010150 dense_elements_length =
10151 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010152 break;
10153 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010154 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010155 dense_elements_length =
10156 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010157 break;
10158 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010159 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010160 dense_elements_length =
10161 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010162 break;
10163 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010164 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010165 dense_elements_length =
10166 ExternalFloatArray::cast(object->elements())->length();
10167 break;
10168 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010169 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010170 dense_elements_length =
10171 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010172 break;
10173 }
10174 default:
10175 UNREACHABLE();
10176 dense_elements_length = 0;
10177 break;
10178 }
10179 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10180 if (range <= length) {
10181 length = range;
10182 // We will add all indices, so we might as well clear it first
10183 // and avoid duplicates.
10184 indices->Clear();
10185 }
10186 for (uint32_t i = 0; i < length; i++) {
10187 indices->Add(i);
10188 }
10189 if (length == range) return; // All indices accounted for already.
10190 break;
10191 }
10192 }
10193
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010194 Handle<Object> prototype(object->GetPrototype(), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010195 if (prototype->IsJSObject()) {
10196 // The prototype will usually have no inherited element indices,
10197 // but we have to check.
10198 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10199 }
10200}
10201
10202
10203/**
10204 * A helper function that visits elements of a JSArray in numerical
10205 * order.
10206 *
10207 * The visitor argument called for each existing element in the array
10208 * with the element index and the element's value.
10209 * Afterwards it increments the base-index of the visitor by the array
10210 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010211 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010212 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213static bool IterateElements(Isolate* isolate,
10214 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010215 ArrayConcatVisitor* visitor) {
10216 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10217 switch (receiver->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010218 case FAST_SMI_ELEMENTS:
10219 case FAST_ELEMENTS:
10220 case FAST_HOLEY_SMI_ELEMENTS:
10221 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010222 // Run through the elements FixedArray and use HasElement and GetElement
10223 // to check the prototype for missing elements.
10224 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10225 int fast_length = static_cast<int>(length);
10226 ASSERT(fast_length <= elements->length());
10227 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 HandleScope loop_scope(isolate);
10229 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010230 if (!element_value->IsTheHole()) {
10231 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010232 } else if (JSReceiver::HasElement(receiver, j)) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010233 // Call GetElement on receiver, not its prototype, or getters won't
10234 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010235 element_value = Object::GetElement(isolate, receiver, j);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010236 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010237 visitor->visit(j, element_value);
10238 }
10239 }
10240 break;
10241 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010242 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010243 case FAST_DOUBLE_ELEMENTS: {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010244 // Run through the elements FixedArray and use HasElement and GetElement
10245 // to check the prototype for missing elements.
10246 Handle<FixedDoubleArray> elements(
10247 FixedDoubleArray::cast(receiver->elements()));
10248 int fast_length = static_cast<int>(length);
10249 ASSERT(fast_length <= elements->length());
10250 for (int j = 0; j < fast_length; j++) {
10251 HandleScope loop_scope(isolate);
10252 if (!elements->is_the_hole(j)) {
10253 double double_value = elements->get_scalar(j);
10254 Handle<Object> element_value =
10255 isolate->factory()->NewNumber(double_value);
10256 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010257 } else if (JSReceiver::HasElement(receiver, j)) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010258 // Call GetElement on receiver, not its prototype, or getters won't
10259 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010260 Handle<Object> element_value =
10261 Object::GetElement(isolate, receiver, j);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010262 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10263 visitor->visit(j, element_value);
10264 }
10265 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010266 break;
10267 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010268 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010269 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010270 List<uint32_t> indices(dict->Capacity() / 2);
10271 // Collect all indices in the object and the prototypes less
10272 // than length. This might introduce duplicates in the indices list.
10273 CollectElementIndices(receiver, length, &indices);
10274 indices.Sort(&compareUInt32);
10275 int j = 0;
10276 int n = indices.length();
10277 while (j < n) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010278 HandleScope loop_scope(isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010279 uint32_t index = indices[j];
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010280 Handle<Object> element = Object::GetElement(isolate, receiver, index);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010281 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010282 visitor->visit(index, element);
10283 // Skip to next different index (i.e., omit duplicates).
10284 do {
10285 j++;
10286 } while (j < n && indices[j] == index);
10287 }
10288 break;
10289 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010290 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010291 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10292 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010293 for (uint32_t j = 0; j < length; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010294 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010295 visitor->visit(j, e);
10296 }
10297 break;
10298 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010299 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010300 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010301 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010302 break;
10303 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010304 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010305 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010306 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010307 break;
10308 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010309 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010310 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010312 break;
10313 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010314 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010315 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010316 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010317 break;
10318 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010319 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010320 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010322 break;
10323 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010324 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010325 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010327 break;
10328 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010329 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010330 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010332 break;
10333 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010334 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010335 IterateExternalArrayElements<ExternalDoubleArray, double>(
10336 isolate, receiver, false, false, visitor);
10337 break;
10338 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010339 default:
10340 UNREACHABLE();
10341 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010342 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010343 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010344 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010345}
10346
10347
10348/**
10349 * Array::concat implementation.
10350 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010351 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010352 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010353 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010354RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010356 ASSERT(args.length() == 1);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010357
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010358 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010359 int argument_count = static_cast<int>(arguments->length()->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010360 RUNTIME_ASSERT(arguments->HasFastObjectElements());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010361 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010362
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010363 // Pass 1: estimate the length and number of elements of the result.
10364 // The actual length can be larger if any of the arguments have getters
10365 // that mutate other arguments (but will otherwise be precise).
10366 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010367
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010368 ElementsKind kind = FAST_SMI_ELEMENTS;
10369
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010370 uint32_t estimate_result_length = 0;
10371 uint32_t estimate_nof_elements = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010372 for (int i = 0; i < argument_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010373 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010374 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010375 uint32_t length_estimate;
10376 uint32_t element_estimate;
10377 if (obj->IsJSArray()) {
10378 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10379 length_estimate = static_cast<uint32_t>(array->length()->Number());
10380 if (length_estimate != 0) {
10381 ElementsKind array_kind =
10382 GetPackedElementsKind(array->map()->elements_kind());
10383 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10384 kind = array_kind;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010385 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010386 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010387 element_estimate = EstimateElementCount(array);
10388 } else {
10389 if (obj->IsHeapObject()) {
10390 if (obj->IsNumber()) {
10391 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10392 kind = FAST_DOUBLE_ELEMENTS;
10393 }
10394 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10395 kind = FAST_ELEMENTS;
10396 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010397 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010398 length_estimate = 1;
10399 element_estimate = 1;
10400 }
10401 // Avoid overflows by capping at kMaxElementCount.
10402 if (JSObject::kMaxElementCount - estimate_result_length <
10403 length_estimate) {
10404 estimate_result_length = JSObject::kMaxElementCount;
10405 } else {
10406 estimate_result_length += length_estimate;
10407 }
10408 if (JSObject::kMaxElementCount - estimate_nof_elements <
10409 element_estimate) {
10410 estimate_nof_elements = JSObject::kMaxElementCount;
10411 } else {
10412 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010413 }
10414 }
10415
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010416 // If estimated number of elements is more than half of length, a
10417 // fixed array (fast case) is more time and space-efficient than a
10418 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010419 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010420
10421 Handle<FixedArray> storage;
10422 if (fast_case) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010423 if (kind == FAST_DOUBLE_ELEMENTS) {
10424 Handle<FixedDoubleArray> double_storage =
10425 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10426 int j = 0;
10427 bool failure = false;
10428 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010429 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010430 if (obj->IsSmi()) {
10431 double_storage->set(j, Smi::cast(*obj)->value());
10432 j++;
10433 } else if (obj->IsNumber()) {
10434 double_storage->set(j, obj->Number());
10435 j++;
10436 } else {
10437 JSArray* array = JSArray::cast(*obj);
10438 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10439 switch (array->map()->elements_kind()) {
10440 case FAST_HOLEY_DOUBLE_ELEMENTS:
10441 case FAST_DOUBLE_ELEMENTS: {
10442 // Empty fixed array indicates that there are no elements.
10443 if (array->elements()->IsFixedArray()) break;
10444 FixedDoubleArray* elements =
10445 FixedDoubleArray::cast(array->elements());
10446 for (uint32_t i = 0; i < length; i++) {
10447 if (elements->is_the_hole(i)) {
10448 failure = true;
10449 break;
10450 }
10451 double double_value = elements->get_scalar(i);
10452 double_storage->set(j, double_value);
10453 j++;
10454 }
10455 break;
10456 }
10457 case FAST_HOLEY_SMI_ELEMENTS:
10458 case FAST_SMI_ELEMENTS: {
10459 FixedArray* elements(
10460 FixedArray::cast(array->elements()));
10461 for (uint32_t i = 0; i < length; i++) {
10462 Object* element = elements->get(i);
10463 if (element->IsTheHole()) {
10464 failure = true;
10465 break;
10466 }
10467 int32_t int_value = Smi::cast(element)->value();
10468 double_storage->set(j, int_value);
10469 j++;
10470 }
10471 break;
10472 }
10473 case FAST_HOLEY_ELEMENTS:
10474 ASSERT_EQ(0, length);
10475 break;
10476 default:
10477 UNREACHABLE();
10478 }
10479 }
10480 if (failure) break;
10481 }
10482 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10483 Smi* length = Smi::FromInt(j);
10484 Handle<Map> map;
10485 map = isolate->factory()->GetElementsTransitionMap(array, kind);
10486 array->set_map(*map);
10487 array->set_length(length);
10488 array->set_elements(*double_storage);
10489 return *array;
10490 }
10491 // The backing storage array must have non-existing elements to preserve
10492 // holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 storage = isolate->factory()->NewFixedArrayWithHoles(
10494 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010495 } else {
10496 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10497 uint32_t at_least_space_for = estimate_nof_elements +
10498 (estimate_nof_elements >> 2);
10499 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010500 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010501 }
10502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010504
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010505 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010506 Handle<Object> obj(elements->get(i), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010507 if (obj->IsJSArray()) {
10508 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010510 return Failure::Exception();
10511 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010512 } else {
10513 visitor.visit(0, obj);
10514 visitor.increase_index_offset(1);
10515 }
10516 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010517
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000010518 if (visitor.exceeds_array_limit()) {
10519 return isolate->Throw(
10520 *isolate->factory()->NewRangeError("invalid_array_length",
10521 HandleVector<Object>(NULL, 0)));
10522 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010523 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010524}
10525
10526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527// This will not allocate (flatten the string), but it may run
10528// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010529RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010530 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 ASSERT(args.length() == 1);
10532
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010533 CONVERT_ARG_CHECKED(String, string, 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010534 ConsStringIteratorOp op;
10535 StringCharacterStream stream(string, &op);
10536 while (stream.HasMore()) {
10537 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538 PrintF("%c", character);
10539 }
10540 return string;
10541}
10542
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010543
ager@chromium.org5ec48922009-05-05 07:25:34 +000010544// Moves all own elements of an object, that are below a limit, to positions
10545// starting at zero. All undefined values are placed after non-undefined values,
10546// and are followed by non-existing element. Does not change the length
10547// property.
10548// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010549RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010550 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010551 ASSERT(args.length() == 2);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010552 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010553 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010554 return *JSObject::PrepareElementsForSort(object, limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010555}
10556
10557
10558// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010559RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010560 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010562 CONVERT_ARG_CHECKED(JSArray, from, 0);
10563 CONVERT_ARG_CHECKED(JSArray, to, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010564 from->ValidateElements();
10565 to->ValidateElements();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010566 FixedArrayBase* new_elements = from->elements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010567 ElementsKind from_kind = from->GetElementsKind();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010568 MaybeObject* maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010569 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010570 Object* new_map;
10571 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010572 to->set_map_and_elements(Map::cast(new_map), new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010574 Object* obj;
10575 { MaybeObject* maybe_obj = from->ResetElements();
10576 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10577 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010578 from->set_length(Smi::FromInt(0));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010579 to->ValidateElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 return to;
10581}
10582
10583
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010584// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010585RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010586 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010588 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010589 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010591 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10592 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010593 } else if (object->IsJSArray()) {
10594 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010596 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 }
10598}
10599
10600
10601// Returns an array that tells you where in the [0, length) interval an array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010602// might have elements. Can either return an array of keys (positive integers
10603// or undefined) or a number representing the positive length of an interval
10604// starting at index 0.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010605// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010608 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010609 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010611 if (array->elements()->IsDictionary()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010612 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10613 for (Handle<Object> p = array;
10614 !p->IsNull();
10615 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10616 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10617 // Bail out if we find a proxy or interceptor, likely not worth
10618 // collecting keys in that case.
10619 return *isolate->factory()->NewNumberFromUint(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010621 Handle<JSObject> current = Handle<JSObject>::cast(p);
10622 Handle<FixedArray> current_keys =
10623 isolate->factory()->NewFixedArray(
10624 current->NumberOfLocalElements(NONE));
10625 current->GetLocalElementKeys(*current_keys, NONE);
10626 keys = UnionOfKeys(keys, current_keys);
10627 }
10628 // Erase any keys >= length.
10629 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10630 // is changed to let this happen on the JS side.
10631 for (int i = 0; i < keys->length(); i++) {
10632 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010634 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010636 ASSERT(array->HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010637 array->HasFastDoubleElements());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010638 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10639 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 }
10641}
10642
10643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010644RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010645 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646 ASSERT(args.length() == 3);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010647 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10648 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010649 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010650 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000010651 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010652 Handle<Object> result =
10653 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component);
10654 RETURN_IF_EMPTY_HANDLE(isolate, result);
10655 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656}
10657
10658
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010659#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010660RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010661 SealHandleScope shs(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010662 ASSERT(args.length() == 0);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000010663 return Execution::DebugBreakHelper(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010664}
10665
10666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667// Helper functions for wrapping and unwrapping stack frame ids.
10668static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010669 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 return Smi::FromInt(id >> 2);
10671}
10672
10673
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010674static StackFrame::Id UnwrapFrameId(int wrapped) {
10675 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676}
10677
10678
10679// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010680// args[0]: debug event listener function to set or null or undefined for
10681// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010683RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010684 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010685 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010686 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10687 args[0]->IsUndefined() ||
10688 args[0]->IsNull());
10689 Handle<Object> callback = args.at<Object>(0);
10690 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010691 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010694}
10695
10696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010697RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010698 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010699 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010700 isolate->stack_guard()->DebugBreak();
10701 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702}
10703
10704
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705static MaybeObject* DebugLookupResultValue(Heap* heap,
10706 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000010707 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010708 LookupResult* result,
10709 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010710 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010712 case NORMAL:
10713 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010714 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010715 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716 }
10717 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010718 case FIELD: {
10719 Object* value;
10720 MaybeObject* maybe_value =
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010721 JSObject::cast(result->holder())->FastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010722 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010723 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010724 if (!maybe_value->To(&value)) return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010725 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010726 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010727 }
10728 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010729 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000010730 case CONSTANT:
10731 return result->GetConstant();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010732 case CALLBACKS: {
10733 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010734 if (structure->IsForeign() || structure->IsAccessorInfo()) {
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010735 Isolate* isolate = heap->isolate();
10736 HandleScope scope(isolate);
10737 Handle<Object> value = JSObject::GetPropertyWithCallback(
10738 handle(result->holder(), isolate),
10739 handle(receiver, isolate),
10740 handle(structure, isolate),
10741 handle(name, isolate));
10742 if (value.is_null()) {
10743 MaybeObject* exception = heap->isolate()->pending_exception();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010744 heap->isolate()->clear_pending_exception();
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010745 if (caught_exception != NULL) *caught_exception = true;
10746 return exception;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010747 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010748 return *value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010749 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010751 }
10752 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753 case INTERCEPTOR:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010754 case TRANSITION:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010756 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010757 case NONEXISTENT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010759 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010761 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763}
10764
10765
ager@chromium.org32912102009-01-16 10:38:43 +000010766// Get debugger related details for an object property.
10767// args[0]: object holding property
10768// args[1]: name of the property
10769//
10770// The array returned contains the following information:
10771// 0: Property value
10772// 1: Property details
10773// 2: Property value is exception
10774// 3: Getter function if defined
10775// 4: Setter function if defined
10776// Items 2-4 are only filled if the property has either a getter or a setter
10777// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010778RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780
10781 ASSERT(args.length() == 2);
10782
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010783 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010784 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010786 // Make sure to set the current context to the context before the debugger was
10787 // entered (if the debugger is entered). The reason for switching context here
10788 // is that for some property lookups (accessors and interceptors) callbacks
10789 // into the embedding application can occour, and the embedding application
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010790 // could have the assumption that its own native context is the current
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010791 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 SaveContext save(isolate);
10793 if (isolate->debug()->InDebugger()) {
10794 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010795 }
10796
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010797 // Skip the global proxy as it has no properties and always delegates to the
10798 // real global object.
10799 if (obj->IsJSGlobalProxy()) {
10800 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10801 }
10802
10803
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804 // Check if the name is trivially convertible to an index and get the element
10805 // if so.
10806 uint32_t index;
10807 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010808 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010809 Object* element_or_char;
10810 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010812 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10813 return maybe_element_or_char;
10814 }
10815 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010816 details->set(0, element_or_char);
danno@chromium.orgf005df62013-04-30 16:36:45 +000010817 details->set(
10818 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 }
10821
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010822 // Find the number of objects making up this.
10823 int length = LocalPrototypeChainLength(*obj);
10824
10825 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010826 Handle<JSObject> jsproto = obj;
10827 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010828 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010829 jsproto->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010830 if (result.IsFound()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010831 // LookupResult is not GC safe as it holds raw object pointers.
10832 // GC can happen later in this code so put the required fields into
10833 // local variables using handles when required for later use.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010834 Handle<Object> result_callback_obj;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010835 if (result.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10837 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010838 }
10839 Smi* property_details = result.GetPropertyDetails().AsSmi();
10840 // DebugLookupResultValue can cause GC so details from LookupResult needs
10841 // to be copied to handles before this.
10842 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010843 Object* raw_value;
10844 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010845 DebugLookupResultValue(isolate->heap(), *obj, *name,
10846 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010847 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10848 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010850
10851 // If the callback object is a fixed array then it contains JavaScript
10852 // getter and/or setter.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010853 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010854 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010855 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010856 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010857 details->set(0, *value);
10858 details->set(1, property_details);
10859 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010860 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010861 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010862 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10863 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010864 }
10865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010866 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010867 }
10868 if (i < length - 1) {
10869 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10870 }
10871 }
10872
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874}
10875
10876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010877RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010879
10880 ASSERT(args.length() == 2);
10881
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010882 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010883 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010885 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 obj->Lookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010887 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010891}
10892
10893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894// Return the property type calculated from the property details.
10895// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010896RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010897 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010899 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10900 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901}
10902
10903
10904// Return the property attribute calculated from the property details.
10905// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010906RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010907 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010908 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010909 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10910 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010911}
10912
10913
10914// Return the property insertion index calculated from the property details.
10915// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010916RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010917 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010919 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010920 // TODO(verwaest): Depends on the type of details.
10921 return Smi::FromInt(details.dictionary_index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010922}
10923
10924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925// Return property value from named interceptor.
10926// args[0]: object
10927// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010928RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010929 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010930 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010931 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 RUNTIME_ASSERT(obj->HasNamedInterceptor());
ulan@chromium.org750145a2013-03-07 15:14:13 +000010933 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934
10935 PropertyAttributes attributes;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000010936 Handle<Object> result =
10937 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes);
10938 RETURN_IF_EMPTY_HANDLE(isolate, result);
10939 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940}
10941
10942
10943// Return element value from indexed interceptor.
10944// args[0]: object
10945// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010946RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010947 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010949 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10951 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10952
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010953 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954}
10955
10956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010957RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010958 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 ASSERT(args.length() >= 1);
10960 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010961 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 if (isolate->debug()->break_id() == 0 ||
10963 break_id != isolate->debug()->break_id()) {
10964 return isolate->Throw(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010965 isolate->heap()->illegal_execution_state_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966 }
10967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010968 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969}
10970
10971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010972RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010973 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 ASSERT(args.length() == 1);
10975
10976 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010977 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10979 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010980 if (!maybe_result->ToObject(&result)) return maybe_result;
10981 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982
10983 // Count all frames which are relevant to debugging stack trace.
10984 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010986 if (id == StackFrame::NO_ID) {
10987 // If there is no JavaScript stack frame count is 0.
10988 return Smi::FromInt(0);
10989 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010990
10991 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10992 n += it.frame()->GetInlineCount();
10993 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 return Smi::FromInt(n);
10995}
10996
10997
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010998class FrameInspector {
10999 public:
11000 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011001 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011002 Isolate* isolate)
11003 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
11004 // Calculate the deoptimized frame.
11005 if (frame->is_optimized()) {
11006 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011007 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011008 }
11009 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000011010 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011011 is_optimized_ = frame_->is_optimized();
11012 }
11013
11014 ~FrameInspector() {
11015 // Get rid of the calculated deoptimized frame if any.
11016 if (deoptimized_frame_ != NULL) {
11017 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
11018 isolate_);
11019 }
11020 }
11021
11022 int GetParametersCount() {
11023 return is_optimized_
11024 ? deoptimized_frame_->parameters_count()
11025 : frame_->ComputeParametersCount();
11026 }
11027 int expression_count() { return deoptimized_frame_->expression_count(); }
11028 Object* GetFunction() {
11029 return is_optimized_
11030 ? deoptimized_frame_->GetFunction()
11031 : frame_->function();
11032 }
11033 Object* GetParameter(int index) {
11034 return is_optimized_
11035 ? deoptimized_frame_->GetParameter(index)
11036 : frame_->GetParameter(index);
11037 }
11038 Object* GetExpression(int index) {
11039 return is_optimized_
11040 ? deoptimized_frame_->GetExpression(index)
11041 : frame_->GetExpression(index);
11042 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011043 int GetSourcePosition() {
11044 return is_optimized_
11045 ? deoptimized_frame_->GetSourcePosition()
11046 : frame_->LookupCode()->SourcePosition(frame_->pc());
11047 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000011048 bool IsConstructor() {
11049 return is_optimized_ && !is_bottommost_
11050 ? deoptimized_frame_->HasConstructStub()
11051 : frame_->IsConstructor();
11052 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011053
11054 // To inspect all the provided arguments the frame might need to be
11055 // replaced with the arguments frame.
11056 void SetArgumentsFrame(JavaScriptFrame* frame) {
11057 ASSERT(has_adapted_arguments_);
11058 frame_ = frame;
11059 is_optimized_ = frame_->is_optimized();
11060 ASSERT(!is_optimized_);
11061 }
11062
11063 private:
11064 JavaScriptFrame* frame_;
11065 DeoptimizedFrameInfo* deoptimized_frame_;
11066 Isolate* isolate_;
11067 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000011068 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011069 bool has_adapted_arguments_;
11070
11071 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11072};
11073
11074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011075static const int kFrameDetailsFrameIdIndex = 0;
11076static const int kFrameDetailsReceiverIndex = 1;
11077static const int kFrameDetailsFunctionIndex = 2;
11078static const int kFrameDetailsArgumentCountIndex = 3;
11079static const int kFrameDetailsLocalCountIndex = 4;
11080static const int kFrameDetailsSourcePositionIndex = 5;
11081static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011082static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011083static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011084static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011086
11087static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11088 JavaScriptFrame* frame) {
11089 SaveContext* save = isolate->save_context();
11090 while (save != NULL && !save->IsBelowFrame(frame)) {
11091 save = save->prev();
11092 }
11093 ASSERT(save != NULL);
11094 return save;
11095}
11096
11097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011098// Return an array with frame details
11099// args[0]: number: break id
11100// args[1]: number: frame index
11101//
11102// The array returned contains the following information:
11103// 0: Frame id
11104// 1: Receiver
11105// 2: Function
11106// 3: Argument count
11107// 4: Local count
11108// 5: Source position
11109// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011110// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011111// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112// Arguments name, value
11113// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011114// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011115RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117 ASSERT(args.length() == 2);
11118
11119 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011120 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011121 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11122 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011123 if (!maybe_check->ToObject(&check)) return maybe_check;
11124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127
11128 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011130 if (id == StackFrame::NO_ID) {
11131 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011132 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011133 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011135 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011136 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011138 if (index < count + it.frame()->GetInlineCount()) break;
11139 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011141 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011143 bool is_optimized = it.frame()->is_optimized();
11144
11145 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11146 if (is_optimized) {
11147 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011148 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011149 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011150 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152 // Traverse the saved contexts chain to find the active context for the
11153 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011154 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155
11156 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011157 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011158
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011159 // Find source position in unoptimized code.
11160 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161
ulan@chromium.org967e2702012-02-28 09:49:15 +000011162 // Check for constructor frame.
11163 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011165 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011166 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011167 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011168 Handle<ScopeInfo> scope_info(shared->scope_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011169 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171 // Get the locals names and values into a temporary array.
11172 //
11173 // TODO(1240907): Hide compiler-introduced stack variables
11174 // (e.g. .result)? For users of the debugger, they will probably be
11175 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011176 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011177 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011179 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011180 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011181 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011182 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011183 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011184 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011185 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011186 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011187 // Get the context containing declarations.
11188 Handle<Context> context(
11189 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011190 for (; i < scope_info->LocalCount(); ++i) {
11191 Handle<String> name(scope_info->LocalName(i));
11192 VariableMode mode;
11193 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011194 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011195 locals->set(i * 2 + 1, context->get(
11196 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011197 }
11198 }
11199
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011200 // Check whether this frame is positioned at return. If not top
11201 // frame or if the frame is optimized it cannot be at a return.
11202 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011203 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011205 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011206
11207 // If positioned just before return find the value to be returned and add it
11208 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011210 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011211 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011212 Address internal_frame_sp = NULL;
11213 while (!it2.done()) {
11214 if (it2.frame()->is_internal()) {
11215 internal_frame_sp = it2.frame()->sp();
11216 } else {
11217 if (it2.frame()->is_java_script()) {
11218 if (it2.frame()->id() == it.frame()->id()) {
11219 // The internal frame just before the JavaScript frame contains the
11220 // value to return on top. A debug break at return will create an
11221 // internal frame to store the return value (eax/rax/r0) before
11222 // entering the debug break exit frame.
11223 if (internal_frame_sp != NULL) {
11224 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011225 Handle<Object>(Memory::Object_at(internal_frame_sp),
11226 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011227 break;
11228 }
11229 }
11230 }
11231
11232 // Indicate that the previous frame was not an internal frame.
11233 internal_frame_sp = NULL;
11234 }
11235 it2.Advance();
11236 }
11237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011238
11239 // Now advance to the arguments adapter frame (if any). It contains all
11240 // the provided parameters whereas the function frame always have the number
11241 // of arguments matching the functions parameters. The rest of the
11242 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011243 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011244 it.AdvanceToArgumentsFrame();
11245 frame_inspector.SetArgumentsFrame(it.frame());
11246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011247
11248 // Find the number of arguments to fill. At least fill the number of
11249 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011250 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011251 if (argument_count < frame_inspector.GetParametersCount()) {
11252 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 }
11254
11255 // Calculate the size of the result.
11256 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011257 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011258 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011259 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260
11261 // Add the frame id.
11262 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11263
11264 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011265 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011266
11267 // Add the arguments count.
11268 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11269
11270 // Add the locals count
11271 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011272 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273
11274 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000011275 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011276 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11277 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011278 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011279 }
11280
11281 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011282 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011283
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011284 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011285 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011286
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011287 // Add flags to indicate information on whether this frame is
11288 // bit 0: invoked in the debugger context.
11289 // bit 1: optimized frame.
11290 // bit 2: inlined in optimized frame
11291 int flags = 0;
11292 if (*save->context() == *isolate->debug()->debug_context()) {
11293 flags |= 1 << 0;
11294 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011295 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011296 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011297 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011298 }
11299 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011300
11301 // Fill the dynamic part.
11302 int details_index = kFrameDetailsFirstDynamicIndex;
11303
11304 // Add arguments name and value.
11305 for (int i = 0; i < argument_count; i++) {
11306 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011307 if (i < scope_info->ParameterCount()) {
11308 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011310 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011311 }
11312
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011313 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011314 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011315 // Get the value from the stack.
11316 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011317 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011318 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319 }
11320 }
11321
11322 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011323 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011324 details->set(details_index++, locals->get(i));
11325 }
11326
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011327 // Add the value being returned.
11328 if (at_return) {
11329 details->set(details_index++, *return_value);
11330 }
11331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011332 // Add the receiver (same as in function frame).
11333 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11334 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011336 if (!receiver->IsJSObject() &&
11337 shared->is_classic_mode() &&
danno@chromium.orgbee51992013-07-10 14:57:15 +000011338 !function->IsBuiltin()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011339 // If the receiver is not a JSObject and the function is not a
11340 // builtin or strict-mode we have hit an optimization where a
11341 // value object is not converted into a wrapped JS objects. To
11342 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011343 // by creating correct wrapper object based on the calling frame's
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011344 // native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011345 it.Advance();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011346 Handle<Context> calling_frames_native_context(
11347 Context::cast(Context::cast(it.frame()->context())->native_context()));
danno@chromium.orgbee51992013-07-10 14:57:15 +000011348 ASSERT(!receiver->IsUndefined() && !receiver->IsNull());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 receiver =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011350 isolate->factory()->ToObject(receiver, calling_frames_native_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011351 }
11352 details->set(kFrameDetailsReceiverIndex, *receiver);
11353
11354 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011355 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356}
11357
11358
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359// Create a plain JSObject which materializes the local scope for the specified
11360// frame.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011361static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011362 Isolate* isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011363 Handle<JSObject> target,
11364 Handle<JSFunction> function,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011365 FrameInspector* frame_inspector) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011366 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011367 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011369 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011370 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000011371 Handle<String> name(scope_info->ParameterName(i));
11372 VariableMode mode;
11373 InitializationFlag init_flag;
11374 // Do not materialize the parameter if it is shadowed by a context local.
11375 if (scope_info->ContextSlotIndex(*name, &mode, &init_flag) != -1) continue;
11376
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011377 Handle<Object> value(i < frame_inspector->GetParametersCount()
11378 ? frame_inspector->GetParameter(i)
11379 : isolate->heap()->undefined_value(),
11380 isolate);
danno@chromium.org59400602013-08-13 17:09:37 +000011381 ASSERT(!value->IsTheHole());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011382
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011383 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011384 isolate,
yangguo@chromium.org49546742013-12-23 16:17:49 +000011385 Runtime::SetObjectProperty(
11386 isolate, target, name, value, NONE, kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011387 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011388 }
11389
11390 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011391 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000011392 Handle<String> name(scope_info->StackLocalName(i));
danno@chromium.org59400602013-08-13 17:09:37 +000011393 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11394 if (value->IsTheHole()) continue;
11395
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011396 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011398 Runtime::SetObjectProperty(
yangguo@chromium.org49546742013-12-23 16:17:49 +000011399 isolate, target, name, value, NONE, kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011400 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011401 }
11402
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011403 return target;
11404}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011405
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011406
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011407static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11408 Handle<JSObject> target,
11409 Handle<JSFunction> function,
11410 JavaScriptFrame* frame,
11411 int inlined_jsframe_index) {
11412 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11413 // Optimized frames are not supported.
11414 // TODO(yangguo): make sure all code deoptimized when debugger is active
11415 // and assert that this cannot happen.
11416 return;
11417 }
11418
11419 Handle<SharedFunctionInfo> shared(function->shared());
11420 Handle<ScopeInfo> scope_info(shared->scope_info());
11421
11422 // Parameters.
11423 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011424 ASSERT(!frame->GetParameter(i)->IsTheHole());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011425 HandleScope scope(isolate);
11426 Handle<Object> value = GetProperty(
11427 isolate, target, Handle<String>(scope_info->ParameterName(i)));
11428 frame->SetParameterValue(i, *value);
11429 }
11430
11431 // Stack locals.
11432 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011433 if (frame->GetExpression(i)->IsTheHole()) continue;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011434 HandleScope scope(isolate);
11435 Handle<Object> value = GetProperty(
11436 isolate, target, Handle<String>(scope_info->StackLocalName(i)));
11437 frame->SetExpression(i, *value);
11438 }
11439}
11440
11441
11442static Handle<JSObject> MaterializeLocalContext(Isolate* isolate,
11443 Handle<JSObject> target,
11444 Handle<JSFunction> function,
11445 JavaScriptFrame* frame) {
11446 HandleScope scope(isolate);
11447 Handle<SharedFunctionInfo> shared(function->shared());
11448 Handle<ScopeInfo> scope_info(shared->scope_info());
11449
11450 if (!scope_info->HasContext()) return target;
11451
11452 // Third fill all context locals.
11453 Handle<Context> frame_context(Context::cast(frame->context()));
11454 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011455 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11456 scope_info, function_context, target)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011457 return Handle<JSObject>();
11458 }
11459
11460 // Finally copy any properties from the function context extension.
11461 // These will be variables introduced by eval.
11462 if (function_context->closure() == *function) {
11463 if (function_context->has_extension() &&
11464 !function_context->IsNativeContext()) {
11465 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11466 bool threw = false;
11467 Handle<FixedArray> keys =
11468 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11469 if (threw) return Handle<JSObject>();
11470
11471 for (int i = 0; i < keys->length(); i++) {
11472 // Names of variables introduced by eval are strings.
11473 ASSERT(keys->get(i)->IsString());
11474 Handle<String> key(String::cast(keys->get(i)));
11475 RETURN_IF_EMPTY_HANDLE_VALUE(
11476 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011477 Runtime::SetObjectProperty(isolate,
11478 target,
11479 key,
11480 GetProperty(isolate, ext, key),
11481 NONE,
11482 kNonStrictMode),
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011483 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011484 }
11485 }
11486 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011487
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011488 return target;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011489}
11490
11491
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011492static Handle<JSObject> MaterializeLocalScope(
11493 Isolate* isolate,
11494 JavaScriptFrame* frame,
11495 int inlined_jsframe_index) {
11496 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011497 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11498
11499 Handle<JSObject> local_scope =
11500 isolate->factory()->NewJSObject(isolate->object_function());
11501 local_scope = MaterializeStackLocalsWithFrameInspector(
11502 isolate, local_scope, function, &frame_inspector);
11503 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
11504
11505 return MaterializeLocalContext(isolate, local_scope, function, frame);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011506}
11507
11508
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011509// Set the context local variable value.
11510static bool SetContextLocalValue(Isolate* isolate,
11511 Handle<ScopeInfo> scope_info,
11512 Handle<Context> context,
11513 Handle<String> variable_name,
11514 Handle<Object> new_value) {
11515 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11516 Handle<String> next_name(scope_info->ContextLocalName(i));
11517 if (variable_name->Equals(*next_name)) {
11518 VariableMode mode;
11519 InitializationFlag init_flag;
11520 int context_index =
11521 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
11522 context->set(context_index, *new_value);
11523 return true;
11524 }
11525 }
11526
11527 return false;
11528}
11529
11530
11531static bool SetLocalVariableValue(Isolate* isolate,
11532 JavaScriptFrame* frame,
11533 int inlined_jsframe_index,
11534 Handle<String> variable_name,
11535 Handle<Object> new_value) {
11536 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11537 // Optimized frames are not supported.
11538 return false;
11539 }
11540
danno@chromium.org169691d2013-07-15 08:01:13 +000011541 Handle<JSFunction> function(frame->function());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011542 Handle<SharedFunctionInfo> shared(function->shared());
11543 Handle<ScopeInfo> scope_info(shared->scope_info());
11544
11545 bool default_result = false;
11546
11547 // Parameters.
11548 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11549 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
11550 frame->SetParameterValue(i, *new_value);
11551 // Argument might be shadowed in heap context, don't stop here.
11552 default_result = true;
11553 }
11554 }
11555
11556 // Stack locals.
11557 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11558 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
11559 frame->SetExpression(i, *new_value);
11560 return true;
11561 }
11562 }
11563
11564 if (scope_info->HasContext()) {
11565 // Context locals.
11566 Handle<Context> frame_context(Context::cast(frame->context()));
11567 Handle<Context> function_context(frame_context->declaration_context());
11568 if (SetContextLocalValue(
11569 isolate, scope_info, function_context, variable_name, new_value)) {
11570 return true;
11571 }
11572
11573 // Function context extension. These are variables introduced by eval.
11574 if (function_context->closure() == *function) {
11575 if (function_context->has_extension() &&
11576 !function_context->IsNativeContext()) {
11577 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11578
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011579 if (JSReceiver::HasProperty(ext, variable_name)) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011580 // We don't expect this to do anything except replacing
11581 // property value.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011582 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11583 NONE,
11584 kNonStrictMode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011585 return true;
11586 }
11587 }
11588 }
11589 }
11590
11591 return default_result;
11592}
11593
11594
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011595// Create a plain JSObject which materializes the closure content for the
11596// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11598 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011599 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011600
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011601 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011602 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011603
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011604 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011606 Handle<JSObject> closure_scope =
11607 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011608
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011609 // Fill all context locals to the context extension.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011610 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11611 scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011612 return Handle<JSObject>();
11613 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011614
11615 // Finally copy any properties from the function context extension. This will
11616 // be variables introduced by eval.
11617 if (context->has_extension()) {
11618 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011619 bool threw = false;
11620 Handle<FixedArray> keys =
11621 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11622 if (threw) return Handle<JSObject>();
11623
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011624 for (int i = 0; i < keys->length(); i++) {
11625 // Names of variables introduced by eval are strings.
11626 ASSERT(keys->get(i)->IsString());
11627 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 RETURN_IF_EMPTY_HANDLE_VALUE(
11629 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011630 Runtime::SetObjectProperty(isolate, closure_scope, key,
11631 GetProperty(isolate, ext, key),
11632 NONE,
11633 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011634 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011635 }
11636 }
11637
11638 return closure_scope;
11639}
11640
11641
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011642// This method copies structure of MaterializeClosure method above.
11643static bool SetClosureVariableValue(Isolate* isolate,
11644 Handle<Context> context,
11645 Handle<String> variable_name,
11646 Handle<Object> new_value) {
11647 ASSERT(context->IsFunctionContext());
11648
11649 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11650 Handle<ScopeInfo> scope_info(shared->scope_info());
11651
11652 // Context locals to the context extension.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011653 if (SetContextLocalValue(
11654 isolate, scope_info, context, variable_name, new_value)) {
11655 return true;
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011656 }
11657
11658 // Properties from the function context extension. This will
11659 // be variables introduced by eval.
11660 if (context->has_extension()) {
11661 Handle<JSObject> ext(JSObject::cast(context->extension()));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011662 if (JSReceiver::HasProperty(ext, variable_name)) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011663 // We don't expect this to do anything except replacing property value.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011664 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11665 NONE,
11666 kNonStrictMode);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011667 return true;
11668 }
11669 }
11670
11671 return false;
11672}
11673
11674
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011675// Create a plain JSObject which materializes the scope for the specified
11676// catch context.
11677static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11678 Handle<Context> context) {
11679 ASSERT(context->IsCatchContext());
11680 Handle<String> name(String::cast(context->extension()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011681 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11682 isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011683 Handle<JSObject> catch_scope =
11684 isolate->factory()->NewJSObject(isolate->object_function());
11685 RETURN_IF_EMPTY_HANDLE_VALUE(
11686 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011687 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
11688 NONE,
11689 kNonStrictMode),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011690 Handle<JSObject>());
11691 return catch_scope;
11692}
11693
11694
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011695static bool SetCatchVariableValue(Isolate* isolate,
11696 Handle<Context> context,
11697 Handle<String> variable_name,
11698 Handle<Object> new_value) {
11699 ASSERT(context->IsCatchContext());
11700 Handle<String> name(String::cast(context->extension()));
11701 if (!name->Equals(*variable_name)) {
11702 return false;
11703 }
11704 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11705 return true;
11706}
11707
11708
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011709// Create a plain JSObject which materializes the block scope for the specified
11710// block context.
11711static Handle<JSObject> MaterializeBlockScope(
11712 Isolate* isolate,
11713 Handle<Context> context) {
11714 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011715 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011716
11717 // Allocate and initialize a JSObject with all the arguments, stack locals
11718 // heap locals and extension properties of the debugged function.
11719 Handle<JSObject> block_scope =
11720 isolate->factory()->NewJSObject(isolate->object_function());
11721
11722 // Fill all context locals.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011723 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11724 scope_info, context, block_scope)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011725 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011726 }
11727
11728 return block_scope;
11729}
11730
11731
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011732// Create a plain JSObject which materializes the module scope for the specified
11733// module context.
11734static Handle<JSObject> MaterializeModuleScope(
11735 Isolate* isolate,
11736 Handle<Context> context) {
11737 ASSERT(context->IsModuleContext());
11738 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11739
11740 // Allocate and initialize a JSObject with all the members of the debugged
11741 // module.
11742 Handle<JSObject> module_scope =
11743 isolate->factory()->NewJSObject(isolate->object_function());
11744
11745 // Fill all context locals.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011746 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11747 scope_info, context, module_scope)) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011748 return Handle<JSObject>();
11749 }
11750
11751 return module_scope;
11752}
11753
11754
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011755// Iterate over the actual scopes visible from a stack frame or from a closure.
11756// The iteration proceeds from the innermost visible nested scope outwards.
11757// All scopes are backed by an actual context except the local scope,
11758// which is inserted "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011759class ScopeIterator {
11760 public:
11761 enum ScopeType {
11762 ScopeTypeGlobal = 0,
11763 ScopeTypeLocal,
11764 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011765 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011766 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011767 ScopeTypeBlock,
11768 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011769 };
11770
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011771 ScopeIterator(Isolate* isolate,
11772 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011773 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 : isolate_(isolate),
11775 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011776 inlined_jsframe_index_(inlined_jsframe_index),
danno@chromium.org169691d2013-07-15 08:01:13 +000011777 function_(frame->function()),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011778 context_(Context::cast(frame->context())),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011779 nested_scope_chain_(4),
11780 failed_(false) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011781
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011782 // Catch the case when the debugger stops in an internal function.
11783 Handle<SharedFunctionInfo> shared_info(function_->shared());
11784 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11785 if (shared_info->script() == isolate->heap()->undefined_value()) {
11786 while (context_->closure() == *function_) {
11787 context_ = Handle<Context>(context_->previous(), isolate_);
11788 }
11789 return;
11790 }
11791
11792 // Get the debug info (create it if it does not exist).
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011793 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011794 // Return if ensuring debug info failed.
11795 return;
11796 }
11797 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11798
11799 // Find the break point where execution has stopped.
11800 BreakLocationIterator break_location_iterator(debug_info,
11801 ALL_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +000011802 // pc points to the instruction after the current one, possibly a break
11803 // location as well. So the "- 1" to exclude it from the search.
11804 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011805 if (break_location_iterator.IsExit()) {
11806 // We are within the return sequence. At the momemt it is not possible to
11807 // get a source position which is consistent with the current scope chain.
11808 // Thus all nested with, catch and block contexts are skipped and we only
11809 // provide the function scope.
11810 if (scope_info->HasContext()) {
11811 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11812 } else {
11813 while (context_->closure() == *function_) {
11814 context_ = Handle<Context>(context_->previous(), isolate_);
11815 }
11816 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011817 if (scope_info->scope_type() != EVAL_SCOPE) {
11818 nested_scope_chain_.Add(scope_info);
11819 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011820 } else {
11821 // Reparse the code and analyze the scopes.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011822 Handle<Script> script(Script::cast(shared_info->script()));
11823 Scope* scope = NULL;
11824
11825 // Check whether we are in global, eval or function code.
11826 Handle<ScopeInfo> scope_info(shared_info->scope_info());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011827 if (scope_info->scope_type() != FUNCTION_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011828 // Global or eval code.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011829 CompilationInfoWithZone info(script);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011830 if (scope_info->scope_type() == GLOBAL_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011831 info.MarkAsGlobal();
11832 } else {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011833 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011834 info.MarkAsEval();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011835 info.SetContext(Handle<Context>(function_->context()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011836 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011837 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011838 scope = info.function()->scope();
11839 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011840 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011841 } else {
11842 // Function code
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011843 CompilationInfoWithZone info(shared_info);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011844 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011845 scope = info.function()->scope();
11846 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011847 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011848 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011849 }
11850 }
11851
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011852 ScopeIterator(Isolate* isolate,
11853 Handle<JSFunction> function)
11854 : isolate_(isolate),
11855 frame_(NULL),
11856 inlined_jsframe_index_(0),
11857 function_(function),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011858 context_(function->context()),
11859 failed_(false) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011860 if (function->IsBuiltin()) {
11861 context_ = Handle<Context>();
11862 }
11863 }
11864
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011865 // More scopes?
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011866 bool Done() {
11867 ASSERT(!failed_);
11868 return context_.is_null();
11869 }
11870
11871 bool Failed() { return failed_; }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011872
11873 // Move to the next scope.
11874 void Next() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011875 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011876 ScopeType scope_type = Type();
11877 if (scope_type == ScopeTypeGlobal) {
11878 // The global scope is always the last in the chain.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011879 ASSERT(context_->IsNativeContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011880 context_ = Handle<Context>();
11881 return;
11882 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011883 if (nested_scope_chain_.is_empty()) {
11884 context_ = Handle<Context>(context_->previous(), isolate_);
11885 } else {
11886 if (nested_scope_chain_.last()->HasContext()) {
11887 ASSERT(context_->previous() != NULL);
11888 context_ = Handle<Context>(context_->previous(), isolate_);
11889 }
11890 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011891 }
11892 }
11893
11894 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011895 ScopeType Type() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011896 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011897 if (!nested_scope_chain_.is_empty()) {
11898 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011899 switch (scope_info->scope_type()) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011900 case FUNCTION_SCOPE:
11901 ASSERT(context_->IsFunctionContext() ||
11902 !scope_info->HasContext());
11903 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011904 case MODULE_SCOPE:
11905 ASSERT(context_->IsModuleContext());
11906 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011907 case GLOBAL_SCOPE:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011908 ASSERT(context_->IsNativeContext());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011909 return ScopeTypeGlobal;
11910 case WITH_SCOPE:
11911 ASSERT(context_->IsWithContext());
11912 return ScopeTypeWith;
11913 case CATCH_SCOPE:
11914 ASSERT(context_->IsCatchContext());
11915 return ScopeTypeCatch;
11916 case BLOCK_SCOPE:
11917 ASSERT(!scope_info->HasContext() ||
11918 context_->IsBlockContext());
11919 return ScopeTypeBlock;
11920 case EVAL_SCOPE:
11921 UNREACHABLE();
11922 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011923 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011924 if (context_->IsNativeContext()) {
11925 ASSERT(context_->global_object()->IsGlobalObject());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011926 return ScopeTypeGlobal;
11927 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011928 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011929 return ScopeTypeClosure;
11930 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011931 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011932 return ScopeTypeCatch;
11933 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011934 if (context_->IsBlockContext()) {
11935 return ScopeTypeBlock;
11936 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011937 if (context_->IsModuleContext()) {
11938 return ScopeTypeModule;
11939 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011940 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011941 return ScopeTypeWith;
11942 }
11943
11944 // Return the JavaScript object with the content of the current scope.
11945 Handle<JSObject> ScopeObject() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011946 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011947 switch (Type()) {
11948 case ScopeIterator::ScopeTypeGlobal:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011949 return Handle<JSObject>(CurrentContext()->global_object());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011950 case ScopeIterator::ScopeTypeLocal:
11951 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011952 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011953 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011954 case ScopeIterator::ScopeTypeWith:
11955 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011956 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11957 case ScopeIterator::ScopeTypeCatch:
11958 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011959 case ScopeIterator::ScopeTypeClosure:
11960 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011962 case ScopeIterator::ScopeTypeBlock:
11963 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011964 case ScopeIterator::ScopeTypeModule:
11965 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011966 }
11967 UNREACHABLE();
11968 return Handle<JSObject>();
11969 }
11970
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011971 bool SetVariableValue(Handle<String> variable_name,
11972 Handle<Object> new_value) {
11973 ASSERT(!failed_);
11974 switch (Type()) {
11975 case ScopeIterator::ScopeTypeGlobal:
11976 break;
11977 case ScopeIterator::ScopeTypeLocal:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011978 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
11979 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011980 case ScopeIterator::ScopeTypeWith:
11981 break;
11982 case ScopeIterator::ScopeTypeCatch:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011983 return SetCatchVariableValue(isolate_, CurrentContext(),
11984 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011985 case ScopeIterator::ScopeTypeClosure:
11986 return SetClosureVariableValue(isolate_, CurrentContext(),
11987 variable_name, new_value);
11988 case ScopeIterator::ScopeTypeBlock:
11989 // TODO(2399): should we implement it?
11990 break;
11991 case ScopeIterator::ScopeTypeModule:
11992 // TODO(2399): should we implement it?
11993 break;
11994 }
11995 return false;
11996 }
11997
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011998 Handle<ScopeInfo> CurrentScopeInfo() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011999 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012000 if (!nested_scope_chain_.is_empty()) {
12001 return nested_scope_chain_.last();
12002 } else if (context_->IsBlockContext()) {
12003 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
12004 } else if (context_->IsFunctionContext()) {
12005 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
12006 }
12007 return Handle<ScopeInfo>::null();
12008 }
12009
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012010 // Return the context for this scope. For the local context there might not
12011 // be an actual context.
12012 Handle<Context> CurrentContext() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012013 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012014 if (Type() == ScopeTypeGlobal ||
12015 nested_scope_chain_.is_empty()) {
12016 return context_;
12017 } else if (nested_scope_chain_.last()->HasContext()) {
12018 return context_;
12019 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012020 return Handle<Context>();
12021 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012022 }
12023
12024#ifdef DEBUG
12025 // Debug print of the content of the current scope.
12026 void DebugPrint() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012027 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012028 switch (Type()) {
12029 case ScopeIterator::ScopeTypeGlobal:
12030 PrintF("Global:\n");
12031 CurrentContext()->Print();
12032 break;
12033
12034 case ScopeIterator::ScopeTypeLocal: {
12035 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012036 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012037 if (!CurrentContext().is_null()) {
12038 CurrentContext()->Print();
12039 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012040 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012041 if (extension->IsJSContextExtensionObject()) {
12042 extension->Print();
12043 }
12044 }
12045 }
12046 break;
12047 }
12048
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012049 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012050 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012051 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012052 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012053
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012054 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000012055 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012056 CurrentContext()->extension()->Print();
12057 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012058 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012059
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012060 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012061 PrintF("Closure:\n");
12062 CurrentContext()->Print();
12063 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012064 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012065 if (extension->IsJSContextExtensionObject()) {
12066 extension->Print();
12067 }
12068 }
12069 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012070
12071 default:
12072 UNREACHABLE();
12073 }
12074 PrintF("\n");
12075 }
12076#endif
12077
12078 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012080 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012081 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012082 Handle<JSFunction> function_;
12083 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012084 List<Handle<ScopeInfo> > nested_scope_chain_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012085 bool failed_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012086
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012087 void RetrieveScopeChain(Scope* scope,
12088 Handle<SharedFunctionInfo> shared_info) {
12089 if (scope != NULL) {
12090 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12091 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12092 } else {
12093 // A failed reparse indicates that the preparser has diverged from the
12094 // parser or that the preparse data given to the initial parse has been
12095 // faulty. We fail in debug mode but in release mode we only provide the
12096 // information we get from the context chain but nothing about
12097 // completely stack allocated scopes or stack allocated locals.
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012098 // Or it could be due to stack overflow.
12099 ASSERT(isolate_->has_pending_exception());
12100 failed_ = true;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012101 }
12102 }
12103
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012104 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12105};
12106
12107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012108RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012109 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012110 ASSERT(args.length() == 2);
12111
12112 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012113 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012114 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12115 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012116 if (!maybe_check->ToObject(&check)) return maybe_check;
12117 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012118 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012119
12120 // Get the frame where the debugging is performed.
12121 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012122 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012123 JavaScriptFrame* frame = it.frame();
12124
12125 // Count the visible scopes.
12126 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012127 for (ScopeIterator it(isolate, frame, 0);
12128 !it.Done();
12129 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012130 n++;
12131 }
12132
12133 return Smi::FromInt(n);
12134}
12135
12136
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012137// Returns the list of step-in positions (text offset) in a function of the
12138// stack frame in a range from the current debug break position to the end
12139// of the corresponding statement.
12140RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) {
12141 HandleScope scope(isolate);
12142 ASSERT(args.length() == 2);
12143
12144 // Check arguments.
12145 Object* check;
12146 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12147 RUNTIME_ARGUMENTS(isolate, args));
12148 if (!maybe_check->ToObject(&check)) return maybe_check;
12149 }
12150 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12151
12152 // Get the frame where the debugging is performed.
12153 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12154 JavaScriptFrameIterator frame_it(isolate, id);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012155 RUNTIME_ASSERT(!frame_it.done());
12156
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012157 JavaScriptFrame* frame = frame_it.frame();
12158
danno@chromium.org59400602013-08-13 17:09:37 +000012159 Handle<JSFunction> fun =
12160 Handle<JSFunction>(frame->function());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012161 Handle<SharedFunctionInfo> shared =
danno@chromium.org59400602013-08-13 17:09:37 +000012162 Handle<SharedFunctionInfo>(fun->shared());
12163
12164 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12165 return isolate->heap()->undefined_value();
12166 }
12167
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012168 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12169
12170 int len = 0;
12171 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12172 // Find the break point where execution has stopped.
12173 BreakLocationIterator break_location_iterator(debug_info,
12174 ALL_BREAK_LOCATIONS);
12175
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012176 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012177 int current_statement_pos = break_location_iterator.statement_position();
12178
12179 while (!break_location_iterator.Done()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012180 bool accept;
danno@chromium.org59400602013-08-13 17:09:37 +000012181 if (break_location_iterator.pc() > frame->pc()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012182 accept = true;
12183 } else {
12184 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12185 // The break point is near our pc. Could be a step-in possibility,
12186 // that is currently taken by active debugger call.
12187 if (break_frame_id == StackFrame::NO_ID) {
12188 // We are not stepping.
12189 accept = false;
12190 } else {
12191 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12192 // If our frame is a top frame and we are stepping, we can do step-in
12193 // at this place.
12194 accept = additional_frame_it.frame()->id() == id;
12195 }
12196 }
12197 if (accept) {
danno@chromium.org59400602013-08-13 17:09:37 +000012198 if (break_location_iterator.IsStepInLocation(isolate)) {
12199 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12200 JSObject::SetElement(array, len,
12201 Handle<Object>(position_value, isolate),
12202 NONE, kNonStrictMode);
12203 len++;
12204 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012205 }
12206 // Advance iterator.
12207 break_location_iterator.Next();
12208 if (current_statement_pos !=
12209 break_location_iterator.statement_position()) {
12210 break;
12211 }
12212 }
12213 return *array;
12214}
12215
12216
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012217static const int kScopeDetailsTypeIndex = 0;
12218static const int kScopeDetailsObjectIndex = 1;
12219static const int kScopeDetailsSize = 2;
12220
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012221
12222static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
12223 ScopeIterator* it) {
12224 // Calculate the size of the result.
12225 int details_size = kScopeDetailsSize;
12226 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12227
12228 // Fill in scope details.
12229 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12230 Handle<JSObject> scope_object = it->ScopeObject();
12231 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
12232 details->set(kScopeDetailsObjectIndex, *scope_object);
12233
12234 return *isolate->factory()->NewJSArrayWithElements(details);
12235}
12236
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000012237
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012238// Return an array with scope details
12239// args[0]: number: break id
12240// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012241// args[2]: number: inlined frame index
12242// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012243//
12244// The array returned contains the following information:
12245// 0: Scope type
12246// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012247RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012249 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012250
12251 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012252 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012253 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12254 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012255 if (!maybe_check->ToObject(&check)) return maybe_check;
12256 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012257 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012258 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012259 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012260
12261 // Get the frame where the debugging is performed.
12262 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012263 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012264 JavaScriptFrame* frame = frame_it.frame();
12265
12266 // Find the requested scope.
12267 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012268 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012269 for (; !it.Done() && n < index; it.Next()) {
12270 n++;
12271 }
12272 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012273 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012274 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012275 return MaterializeScopeDetails(isolate, &it);
12276}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012277
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012278
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
12280 HandleScope scope(isolate);
12281 ASSERT(args.length() == 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012282
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012283 // Check arguments.
12284 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12285
12286 // Count the visible scopes.
12287 int n = 0;
12288 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12289 n++;
12290 }
12291
12292 return Smi::FromInt(n);
12293}
12294
12295
12296RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
12297 HandleScope scope(isolate);
12298 ASSERT(args.length() == 2);
12299
12300 // Check arguments.
12301 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12302 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12303
12304 // Find the requested scope.
12305 int n = 0;
12306 ScopeIterator it(isolate, fun);
12307 for (; !it.Done() && n < index; it.Next()) {
12308 n++;
12309 }
12310 if (it.Done()) {
12311 return isolate->heap()->undefined_value();
12312 }
12313
12314 return MaterializeScopeDetails(isolate, &it);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012315}
12316
12317
mmassi@chromium.org49a44672012-12-04 13:52:03 +000012318static bool SetScopeVariableValue(ScopeIterator* it, int index,
12319 Handle<String> variable_name,
12320 Handle<Object> new_value) {
12321 for (int n = 0; !it->Done() && n < index; it->Next()) {
12322 n++;
12323 }
12324 if (it->Done()) {
12325 return false;
12326 }
12327 return it->SetVariableValue(variable_name, new_value);
12328}
12329
12330
12331// Change variable value in closure or local scope
12332// args[0]: number or JsFunction: break id or function
12333// args[1]: number: frame index (when arg[0] is break id)
12334// args[2]: number: inlined frame index (when arg[0] is break id)
12335// args[3]: number: scope index
12336// args[4]: string: variable name
12337// args[5]: object: new value
12338//
12339// Return true if success and false otherwise
12340RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
12341 HandleScope scope(isolate);
12342 ASSERT(args.length() == 6);
12343
12344 // Check arguments.
12345 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12346 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12347 Handle<Object> new_value = args.at<Object>(5);
12348
12349 bool res;
12350 if (args[0]->IsNumber()) {
12351 Object* check;
12352 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12353 RUNTIME_ARGUMENTS(isolate, args));
12354 if (!maybe_check->ToObject(&check)) return maybe_check;
12355 }
12356 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12357 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12358
12359 // Get the frame where the debugging is performed.
12360 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12361 JavaScriptFrameIterator frame_it(isolate, id);
12362 JavaScriptFrame* frame = frame_it.frame();
12363
12364 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12365 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12366 } else {
12367 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12368 ScopeIterator it(isolate, fun);
12369 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12370 }
12371
12372 return isolate->heap()->ToBoolean(res);
12373}
12374
12375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012376RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012377 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012378 ASSERT(args.length() == 0);
12379
12380#ifdef DEBUG
12381 // Print the scopes for the top frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000012382 StackFrameLocator locator(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012383 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012384 for (ScopeIterator it(isolate, frame, 0);
12385 !it.Done();
12386 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012387 it.DebugPrint();
12388 }
12389#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012390 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012391}
12392
12393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012394RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012395 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012396 ASSERT(args.length() == 1);
12397
12398 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012399 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012400 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12401 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012402 if (!maybe_result->ToObject(&result)) return maybe_result;
12403 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012404
12405 // Count all archived V8 threads.
12406 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012407 for (ThreadState* thread =
12408 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012409 thread != NULL;
12410 thread = thread->Next()) {
12411 n++;
12412 }
12413
12414 // Total number of threads is current thread and archived threads.
12415 return Smi::FromInt(n + 1);
12416}
12417
12418
12419static const int kThreadDetailsCurrentThreadIndex = 0;
12420static const int kThreadDetailsThreadIdIndex = 1;
12421static const int kThreadDetailsSize = 2;
12422
12423// Return an array with thread details
12424// args[0]: number: break id
12425// args[1]: number: thread index
12426//
12427// The array returned contains the following information:
12428// 0: Is current thread?
12429// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012430RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012432 ASSERT(args.length() == 2);
12433
12434 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012435 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012436 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12437 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012438 if (!maybe_check->ToObject(&check)) return maybe_check;
12439 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012440 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12441
12442 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012443 Handle<FixedArray> details =
12444 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012445
12446 // Thread index 0 is current thread.
12447 if (index == 0) {
12448 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012449 details->set(kThreadDetailsCurrentThreadIndex,
12450 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012451 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012452 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012453 } else {
12454 // Find the thread with the requested index.
12455 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 ThreadState* thread =
12457 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012458 while (index != n && thread != NULL) {
12459 thread = thread->Next();
12460 n++;
12461 }
12462 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012463 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012464 }
12465
12466 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 details->set(kThreadDetailsCurrentThreadIndex,
12468 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012469 details->set(kThreadDetailsThreadIdIndex,
12470 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012471 }
12472
12473 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012474 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012475}
12476
12477
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012478// Sets the disable break state
12479// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012480RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012481 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012482 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012483 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012484 isolate->debug()->set_disable_break(disable_break);
12485 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012486}
12487
12488
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012489static bool IsPositionAlignmentCodeCorrect(int alignment) {
12490 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12491}
12492
12493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012494RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012496 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012497
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012498 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012499 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12500
12501 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12502 return isolate->ThrowIllegalOperation();
12503 }
12504 BreakPositionAlignment alignment =
12505 static_cast<BreakPositionAlignment>(statement_aligned_code);
12506
ager@chromium.org5aa501c2009-06-23 07:57:28 +000012507 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012508 // Find the number of break points
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012509 Handle<Object> break_locations =
12510 Debug::GetSourceBreakLocations(shared, alignment);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012513 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514 Handle<FixedArray>::cast(break_locations));
12515}
12516
12517
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012518// Set a break point in a function.
12519// args[0]: function
12520// args[1]: number: break source position (within the function source)
12521// args[2]: number: break point object
12522RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
12523 HandleScope scope(isolate);
12524 ASSERT(args.length() == 3);
12525 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12526 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12527 RUNTIME_ASSERT(source_position >= 0);
12528 Handle<Object> break_point_object_arg = args.at<Object>(2);
12529
12530 // Set break point.
12531 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12532 &source_position);
12533
12534 return Smi::FromInt(source_position);
12535}
12536
12537
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012538// Changes the state of a break point in a script and returns source position
12539// where break point was set. NOTE: Regarding performance see the NOTE for
12540// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012541// args[0]: script to set break point in
12542// args[1]: number: break source position (within the script source)
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012543// args[2]: number, breakpoint position alignment
12544// args[3]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012545RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012547 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012548 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012549 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12550 RUNTIME_ASSERT(source_position >= 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012551 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12552 Handle<Object> break_point_object_arg = args.at<Object>(3);
12553
12554 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12555 return isolate->ThrowIllegalOperation();
12556 }
12557 BreakPositionAlignment alignment =
12558 static_cast<BreakPositionAlignment>(statement_aligned_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012559
12560 // Get the script from the script wrapper.
12561 RUNTIME_ASSERT(wrapper->value()->IsScript());
12562 Handle<Script> script(Script::cast(wrapper->value()));
12563
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012564 // Set break point.
12565 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012566 &source_position,
12567 alignment)) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000012568 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012569 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012570
12571 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012572}
12573
12574
12575// Clear a break point
12576// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012577RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012579 ASSERT(args.length() == 1);
12580 Handle<Object> break_point_object_arg = args.at<Object>(0);
12581
12582 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012583 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012584
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012586}
12587
12588
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012589// Change the state of break on exceptions.
12590// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12591// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012592RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012594 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012595 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012596 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012597
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012598 // If the number doesn't match an enum value, the ChangeBreakOnException
12599 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012600 ExceptionBreakType type =
12601 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012602 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 isolate->debug()->ChangeBreakOnException(type, enable);
12604 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012605}
12606
12607
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012608// Returns the state of break on exceptions
12609// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012610RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012611 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012612 ASSERT(args.length() == 1);
12613 RUNTIME_ASSERT(args[0]->IsNumber());
12614
12615 ExceptionBreakType type =
12616 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012618 return Smi::FromInt(result);
12619}
12620
12621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012622// Prepare for stepping
12623// args[0]: break id for checking execution state
12624// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000012625// args[2]: number of times to perform the step, for step out it is the number
12626// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012627RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 HandleScope scope(isolate);
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012629 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012630 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012631 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012632 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12633 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012634 if (!maybe_check->ToObject(&check)) return maybe_check;
12635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012636 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012637 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012638 }
12639
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012640 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12641
12642 StackFrame::Id frame_id;
12643 if (wrapped_frame_id == 0) {
12644 frame_id = StackFrame::NO_ID;
12645 } else {
12646 frame_id = UnwrapFrameId(wrapped_frame_id);
12647 }
12648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012649 // Get the step action and check validity.
12650 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12651 if (step_action != StepIn &&
12652 step_action != StepNext &&
12653 step_action != StepOut &&
12654 step_action != StepInMin &&
12655 step_action != StepMin) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012656 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012657 }
12658
mvstanton@chromium.org63ea3d22013-10-10 09:24:12 +000012659 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12660 step_action != StepMin && step_action != StepOut) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012661 return isolate->ThrowIllegalOperation();
12662 }
12663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012664 // Get the number of steps.
12665 int step_count = NumberToInt32(args[2]);
12666 if (step_count < 1) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012667 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012668 }
12669
ager@chromium.orga1645e22009-09-09 19:27:10 +000012670 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012671 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012673 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012675 step_count,
12676 frame_id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012677 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012678}
12679
12680
12681// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012682RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012684 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012685 isolate->debug()->ClearStepping();
12686 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012687}
12688
12689
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012690// Helper function to find or create the arguments object for
12691// Runtime_DebugEvaluate.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012692static Handle<JSObject> MaterializeArgumentsObject(
12693 Isolate* isolate,
12694 Handle<JSObject> target,
12695 Handle<JSFunction> function) {
12696 // Do not materialize the arguments object for eval or top-level code.
12697 // Skip if "arguments" is already taken.
12698 if (!function->shared()->is_function() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012699 JSReceiver::HasLocalProperty(target,
12700 isolate->factory()->arguments_string())) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012701 return target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012702 }
12703
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012704 // FunctionGetArguments can't throw an exception.
12705 Handle<JSObject> arguments = Handle<JSObject>::cast(
12706 Accessors::FunctionGetArguments(function));
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000012707 Runtime::SetObjectProperty(isolate, target,
12708 isolate->factory()->arguments_string(),
12709 arguments,
12710 ::NONE,
12711 kNonStrictMode);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012712 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
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012728 Handle<JSFunction> eval_fun =
yangguo@chromium.org49546742013-12-23 16:17:49 +000012729 Compiler::GetFunctionFromEval(source,
12730 context,
12731 CLASSIC_MODE,
12732 NO_PARSE_RESTRICTION,
12733 RelocInfo::kNoPosition);
12734 RETURN_IF_EMPTY_HANDLE(isolate, eval_fun);
12735
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012736 bool pending_exception;
12737 Handle<Object> result = Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000012738 isolate, eval_fun, receiver, 0, NULL, &pending_exception);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012739
12740 if (pending_exception) return Failure::Exception();
12741
12742 // Skip the global proxy as it has no properties and always delegates to the
12743 // real global object.
12744 if (result->IsJSGlobalProxy()) {
12745 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
12746 }
12747
12748 // Clear the oneshot breakpoints so that the debugger does not step further.
12749 isolate->debug()->ClearStepping();
12750 return *result;
12751}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012752
12753
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012754// Evaluate a piece of JavaScript in the context of a stack frame for
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012755// debugging. Things that need special attention are:
12756// - Parameters and stack-allocated locals need to be materialized. Altered
12757// values need to be written back to the stack afterwards.
12758// - The arguments object needs to materialized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012759RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012760 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012761
12762 // Check the execution state and decode arguments frame and source to be
12763 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012764 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012765 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012766 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012767 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012768 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012769 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012770 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012771 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012772 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12773 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012774 Handle<Object> context_extension(args[5], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012775
12776 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012777 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012778
12779 // Get the frame where the debugging is performed.
12780 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012781 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012782 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012783 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12784 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012785
12786 // Traverse the saved contexts chain to find the active context for the
12787 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012788 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012790 SaveContext savex(isolate);
12791 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012792
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012793 // Evaluate on the context of the frame.
12794 Handle<Context> context(Context::cast(frame->context()));
12795 ASSERT(!context.is_null());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012796
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012797 // Materialize stack locals and the arguments object.
12798 Handle<JSObject> materialized =
12799 isolate->factory()->NewJSObject(isolate->object_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012800
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012801 materialized = MaterializeStackLocalsWithFrameInspector(
12802 isolate, materialized, function, &frame_inspector);
12803 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012804
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012805 materialized = MaterializeArgumentsObject(isolate, materialized, function);
12806 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012807
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012808 // Add the materialized object in a with-scope to shadow the stack locals.
12809 context = isolate->factory()->NewWithContext(function, context, materialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012811 Handle<Object> receiver(frame->receiver(), isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012812 Object* evaluate_result_object;
12813 { MaybeObject* maybe_result =
12814 DebugEvaluate(isolate, context, context_extension, receiver, source);
12815 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
12816 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012817
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012818 Handle<Object> result(evaluate_result_object, isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012819
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012820 // Write back potential changes to materialized stack locals to the stack.
12821 UpdateStackLocalsFromMaterializedObject(
12822 isolate, materialized, function, frame, inlined_jsframe_index);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012823
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012824 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012825}
12826
12827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012829 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012830
12831 // Check the execution state and decode arguments frame and source to be
12832 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012833 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012834 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012835 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012836 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012837 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012838 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012839 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12840 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012841 Handle<Object> context_extension(args[3], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012842
12843 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012844 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012845
12846 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012847 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012848 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012850 top = top->prev();
12851 }
12852 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012853 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012854 }
12855
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012856 // Get the native context now set to the top context from before the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012857 // debugger was invoked.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012858 Handle<Context> context = isolate->native_context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012859 Handle<Object> receiver = isolate->global_object();
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012860 return DebugEvaluate(isolate, context, context_extension, receiver, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012861}
12862
12863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012864RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012865 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012866 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012868 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012870
12871 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012872 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012873 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12874 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12875 // because using
12876 // instances->set(i, *GetScriptWrapper(script))
12877 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012878 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012879 Handle<JSValue> wrapper = GetScriptWrapper(script);
12880 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012881 }
12882
12883 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012884 Handle<JSObject> result =
12885 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012886 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012887 return *result;
12888}
12889
12890
12891// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012892static int DebugReferencedBy(HeapIterator* iterator,
12893 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012894 Object* instance_filter, int max_references,
12895 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012896 JSFunction* arguments_function) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012897 Isolate* isolate = target->GetIsolate();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012898 SealHandleScope shs(isolate);
12899 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012900
12901 // Iterate the heap.
12902 int count = 0;
12903 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012904 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012905 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012906 (max_references == 0 || count < max_references)) {
12907 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012908 if (heap_obj->IsJSObject()) {
12909 // Skip context extension objects and argument arrays as these are
12910 // checked in the context of functions using them.
12911 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012912 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012913 obj->map()->constructor() == arguments_function) {
12914 continue;
12915 }
12916
12917 // Check if the JS object has a reference to the object looked for.
12918 if (obj->ReferencesObject(target)) {
12919 // Check instance filter if supplied. This is normally used to avoid
12920 // references from mirror objects (see Runtime_IsInPrototypeChain).
12921 if (!instance_filter->IsUndefined()) {
12922 Object* V = obj;
12923 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012924 Object* prototype = V->GetPrototype(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012925 if (prototype->IsNull()) {
12926 break;
12927 }
12928 if (instance_filter == prototype) {
12929 obj = NULL; // Don't add this object.
12930 break;
12931 }
12932 V = prototype;
12933 }
12934 }
12935
12936 if (obj != NULL) {
12937 // Valid reference found add to instance array if supplied an update
12938 // count.
12939 if (instances != NULL && count < instances_size) {
12940 instances->set(count, obj);
12941 }
12942 last = obj;
12943 count++;
12944 }
12945 }
12946 }
12947 }
12948
12949 // Check for circular reference only. This can happen when the object is only
12950 // referenced from mirrors and has a circular reference in which case the
12951 // object is not really alive and would have been garbage collected if not
12952 // referenced from the mirror.
12953 if (count == 1 && last == target) {
12954 count = 0;
12955 }
12956
12957 // Return the number of referencing objects found.
12958 return count;
12959}
12960
12961
12962// Scan the heap for objects with direct references to an object
12963// args[0]: the object to find references to
12964// args[1]: constructor function for instances to exclude (Mirror)
12965// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012966RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012967 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012968 ASSERT(args.length() == 3);
12969
12970 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012971 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12972 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012973 // The heap iterator reserves the right to do a GC to make the heap iterable.
12974 // Due to the GC above we know it won't need to do that, but it seems cleaner
12975 // to get the heap iterator constructed before we start having unprotected
12976 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012977
12978 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012979 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012980 Object* instance_filter = args[1];
12981 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12982 instance_filter->IsJSObject());
12983 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12984 RUNTIME_ASSERT(max_references >= 0);
12985
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012987 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012988 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012989 isolate->context()->native_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012990 JSFunction* arguments_function =
12991 JSFunction::cast(arguments_boilerplate->map()->constructor());
12992
12993 // Get the number of referencing objects.
12994 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012995 Heap* heap = isolate->heap();
12996 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012997 count = DebugReferencedBy(&heap_iterator,
12998 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012999 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013000
13001 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013002 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013003 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013004 if (!maybe_object->ToObject(&object)) return maybe_object;
13005 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013006 FixedArray* instances = FixedArray::cast(object);
13007
13008 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013009 // AllocateFixedArray above does not make the heap non-iterable.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013010 ASSERT(heap->IsHeapIterable());
13011 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013012 count = DebugReferencedBy(&heap_iterator2,
13013 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000013014 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013015
13016 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013017 Object* result;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013018 MaybeObject* maybe_result = heap->AllocateJSObject(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013019 isolate->context()->native_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013020 if (!maybe_result->ToObject(&result)) return maybe_result;
13021 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013022}
13023
13024
13025// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013026static int DebugConstructedBy(HeapIterator* iterator,
13027 JSFunction* constructor,
13028 int max_references,
13029 FixedArray* instances,
13030 int instances_size) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013031 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013032
13033 // Iterate the heap.
13034 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013035 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013036 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013037 (max_references == 0 || count < max_references)) {
13038 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013039 if (heap_obj->IsJSObject()) {
13040 JSObject* obj = JSObject::cast(heap_obj);
13041 if (obj->map()->constructor() == constructor) {
13042 // Valid reference found add to instance array if supplied an update
13043 // count.
13044 if (instances != NULL && count < instances_size) {
13045 instances->set(count, obj);
13046 }
13047 count++;
13048 }
13049 }
13050 }
13051
13052 // Return the number of referencing objects found.
13053 return count;
13054}
13055
13056
13057// Scan the heap for objects constructed by a specific function.
13058// args[0]: the constructor to find instances of
13059// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013060RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013061 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013062 ASSERT(args.length() == 2);
13063
13064 // First perform a full GC in order to avoid dead objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013065 Heap* heap = isolate->heap();
13066 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013067
13068 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013069 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013070 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13071 RUNTIME_ASSERT(max_references >= 0);
13072
13073 // Get the number of referencing objects.
13074 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013075 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013076 count = DebugConstructedBy(&heap_iterator,
13077 constructor,
13078 max_references,
13079 NULL,
13080 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013081
13082 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013083 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013084 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013085 if (!maybe_object->ToObject(&object)) return maybe_object;
13086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013087 FixedArray* instances = FixedArray::cast(object);
13088
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000013089 ASSERT(isolate->heap()->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090 // Fill the referencing objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013091 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013092 count = DebugConstructedBy(&heap_iterator2,
13093 constructor,
13094 max_references,
13095 instances,
13096 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013097
13098 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013099 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013100 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013101 isolate->context()->native_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013102 if (!maybe_result->ToObject(&result)) return maybe_result;
13103 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013104 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013105}
13106
13107
ager@chromium.orgddb913d2009-01-27 10:01:48 +000013108// Find the effective prototype object as returned by __proto__.
13109// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013110RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013111 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013112 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013113 CONVERT_ARG_CHECKED(JSObject, obj, 0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013114 return GetPrototypeSkipHiddenPrototypes(isolate, obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013115}
13116
13117
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013118// Patches script source (should be called upon BeforeCompile event).
13119RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
13120 HandleScope scope(isolate);
13121 ASSERT(args.length() == 2);
13122
13123 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013124 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013125
13126 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13127 Handle<Script> script(Script::cast(script_wrapper->value()));
13128
danno@chromium.orgd3c42102013-08-01 16:58:23 +000013129 int compilation_state = script->compilation_state();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013130 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13131 script->set_source(*source);
13132
13133 return isolate->heap()->undefined_value();
13134}
13135
13136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013137RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013138 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000013139 ASSERT(args.length() == 0);
rossberg@chromium.org92597162013-08-23 13:28:00 +000013140 OS::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013141 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013142}
13143
13144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013145RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013146 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013147#ifdef DEBUG
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013148 ASSERT(args.length() == 1);
13149 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013150 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +000013151 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013152 return Failure::Exception();
13153 }
13154 func->code()->PrintLn();
13155#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013156 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013157}
ager@chromium.org9085a012009-05-11 19:22:57 +000013158
13159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013160RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013161 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013162#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013163 ASSERT(args.length() == 1);
13164 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013165 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +000013166 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013167 return Failure::Exception();
13168 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +000013169 func->shared()->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013170#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013171 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013172}
13173
13174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013175RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013176 SealHandleScope shs(isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +000013177 ASSERT(args.length() == 1);
13178
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013179 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000013180 return f->shared()->inferred_name();
13181}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013182
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013183
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013184static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13185 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013186 FixedArray* buffer) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013187 DisallowHeapAllocation no_allocation;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013188 int counter = 0;
13189 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013190 for (HeapObject* obj = iterator->next();
13191 obj != NULL;
13192 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013193 ASSERT(obj != NULL);
13194 if (!obj->IsSharedFunctionInfo()) {
13195 continue;
13196 }
13197 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13198 if (shared->script() != script) {
13199 continue;
13200 }
13201 if (counter < buffer_size) {
13202 buffer->set(counter, shared);
13203 }
13204 counter++;
13205 }
13206 return counter;
13207}
13208
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013209
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013210// For a script finds all SharedFunctionInfo's in the heap that points
13211// to this script. Returns JSArray of SharedFunctionInfo wrapped
13212// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013213RUNTIME_FUNCTION(MaybeObject*,
13214 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013215 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013216 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013217 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013218 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013219
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013220 RUNTIME_ASSERT(script_value->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013221 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13222
13223 const int kBufferSize = 32;
13224
13225 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013226 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013227 int number;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013228 Heap* heap = isolate->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013229 {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013230 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013231 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013232 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013233 Script* scr = *script;
13234 FixedArray* arr = *array;
13235 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13236 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013237 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013238 array = isolate->factory()->NewFixedArray(number);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013239 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013240 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013241 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013242 Script* scr = *script;
13243 FixedArray* arr = *array;
13244 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013245 }
13246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013247 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013248 result->set_length(Smi::FromInt(number));
13249
13250 LiveEdit::WrapSharedFunctionInfos(result);
13251
13252 return *result;
13253}
13254
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013255
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013256// For a script calculates compilation information about all its functions.
13257// The script source is explicitly specified by the second argument.
13258// The source of the actual script is not used, however it is important that
13259// all generated code keeps references to this particular instance of script.
13260// Returns a JSArray of compilation infos. The array is ordered so that
13261// each function with all its descendant is always stored in a continues range
13262// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013263RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013264 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013265 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013266 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013267 CONVERT_ARG_CHECKED(JSValue, script, 0);
13268 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013269
13270 RUNTIME_ASSERT(script->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013271 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13272
13273 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
13274
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013275 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013276 return Failure::Exception();
13277 }
13278
13279 return result;
13280}
13281
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013282
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013283// Changes the source of the script to a new_source.
13284// If old_script_name is provided (i.e. is a String), also creates a copy of
13285// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013286RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013287 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013288 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013289 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013290 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13291 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013292 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013293
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013294 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13295 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013296
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013297 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
13298 new_source,
13299 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013300
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013301 if (old_script->IsScript()) {
13302 Handle<Script> script_handle(Script::cast(old_script));
13303 return *(GetScriptWrapper(script_handle));
13304 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013305 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013306 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013307}
13308
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013310RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013311 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013312 CHECK(isolate->debugger()->live_edit_enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013313 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013314 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013315 return LiveEdit::FunctionSourceUpdated(shared_info);
13316}
13317
13318
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013319// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013320RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013321 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013322 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013323 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013324 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13325 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013326
ager@chromium.orgac091b72010-05-05 07:34:42 +000013327 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013328}
13329
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013330
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013331// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013332RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013333 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013334 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013335 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013336 Handle<Object> function_object(args[0], isolate);
13337 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013338
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013339 if (function_object->IsJSValue()) {
13340 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13341 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013342 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13343 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013344 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013345 }
13346
13347 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13348 } else {
13349 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13350 // and we check it in this function.
13351 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013353 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013354}
13355
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013356
13357// In a code of a parent function replaces original function as embedded object
13358// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013359RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013360 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013361 CHECK(isolate->debugger()->live_edit_enabled());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013362 ASSERT(args.length() == 3);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013363
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013364 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13365 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13366 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013367
13368 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
13369 subst_wrapper);
13370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013371 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013372}
13373
13374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013375// Updates positions of a shared function info (first parameter) according
13376// to script source change. Text change is described in second parameter as
13377// array of groups of 3 numbers:
13378// (change_begin, change_end, change_end_new_position).
13379// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013380RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013381 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013382 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013383 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013384 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13385 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013386
ager@chromium.orgac091b72010-05-05 07:34:42 +000013387 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013388}
13389
13390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013391// For array of SharedFunctionInfo's (each wrapped in JSValue)
13392// checks that none of them have activations on stacks (of any thread).
13393// Returns array of the same length with corresponding results of
13394// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013395RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013396 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013397 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.org357bf652010-04-12 11:30:10 +000013398 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013399 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13400 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013401
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013402 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013403}
13404
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013405
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013406// Compares 2 strings line-by-line, then token-wise and returns diff in form
13407// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13408// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013409RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013410 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013411 CHECK(isolate->debugger()->live_edit_enabled());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013412 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013413 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13414 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013415
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013416 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013417}
13418
13419
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013420// Restarts a call frame and completely drops all frames above.
13421// Returns true if successful. Otherwise returns undefined or an error message.
13422RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
13423 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013424 CHECK(isolate->debugger()->live_edit_enabled());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013425 ASSERT(args.length() == 2);
13426
13427 // Check arguments.
13428 Object* check;
13429 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
13430 RUNTIME_ARGUMENTS(isolate, args));
13431 if (!maybe_check->ToObject(&check)) return maybe_check;
13432 }
13433 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13434 Heap* heap = isolate->heap();
13435
13436 // Find the relevant frame with the requested index.
13437 StackFrame::Id id = isolate->debug()->break_frame_id();
13438 if (id == StackFrame::NO_ID) {
13439 // If there are no JavaScript stack frames return undefined.
13440 return heap->undefined_value();
13441 }
13442
13443 int count = 0;
13444 JavaScriptFrameIterator it(isolate, id);
13445 for (; !it.done(); it.Advance()) {
13446 if (index < count + it.frame()->GetInlineCount()) break;
13447 count += it.frame()->GetInlineCount();
13448 }
13449 if (it.done()) return heap->undefined_value();
13450
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013451 const char* error_message = LiveEdit::RestartFrame(it.frame());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013452 if (error_message) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013453 return *(isolate->factory()->InternalizeUtf8String(error_message));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013454 }
13455 return heap->true_value();
13456}
13457
13458
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013459// A testing entry. Returns statement position which is the closest to
13460// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013461RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013462 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013463 CHECK(isolate->debugger()->live_edit_enabled());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013464 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013465 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013466 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013468 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013469
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013470 if (code->kind() != Code::FUNCTION &&
13471 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013472 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013473 }
13474
13475 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013476 int closest_pc = 0;
13477 int distance = kMaxInt;
13478 while (!it.done()) {
13479 int statement_position = static_cast<int>(it.rinfo()->data());
13480 // Check if this break point is closer that what was previously found.
13481 if (source_position <= statement_position &&
13482 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000013483 closest_pc =
13484 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013485 distance = statement_position - source_position;
13486 // Check whether we can't get any closer.
13487 if (distance == 0) break;
13488 }
13489 it.next();
13490 }
13491
13492 return Smi::FromInt(closest_pc);
13493}
13494
13495
ager@chromium.org357bf652010-04-12 11:30:10 +000013496// Calls specified function with or without entering the debugger.
13497// This is used in unit tests to run code as if debugger is entered or simply
13498// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013499RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013500 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013501 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013502 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13503 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000013504
13505 Handle<Object> result;
13506 bool pending_exception;
13507 {
13508 if (without_debugger) {
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013509 result = Execution::Call(isolate,
13510 function,
13511 isolate->global_object(),
13512 0,
13513 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013514 &pending_exception);
13515 } else {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013516 EnterDebugger enter_debugger(isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013517 result = Execution::Call(isolate,
13518 function,
13519 isolate->global_object(),
13520 0,
13521 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013522 &pending_exception);
13523 }
13524 }
13525 if (!pending_exception) {
13526 return *result;
13527 } else {
13528 return Failure::Exception();
13529 }
13530}
13531
13532
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013533// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013534RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013535 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013536 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000013537 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013538 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +000013539 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013540 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013541}
13542
13543
13544// Performs a GC.
13545// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013546RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013547 SealHandleScope shs(isolate);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000013548 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013549 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013550}
13551
13552
13553// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013554RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013555 SealHandleScope shs(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013556 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013557 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013558 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013559 }
13560 return Smi::FromInt(usage);
13561}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013562
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013563#endif // ENABLE_DEBUGGER_SUPPORT
13564
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013565
danno@chromium.org59400602013-08-13 17:09:37 +000013566#ifdef V8_I18N_SUPPORT
13567RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) {
13568 HandleScope scope(isolate);
13569
13570 ASSERT(args.length() == 1);
13571 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13572
13573 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13574
13575 // Return value which denotes invalid language tag.
13576 const char* const kInvalidTag = "invalid-tag";
13577
13578 UErrorCode error = U_ZERO_ERROR;
13579 char icu_result[ULOC_FULLNAME_CAPACITY];
13580 int icu_length = 0;
13581
13582 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13583 &icu_length, &error);
13584 if (U_FAILURE(error) || icu_length == 0) {
13585 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13586 }
13587
13588 char result[ULOC_FULLNAME_CAPACITY];
13589
13590 // Force strict BCP47 rules.
13591 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13592
13593 if (U_FAILURE(error)) {
13594 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13595 }
13596
13597 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13598}
13599
13600
13601RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) {
13602 HandleScope scope(isolate);
13603
13604 ASSERT(args.length() == 1);
13605 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13606
13607 const icu::Locale* available_locales = NULL;
13608 int32_t count = 0;
13609
13610 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13611 available_locales = icu::Collator::getAvailableLocales(count);
13612 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13613 available_locales = icu::NumberFormat::getAvailableLocales(count);
13614 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13615 available_locales = icu::DateFormat::getAvailableLocales(count);
13616 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13617 available_locales = icu::BreakIterator::getAvailableLocales(count);
13618 }
13619
13620 UErrorCode error = U_ZERO_ERROR;
13621 char result[ULOC_FULLNAME_CAPACITY];
13622 Handle<JSObject> locales =
13623 isolate->factory()->NewJSObject(isolate->object_function());
13624
13625 for (int32_t i = 0; i < count; ++i) {
13626 const char* icu_name = available_locales[i].getName();
13627
13628 error = U_ZERO_ERROR;
13629 // No need to force strict BCP47 rules.
13630 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13631 if (U_FAILURE(error)) {
13632 // This shouldn't happen, but lets not break the user.
13633 continue;
13634 }
13635
13636 RETURN_IF_EMPTY_HANDLE(isolate,
13637 JSObject::SetLocalPropertyIgnoreAttributes(
13638 locales,
13639 isolate->factory()->NewStringFromAscii(CStrVector(result)),
13640 isolate->factory()->NewNumber(i),
13641 NONE));
13642 }
13643
13644 return *locales;
13645}
13646
13647
13648RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) {
13649 SealHandleScope shs(isolate);
13650
13651 ASSERT(args.length() == 0);
13652
13653 icu::Locale default_locale;
13654
13655 // Set the locale
13656 char result[ULOC_FULLNAME_CAPACITY];
13657 UErrorCode status = U_ZERO_ERROR;
13658 uloc_toLanguageTag(
13659 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13660 if (U_SUCCESS(status)) {
13661 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13662 }
13663
13664 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und"));
13665}
13666
13667
13668RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
13669 HandleScope scope(isolate);
13670
13671 ASSERT(args.length() == 1);
13672
13673 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13674
13675 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13676 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length);
13677 Handle<Name> maximized =
13678 isolate->factory()->NewStringFromAscii(CStrVector("maximized"));
13679 Handle<Name> base =
13680 isolate->factory()->NewStringFromAscii(CStrVector("base"));
13681 for (unsigned int i = 0; i < length; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000013682 MaybeObject* maybe_string = input->GetElement(isolate, i);
danno@chromium.org59400602013-08-13 17:09:37 +000013683 Object* locale_id;
13684 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) {
13685 return isolate->Throw(isolate->heap()->illegal_argument_string());
13686 }
13687
13688 v8::String::Utf8Value utf8_locale_id(
13689 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id))));
13690
13691 UErrorCode error = U_ZERO_ERROR;
13692
13693 // Convert from BCP47 to ICU format.
13694 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13695 char icu_locale[ULOC_FULLNAME_CAPACITY];
13696 int icu_locale_length = 0;
13697 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13698 &icu_locale_length, &error);
13699 if (U_FAILURE(error) || icu_locale_length == 0) {
13700 return isolate->Throw(isolate->heap()->illegal_argument_string());
13701 }
13702
13703 // Maximize the locale.
13704 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13705 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13706 uloc_addLikelySubtags(
13707 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13708
13709 // Remove extensions from maximized locale.
13710 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13711 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13712 uloc_getBaseName(
13713 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13714
13715 // Get original name without extensions.
13716 // de_DE@collation=phonebook -> de_DE
13717 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13718 uloc_getBaseName(
13719 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13720
13721 // Convert from ICU locale format to BCP47 format.
13722 // de_Latn_DE -> de-Latn-DE
13723 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13724 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13725 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13726
13727 // de_DE -> de-DE
13728 char base_locale[ULOC_FULLNAME_CAPACITY];
13729 uloc_toLanguageTag(
13730 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13731
13732 if (U_FAILURE(error)) {
13733 return isolate->Throw(isolate->heap()->illegal_argument_string());
13734 }
13735
13736 Handle<JSObject> result =
13737 isolate->factory()->NewJSObject(isolate->object_function());
13738 RETURN_IF_EMPTY_HANDLE(isolate,
13739 JSObject::SetLocalPropertyIgnoreAttributes(
13740 result,
13741 maximized,
13742 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)),
13743 NONE));
13744 RETURN_IF_EMPTY_HANDLE(isolate,
13745 JSObject::SetLocalPropertyIgnoreAttributes(
13746 result,
13747 base,
13748 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)),
13749 NONE));
13750 output->set(i, *result);
13751 }
13752
13753 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output);
13754 result->set_length(Smi::FromInt(length));
13755 return *result;
13756}
13757
13758
13759RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
13760 HandleScope scope(isolate);
13761
13762 ASSERT(args.length() == 3);
13763
13764 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13765 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13766 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13767
13768 Handle<ObjectTemplateInfo> date_format_template =
13769 I18N::GetTemplate(isolate);
13770
13771 // Create an empty object wrapper.
13772 bool has_pending_exception = false;
13773 Handle<JSObject> local_object = Execution::InstantiateObject(
13774 date_format_template, &has_pending_exception);
13775 if (has_pending_exception) {
13776 ASSERT(isolate->has_pending_exception());
13777 return Failure::Exception();
13778 }
13779
13780 // Set date time formatter as internal field of the resulting JS object.
13781 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
13782 isolate, locale, options, resolved);
13783
13784 if (!date_format) return isolate->ThrowIllegalOperation();
13785
13786 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
13787
13788 RETURN_IF_EMPTY_HANDLE(isolate,
13789 JSObject::SetLocalPropertyIgnoreAttributes(
13790 local_object,
13791 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
13792 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13793 NONE));
13794
danno@chromium.org59400602013-08-13 17:09:37 +000013795 // Make object handle weak so we can delete the data format once GC kicks in.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013796 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000013797 GlobalHandles::MakeWeak(wrapper.location(),
13798 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013799 DateFormat::DeleteDateFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013800 return *local_object;
13801}
13802
13803
13804RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
13805 HandleScope scope(isolate);
13806
13807 ASSERT(args.length() == 2);
13808
13809 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13810 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
13811
13812 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013813 Handle<Object> value =
13814 Execution::ToNumber(isolate, date, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013815 if (has_pending_exception) {
13816 ASSERT(isolate->has_pending_exception());
13817 return Failure::Exception();
13818 }
13819
13820 icu::SimpleDateFormat* date_format =
13821 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13822 if (!date_format) return isolate->ThrowIllegalOperation();
13823
13824 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013825 date_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013826
13827 return *isolate->factory()->NewStringFromTwoByte(
13828 Vector<const uint16_t>(
13829 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13830 result.length()));
13831}
13832
13833
13834RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
13835 HandleScope scope(isolate);
13836
13837 ASSERT(args.length() == 2);
13838
13839 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13840 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
13841
13842 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
13843 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
13844 icu::SimpleDateFormat* date_format =
13845 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13846 if (!date_format) return isolate->ThrowIllegalOperation();
13847
13848 UErrorCode status = U_ZERO_ERROR;
13849 UDate date = date_format->parse(u_date, status);
13850 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13851
13852 bool has_pending_exception = false;
13853 Handle<JSDate> result = Handle<JSDate>::cast(
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013854 Execution::NewDate(
13855 isolate, static_cast<double>(date), &has_pending_exception));
danno@chromium.org59400602013-08-13 17:09:37 +000013856 if (has_pending_exception) {
13857 ASSERT(isolate->has_pending_exception());
13858 return Failure::Exception();
13859 }
13860 return *result;
13861}
13862
13863
13864RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
13865 HandleScope scope(isolate);
13866
13867 ASSERT(args.length() == 3);
13868
13869 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13870 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13871 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13872
13873 Handle<ObjectTemplateInfo> number_format_template =
13874 I18N::GetTemplate(isolate);
13875
13876 // Create an empty object wrapper.
13877 bool has_pending_exception = false;
13878 Handle<JSObject> local_object = Execution::InstantiateObject(
13879 number_format_template, &has_pending_exception);
13880 if (has_pending_exception) {
13881 ASSERT(isolate->has_pending_exception());
13882 return Failure::Exception();
13883 }
13884
13885 // Set number formatter as internal field of the resulting JS object.
13886 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
13887 isolate, locale, options, resolved);
13888
13889 if (!number_format) return isolate->ThrowIllegalOperation();
13890
13891 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
13892
13893 RETURN_IF_EMPTY_HANDLE(isolate,
13894 JSObject::SetLocalPropertyIgnoreAttributes(
13895 local_object,
13896 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
13897 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13898 NONE));
13899
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013900 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000013901 GlobalHandles::MakeWeak(wrapper.location(),
13902 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013903 NumberFormat::DeleteNumberFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013904 return *local_object;
13905}
13906
13907
13908RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
13909 HandleScope scope(isolate);
13910
13911 ASSERT(args.length() == 2);
13912
13913 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13914 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
13915
13916 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013917 Handle<Object> value = Execution::ToNumber(
13918 isolate, number, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013919 if (has_pending_exception) {
13920 ASSERT(isolate->has_pending_exception());
13921 return Failure::Exception();
13922 }
13923
13924 icu::DecimalFormat* number_format =
13925 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13926 if (!number_format) return isolate->ThrowIllegalOperation();
13927
13928 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013929 number_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013930
13931 return *isolate->factory()->NewStringFromTwoByte(
13932 Vector<const uint16_t>(
13933 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13934 result.length()));
13935}
13936
13937
13938RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
13939 HandleScope scope(isolate);
13940
13941 ASSERT(args.length() == 2);
13942
13943 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13944 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
13945
13946 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
13947 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
13948 icu::DecimalFormat* number_format =
13949 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13950 if (!number_format) return isolate->ThrowIllegalOperation();
13951
13952 UErrorCode status = U_ZERO_ERROR;
13953 icu::Formattable result;
13954 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
13955 // to be part of Chrome.
13956 // TODO(cira): Include currency parsing code using parseCurrency call.
13957 // We need to check if the formatter parses all currencies or only the
13958 // one it was constructed with (it will impact the API - how to return ISO
13959 // code and the value).
13960 number_format->parse(u_number, result, status);
13961 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13962
13963 switch (result.getType()) {
13964 case icu::Formattable::kDouble:
13965 return *isolate->factory()->NewNumber(result.getDouble());
13966 case icu::Formattable::kLong:
13967 return *isolate->factory()->NewNumberFromInt(result.getLong());
13968 case icu::Formattable::kInt64:
13969 return *isolate->factory()->NewNumber(
13970 static_cast<double>(result.getInt64()));
13971 default:
13972 return isolate->heap()->undefined_value();
13973 }
13974}
13975
13976
13977RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) {
13978 HandleScope scope(isolate);
13979
13980 ASSERT(args.length() == 3);
13981
13982 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13983 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13984 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13985
13986 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
13987
13988 // Create an empty object wrapper.
13989 bool has_pending_exception = false;
13990 Handle<JSObject> local_object = Execution::InstantiateObject(
13991 collator_template, &has_pending_exception);
13992 if (has_pending_exception) {
13993 ASSERT(isolate->has_pending_exception());
13994 return Failure::Exception();
13995 }
13996
13997 // Set collator as internal field of the resulting JS object.
13998 icu::Collator* collator = Collator::InitializeCollator(
13999 isolate, locale, options, resolved);
14000
14001 if (!collator) return isolate->ThrowIllegalOperation();
14002
14003 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
14004
14005 RETURN_IF_EMPTY_HANDLE(isolate,
14006 JSObject::SetLocalPropertyIgnoreAttributes(
14007 local_object,
14008 isolate->factory()->NewStringFromAscii(CStrVector("collator")),
14009 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14010 NONE));
14011
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014012 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000014013 GlobalHandles::MakeWeak(wrapper.location(),
14014 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014015 Collator::DeleteCollator);
danno@chromium.org59400602013-08-13 17:09:37 +000014016 return *local_object;
14017}
14018
14019
14020RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) {
14021 HandleScope scope(isolate);
14022
14023 ASSERT(args.length() == 3);
14024
14025 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14026 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14027 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14028
14029 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14030 if (!collator) return isolate->ThrowIllegalOperation();
14031
14032 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14033 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14034 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14035 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14036 UErrorCode status = U_ZERO_ERROR;
14037 UCollationResult result = collator->compare(u_string1,
14038 string_value1.length(),
14039 u_string2,
14040 string_value2.length(),
14041 status);
14042 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14043
14044 return *isolate->factory()->NewNumberFromInt(result);
14045}
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014046
14047
14048RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) {
14049 HandleScope scope(isolate);
14050
14051 ASSERT(args.length() == 3);
14052
14053 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14054 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14055 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14056
14057 Handle<ObjectTemplateInfo> break_iterator_template =
14058 I18N::GetTemplate2(isolate);
14059
14060 // Create an empty object wrapper.
14061 bool has_pending_exception = false;
14062 Handle<JSObject> local_object = Execution::InstantiateObject(
14063 break_iterator_template, &has_pending_exception);
14064 if (has_pending_exception) {
14065 ASSERT(isolate->has_pending_exception());
14066 return Failure::Exception();
14067 }
14068
14069 // Set break iterator as internal field of the resulting JS object.
14070 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14071 isolate, locale, options, resolved);
14072
14073 if (!break_iterator) return isolate->ThrowIllegalOperation();
14074
14075 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14076 // Make sure that the pointer to adopted text is NULL.
14077 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14078
14079 RETURN_IF_EMPTY_HANDLE(isolate,
14080 JSObject::SetLocalPropertyIgnoreAttributes(
14081 local_object,
14082 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")),
14083 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14084 NONE));
14085
14086 // Make object handle weak so we can delete the break iterator once GC kicks
14087 // in.
14088 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000014089 GlobalHandles::MakeWeak(wrapper.location(),
14090 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014091 BreakIterator::DeleteBreakIterator);
14092 return *local_object;
14093}
14094
14095
14096RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) {
14097 HandleScope scope(isolate);
14098
14099 ASSERT(args.length() == 2);
14100
14101 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14102 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14103
14104 icu::BreakIterator* break_iterator =
14105 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14106 if (!break_iterator) return isolate->ThrowIllegalOperation();
14107
14108 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14109 break_iterator_holder->GetInternalField(1));
14110 delete u_text;
14111
14112 v8::String::Value text_value(v8::Utils::ToLocal(text));
14113 u_text = new icu::UnicodeString(
14114 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14115 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14116
14117 break_iterator->setText(*u_text);
14118
14119 return isolate->heap()->undefined_value();
14120}
14121
14122
14123RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) {
14124 HandleScope scope(isolate);
14125
14126 ASSERT(args.length() == 1);
14127
14128 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14129
14130 icu::BreakIterator* break_iterator =
14131 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14132 if (!break_iterator) return isolate->ThrowIllegalOperation();
14133
14134 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14135}
14136
14137
14138RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) {
14139 HandleScope scope(isolate);
14140
14141 ASSERT(args.length() == 1);
14142
14143 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14144
14145 icu::BreakIterator* break_iterator =
14146 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14147 if (!break_iterator) return isolate->ThrowIllegalOperation();
14148
14149 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14150}
14151
14152
14153RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) {
14154 HandleScope scope(isolate);
14155
14156 ASSERT(args.length() == 1);
14157
14158 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14159
14160 icu::BreakIterator* break_iterator =
14161 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14162 if (!break_iterator) return isolate->ThrowIllegalOperation();
14163
14164 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14165}
14166
14167
14168RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) {
14169 HandleScope scope(isolate);
14170
14171 ASSERT(args.length() == 1);
14172
14173 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14174
14175 icu::BreakIterator* break_iterator =
14176 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14177 if (!break_iterator) return isolate->ThrowIllegalOperation();
14178
14179 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14180 icu::RuleBasedBreakIterator* rule_based_iterator =
14181 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14182 int32_t status = rule_based_iterator->getRuleStatus();
14183 // Keep return values in sync with JavaScript BreakType enum.
14184 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14185 return *isolate->factory()->NewStringFromAscii(CStrVector("none"));
14186 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14187 return *isolate->factory()->NewStringFromAscii(CStrVector("number"));
14188 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14189 return *isolate->factory()->NewStringFromAscii(CStrVector("letter"));
14190 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14191 return *isolate->factory()->NewStringFromAscii(CStrVector("kana"));
14192 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14193 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo"));
14194 } else {
14195 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown"));
14196 }
14197}
danno@chromium.org59400602013-08-13 17:09:37 +000014198#endif // V8_I18N_SUPPORT
14199
14200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014201// Finds the script object from the script data. NOTE: This operation uses
14202// heap traversal to find the function generated for the source position
14203// for the requested break point. For lazily compiled functions several heap
14204// traversals might be required rendering this operation as a rather slow
14205// operation. However for setting break points which is normally done through
14206// some kind of user interaction the performance is not crucial.
14207static Handle<Object> Runtime_GetScriptFromScriptName(
14208 Handle<String> script_name) {
14209 // Scan the heap for Script objects to find the script with the requested
14210 // script data.
14211 Handle<Script> script;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014212 Factory* factory = script_name->GetIsolate()->factory();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014213 Heap* heap = script_name->GetHeap();
14214 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014215 DisallowHeapAllocation no_allocation_during_heap_iteration;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014216 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014217 HeapObject* obj = NULL;
14218 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014219 // If a script is found check if it has the script data requested.
14220 if (obj->IsScript()) {
14221 if (Script::cast(obj)->name()->IsString()) {
14222 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14223 script = Handle<Script>(Script::cast(obj));
14224 }
14225 }
14226 }
14227 }
14228
14229 // If no script with the requested script data is found return undefined.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014230 if (script.is_null()) return factory->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014231
14232 // Return the script found.
14233 return GetScriptWrapper(script);
14234}
14235
14236
14237// Get the script object from script data. NOTE: Regarding performance
14238// see the NOTE for GetScriptFromScriptData.
14239// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014242
14243 ASSERT(args.length() == 1);
14244
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014245 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014246
14247 // Find the requested script.
14248 Handle<Object> result =
14249 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14250 return *result;
14251}
14252
14253
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014254// Collect the raw data for a stack trace. Returns an array of 4
14255// element segments each containing a receiver, function, code and
14256// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014257RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014258 HandleScope scope(isolate);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014259 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014260 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014261 Handle<Object> caller = args.at<Object>(1);
14262 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014263
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014264 // Optionally capture a more detailed stack trace for the message.
14265 isolate->CaptureAndSetDetailedStackTrace(error_object);
14266 // Capture a simple stack trace for the stack property.
14267 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14268}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014269
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014270
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014271// Retrieve the stack trace. This is the raw stack trace that yet has to
14272// be formatted. Since we only need this once, clear it afterwards.
14273RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000014274 HandleScope scope(isolate);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014275 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014276 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14277 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14278 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014279 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14280 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014281 JSObject::DeleteHiddenProperty(error_object, key);
14282 return *result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014283}
14284
14285
ager@chromium.org3811b432009-10-28 14:53:37 +000014286// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014287RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014288 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014289 ASSERT_EQ(args.length(), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000014290
14291 const char* version_string = v8::V8::GetVersion();
14292
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000014293 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014294 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000014295}
14296
14297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014298RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014299 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014300 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014301 OS::PrintError("abort: %s\n",
14302 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000014303 isolate->PrintStack(stderr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014304 OS::Abort();
14305 UNREACHABLE();
14306 return NULL;
14307}
14308
14309
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014310RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) {
14311 HandleScope scope(isolate);
14312 ASSERT(args.length() == 1);
14313 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +000014314 OS::PrintError("abort: %s\n", message->ToCString().get());
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014315 isolate->PrintStack(stderr);
14316 OS::Abort();
14317 UNREACHABLE();
14318 return NULL;
14319}
14320
14321
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014322RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
14323 HandleScope scope(isolate);
14324 ASSERT(args.length() == 1);
14325 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14326 FlattenString(str);
14327 return isolate->heap()->undefined_value();
14328}
14329
14330
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +000014331RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) {
14332 HandleScope scope(isolate);
14333 ASSERT(args.length() == 0);
14334 isolate->heap()->NotifyContextDisposed();
14335 return isolate->heap()->undefined_value();
14336}
14337
14338
danno@chromium.org59400602013-08-13 17:09:37 +000014339RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) {
14340 HandleScope scope(isolate);
14341 ASSERT(args.length() == 1);
14342 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14343 if (!object->IsJSObject()) return Smi::FromInt(0);
14344 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14345 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14346 JSObject::MigrateInstance(js_object);
14347 return *object;
14348}
14349
14350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014351RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014352 SealHandleScope shs(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014353 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014354 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014355 Object* key = args[1];
14356
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014357 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014358 Object* o = cache->get(finger_index);
14359 if (o == key) {
14360 // The fastest case: hit the same place again.
14361 return cache->get(finger_index + 1);
14362 }
14363
14364 for (int i = finger_index - 2;
14365 i >= JSFunctionResultCache::kEntriesIndex;
14366 i -= 2) {
14367 o = cache->get(i);
14368 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014369 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014370 return cache->get(i + 1);
14371 }
14372 }
14373
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014374 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014375 ASSERT(size <= cache->length());
14376
14377 for (int i = size - 2; i > finger_index; i -= 2) {
14378 o = cache->get(i);
14379 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014380 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014381 return cache->get(i + 1);
14382 }
14383 }
14384
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014385 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014386 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014387
14388 Handle<JSFunctionResultCache> cache_handle(cache);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014389 Handle<Object> key_handle(key, isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014390 Handle<Object> value;
14391 {
14392 Handle<JSFunction> factory(JSFunction::cast(
14393 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14394 // TODO(antonm): consider passing a receiver when constructing a cache.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014395 Handle<Object> receiver(isolate->native_context()->global_object(),
14396 isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014397 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014398 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014399 bool pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000014400 value = Execution::Call(isolate,
14401 factory,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014402 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014403 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014404 argv,
14405 &pending_exception);
14406 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014407 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014408
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014409#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014410 if (FLAG_verify_heap) {
14411 cache_handle->JSFunctionResultCacheVerify();
14412 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014413#endif
14414
14415 // Function invocation may have cleared the cache. Reread all the data.
14416 finger_index = cache_handle->finger_index();
14417 size = cache_handle->size();
14418
14419 // If we have spare room, put new data into it, otherwise evict post finger
14420 // entry which is likely to be the least recently used.
14421 int index = -1;
14422 if (size < cache_handle->length()) {
14423 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14424 index = size;
14425 } else {
14426 index = finger_index + JSFunctionResultCache::kEntrySize;
14427 if (index == cache_handle->length()) {
14428 index = JSFunctionResultCache::kEntriesIndex;
14429 }
14430 }
14431
14432 ASSERT(index % 2 == 0);
14433 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14434 ASSERT(index < cache_handle->length());
14435
14436 cache_handle->set(index, *key_handle);
14437 cache_handle->set(index + 1, *value);
14438 cache_handle->set_finger_index(index);
14439
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014440#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014441 if (FLAG_verify_heap) {
14442 cache_handle->JSFunctionResultCacheVerify();
14443 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014444#endif
14445
14446 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014447}
14448
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014450RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014451 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014452 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014453 return Smi::FromInt(message->start_position());
14454}
14455
14456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014457RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014458 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014459 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014460 return message->script();
14461}
14462
14463
kasper.lund44510672008-07-25 07:37:58 +000014464#ifdef DEBUG
14465// ListNatives is ONLY used by the fuzz-natives.js in debug mode
14466// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014467RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014468 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014469 ASSERT(args.length() == 0);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014470#define COUNT_ENTRY(Name, argc, ressize) + 1
14471 int entry_count = 0
14472 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14473 INLINE_FUNCTION_LIST(COUNT_ENTRY)
14474 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
14475#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014476 Factory* factory = isolate->factory();
14477 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014478 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014479 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000014480#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014481 { \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014482 HandleScope inner(isolate); \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014483 Handle<String> name; \
14484 /* Inline runtime functions have an underscore in front of the name. */ \
14485 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014486 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014487 Vector<const char>("_" #Name, StrLength("_" #Name))); \
14488 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014489 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014490 Vector<const char>(#Name, StrLength(#Name))); \
14491 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014492 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014493 pair_elements->set(0, *name); \
14494 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014495 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014496 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014497 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014498 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014499 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014500 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014501 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014502 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014503#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014504 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014505 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014506 return *result;
14507}
kasper.lund44510672008-07-25 07:37:58 +000014508#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014509
14510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014511RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014512 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014513 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014514 CONVERT_ARG_CHECKED(String, format, 0);
14515 CONVERT_ARG_CHECKED(JSArray, elms, 1);
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014516 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014517 String::FlatContent format_content = format->GetFlatContent();
14518 RUNTIME_ASSERT(format_content.IsAscii());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014519 Vector<const uint8_t> chars = format_content.ToOneByteVector();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000014520 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014521 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014522}
14523
14524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014525RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014526 UNREACHABLE(); // implemented as macro in the parser
14527 return NULL;
14528}
14529
14530
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014531#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14532 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014533 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014534 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14535 }
14536
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014537ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
14538ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14539ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014540ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014541ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014542ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014543ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014544ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
14545ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14546ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
14547ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
14548ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
14549ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
14550ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
14551ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
14552ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
14553ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
mmassi@chromium.org7028c052012-06-13 11:51:58 +000014554// Properties test sitting with elements tests - not fooling anyone.
14555ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014556
14557#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14558
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014559
14560RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014561 SealHandleScope shs(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014562 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014563 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14564 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014565 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14566}
14567
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014568
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014569RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) {
14570 SealHandleScope shs(isolate);
14571 ASSERT(args.length() == 1);
14572 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
14573 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded());
14574}
14575
14576
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014577RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014578 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014579 ASSERT(args.length() == 1);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +000014580
14581 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14582 JSReceiver* obj = JSReceiver::cast(args[0]);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014583 if (obj->IsJSGlobalProxy()) {
14584 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014585 if (proto->IsNull()) return isolate->heap()->false_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014586 ASSERT(proto->IsJSGlobalObject());
14587 obj = JSReceiver::cast(proto);
14588 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014589 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14590}
14591
14592
14593RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014594 HandleScope scope(isolate);
danno@chromium.org169691d2013-07-15 08:01:13 +000014595 ASSERT(args.length() == 1);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014596 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014597 if (obj->IsJSGlobalProxy()) {
14598 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014599 if (proto->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014600 ASSERT(proto->IsJSGlobalObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014601 obj = handle(JSReceiver::cast(proto));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014602 }
danno@chromium.org59400602013-08-13 17:09:37 +000014603 if (obj->IsJSProxy())
14604 return isolate->heap()->undefined_value();
14605
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014606 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014607 Handle<JSObject>::cast(obj)->HasFastElements()));
danno@chromium.org169691d2013-07-15 08:01:13 +000014608 ASSERT(obj->IsJSObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014609 JSObject::SetObserved(Handle<JSObject>::cast(obj));
14610 return isolate->heap()->undefined_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014611}
14612
14613
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014614RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014615 SealHandleScope shs(isolate);
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014616 ASSERT(args.length() == 1);
14617 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
14618 bool old_state = isolate->microtask_pending();
14619 isolate->set_microtask_pending(new_state);
14620 return isolate->heap()->ToBoolean(old_state);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014621}
14622
14623
14624RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014625 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014626 ASSERT(args.length() == 0);
14627 return isolate->heap()->observation_state();
14628}
14629
14630
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014631RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014632 HandleScope scope(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014633 ASSERT(args.length() == 0);
14634 // TODO(adamk): Currently this runtime function is only called three times per
14635 // isolate. If it's called more often, the map should be moved into the
14636 // strong root list.
14637 Handle<Map> map =
14638 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
14639 Handle<JSWeakMap> weakmap =
14640 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000014641 return WeakCollectionInitialize(isolate, weakmap);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014642}
14643
14644
14645RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014646 SealHandleScope shs(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014647 ASSERT(args.length() == 1);
14648 Object* object = args[0];
14649 if (object->IsJSGlobalProxy()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000014650 object = object->GetPrototype(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014651 if (object->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014652 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014653 return object;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014654}
14655
14656
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014657RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) {
14658 HandleScope scope(isolate);
14659 ASSERT(args.length() == 3);
14660 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
14661 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
14662 ASSERT(object->IsAccessCheckNeeded());
14663 Handle<Object> key = args.at<Object>(2);
14664 SaveContext save(isolate);
14665 isolate->set_context(observer->context());
14666 if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
14667 v8::ACCESS_KEYS)) {
14668 return isolate->heap()->false_value();
14669 }
14670 bool access_allowed = false;
14671 uint32_t index = 0;
14672 if (key->ToArrayIndex(&index) ||
14673 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) {
14674 access_allowed =
14675 isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) &&
14676 isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS);
14677 } else {
14678 access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) &&
14679 isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS);
14680 }
14681 return isolate->heap()->ToBoolean(access_allowed);
14682}
14683
14684
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014685static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
14686 Handle<JSFunction> constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014687 Handle<AllocationSite> site,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014688 Arguments* caller_args) {
14689 bool holey = false;
14690 bool can_use_type_feedback = true;
14691 if (caller_args->length() == 1) {
14692 Object* argument_one = (*caller_args)[0];
14693 if (argument_one->IsSmi()) {
14694 int value = Smi::cast(argument_one)->value();
14695 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
14696 // the array is a dictionary in this case.
14697 can_use_type_feedback = false;
14698 } else if (value != 0) {
14699 holey = true;
14700 }
14701 } else {
14702 // Non-smi length argument produces a dictionary
14703 can_use_type_feedback = false;
14704 }
14705 }
14706
14707 JSArray* array;
14708 MaybeObject* maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014709 if (!site.is_null() && can_use_type_feedback) {
danno@chromium.orgbee51992013-07-10 14:57:15 +000014710 ElementsKind to_kind = site->GetElementsKind();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014711 if (holey && !IsFastHoleyElementsKind(to_kind)) {
14712 to_kind = GetHoleyElementsKind(to_kind);
14713 // Update the allocation site info to reflect the advice alteration.
danno@chromium.orgbee51992013-07-10 14:57:15 +000014714 site->SetElementsKind(to_kind);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014715 }
14716
14717 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
danno@chromium.orgbee51992013-07-10 14:57:15 +000014718 *constructor, site);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014719 if (!maybe_array->To(&array)) return maybe_array;
14720 } else {
14721 maybe_array = isolate->heap()->AllocateJSObject(*constructor);
14722 if (!maybe_array->To(&array)) return maybe_array;
14723 // We might need to transition to holey
14724 ElementsKind kind = constructor->initial_map()->elements_kind();
14725 if (holey && !IsFastHoleyElementsKind(kind)) {
14726 kind = GetHoleyElementsKind(kind);
14727 maybe_array = array->TransitionElementsKind(kind);
14728 if (maybe_array->IsFailure()) return maybe_array;
14729 }
14730 }
14731
14732 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
14733 DONT_INITIALIZE_ARRAY_ELEMENTS);
14734 if (maybe_array->IsFailure()) return maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014735 ElementsKind old_kind = array->GetElementsKind();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014736 maybe_array = ArrayConstructInitializeElements(array, caller_args);
14737 if (maybe_array->IsFailure()) return maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014738 if (!site.is_null() &&
14739 (old_kind != array->GetElementsKind() ||
14740 !can_use_type_feedback)) {
14741 // The arguments passed in caused a transition. This kind of complexity
14742 // can't be dealt with in the inlined hydrogen array constructor case.
14743 // We must mark the allocationsite as un-inlinable.
14744 site->SetDoNotInlineCall();
14745 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014746 return array;
14747}
14748
14749
14750RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
14751 HandleScope scope(isolate);
14752 // If we get 2 arguments then they are the stub parameters (constructor, type
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014753 // info). If we get 4, then the first one is a pointer to the arguments
14754 // passed by the caller, and the last one is the length of the arguments
14755 // passed to the caller (redundant, but useful to check on the deoptimizer
14756 // with an assert).
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014757 Arguments empty_args(0, NULL);
14758 bool no_caller_args = args.length() == 2;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014759 ASSERT(no_caller_args || args.length() == 4);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014760 int parameters_start = no_caller_args ? 0 : 1;
14761 Arguments* caller_args = no_caller_args
14762 ? &empty_args
14763 : reinterpret_cast<Arguments*>(args[0]);
14764 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14765 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014766#ifdef DEBUG
14767 if (!no_caller_args) {
14768 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
14769 ASSERT(arg_count == caller_args->length());
14770 }
14771#endif
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014772
14773 Handle<AllocationSite> site;
14774 if (!type_info.is_null() &&
14775 *type_info != isolate->heap()->undefined_value() &&
14776 Cell::cast(*type_info)->value()->IsAllocationSite()) {
14777 site = Handle<AllocationSite>(
14778 AllocationSite::cast(Cell::cast(*type_info)->value()), isolate);
14779 ASSERT(!site->SitePointsToLiteral());
14780 }
14781
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014782 return ArrayConstructorCommon(isolate,
14783 constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014784 site,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014785 caller_args);
14786}
14787
14788
14789RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) {
14790 HandleScope scope(isolate);
14791 Arguments empty_args(0, NULL);
14792 bool no_caller_args = args.length() == 1;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014793 ASSERT(no_caller_args || args.length() == 3);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014794 int parameters_start = no_caller_args ? 0 : 1;
14795 Arguments* caller_args = no_caller_args
14796 ? &empty_args
14797 : reinterpret_cast<Arguments*>(args[0]);
14798 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014799#ifdef DEBUG
14800 if (!no_caller_args) {
14801 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
14802 ASSERT(arg_count == caller_args->length());
14803 }
14804#endif
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014805 return ArrayConstructorCommon(isolate,
14806 constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014807 Handle<AllocationSite>::null(),
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014808 caller_args);
14809}
14810
14811
machenbach@chromium.orgea468882013-11-18 08:53:19 +000014812RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) {
14813 return Smi::FromInt(Smi::kMaxValue);
14814}
14815
14816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014817// ----------------------------------------------------------------------------
14818// Implementation of Runtime
14819
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014820#define F(name, number_of_args, result_size) \
14821 { Runtime::k##name, Runtime::RUNTIME, #name, \
14822 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014823
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014824
14825#define I(name, number_of_args, result_size) \
14826 { Runtime::kInline##name, Runtime::INLINE, \
14827 "_" #name, NULL, number_of_args, result_size },
14828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014829static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014830 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014831 INLINE_FUNCTION_LIST(I)
14832 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014833};
14834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014836MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
14837 Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014838 ASSERT(dictionary != NULL);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014839 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014840 for (int i = 0; i < kNumFunctions; ++i) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014841 Object* name_string;
14842 { MaybeObject* maybe_name_string =
14843 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
14844 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014845 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000014846 NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
14847 { MaybeObject* maybe_dictionary = name_dictionary->Add(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014848 String::cast(name_string),
lrn@chromium.org303ada72010-10-27 09:33:13 +000014849 Smi::FromInt(i),
danno@chromium.orgf005df62013-04-30 16:36:45 +000014850 PropertyDetails(NONE, NORMAL, Representation::None()));
lrn@chromium.org303ada72010-10-27 09:33:13 +000014851 if (!maybe_dictionary->ToObject(&dictionary)) {
14852 // Non-recoverable failure. Calling code must restart heap
14853 // initialization.
14854 return maybe_dictionary;
14855 }
14856 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014857 }
14858 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014859}
14860
14861
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014862const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014863 Heap* heap = name->GetHeap();
14864 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014865 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014866 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014867 int function_index = Smi::cast(smi_index)->value();
14868 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014869 }
14870 return NULL;
14871}
14872
14873
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014874const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014875 return &(kIntrinsicFunctions[static_cast<int>(id)]);
14876}
14877
14878
machenbach@chromium.org528ce022013-09-23 14:09:36 +000014879void Runtime::PerformGC(Object* result, Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014880 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014881 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014882 if (isolate->heap()->new_space()->AddFreshPage()) {
14883 return;
14884 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000014885
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014886 // Try to do a garbage collection; ignore it if it fails. The C
14887 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014888 isolate->heap()->CollectGarbage(failure->allocation_space(),
14889 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014890 } else {
14891 // Handle last resort GC and make sure to allow future allocations
14892 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014893 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014894 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
14895 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014897}
14898
14899
14900} } // namespace v8::internal