blob: a175836adb2a8a83eaac8b3e0342ee2b19b4c8eb [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;
5804 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005805 int next_copy_index = 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);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005808 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005809 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005810 proto_with_hidden_properties++;
5811 }
5812 if (i < length - 1) {
5813 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5814 }
5815 }
5816
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005817 // Filter out name of hidden properties object.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005818 if (proto_with_hidden_properties > 0) {
5819 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005821 names->length() - proto_with_hidden_properties);
5822 int dest_pos = 0;
5823 for (int i = 0; i < total_property_count; i++) {
5824 Object* name = old_names->get(i);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005825 if (name == isolate->heap()->hidden_string()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005826 continue;
5827 }
5828 names->set(dest_pos++, name);
5829 }
5830 }
5831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005832 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005833}
5834
5835
5836// Return the names of the local indexed properties.
5837// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005838RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005840 ASSERT(args.length() == 1);
5841 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005843 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005844 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005845
5846 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005848 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005849 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005850}
5851
5852
5853// Return information on whether an object has a named or indexed interceptor.
5854// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005856 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005857 ASSERT(args.length() == 1);
5858 if (!args[0]->IsJSObject()) {
5859 return Smi::FromInt(0);
5860 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005861 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005862
5863 int result = 0;
5864 if (obj->HasNamedInterceptor()) result |= 2;
5865 if (obj->HasIndexedInterceptor()) result |= 1;
5866
5867 return Smi::FromInt(result);
5868}
5869
5870
5871// Return property names from named interceptor.
5872// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005873RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005875 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005876 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005877
5878 if (obj->HasNamedInterceptor()) {
5879 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5880 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5881 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005883}
5884
5885
5886// Return element names from indexed interceptor.
5887// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005888RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005889 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005890 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005891 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005892
5893 if (obj->HasIndexedInterceptor()) {
5894 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5895 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005897 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005898}
5899
5900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005901RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00005902 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005903 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005904 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005905 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005906
5907 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005908 // Do access checks before going to the global object.
5909 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005911 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
danno@chromium.org169691d2013-07-15 08:01:13 +00005913 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005915 }
5916
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005917 Handle<Object> proto(object->GetPrototype(), isolate);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005918 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005920 object = Handle<JSObject>::cast(proto);
5921 }
5922
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005923 bool threw = false;
5924 Handle<FixedArray> contents =
5925 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5926 if (threw) return Failure::Exception();
5927
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005928 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5929 // property array and since the result is mutable we have to create
5930 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005931 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005933 for (int i = 0; i < length; i++) {
5934 Object* entry = contents->get(i);
5935 if (entry->IsString()) {
5936 copy->set(i, entry);
5937 } else {
5938 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005939 HandleScope scope(isolate);
5940 Handle<Object> entry_handle(entry, isolate);
5941 Handle<Object> entry_str =
5942 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005943 copy->set(i, *entry_str);
5944 }
5945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005947}
5948
5949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005950RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005951 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 ASSERT(args.length() == 1);
5953
5954 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005955 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 it.AdvanceToArgumentsFrame();
5957 JavaScriptFrame* frame = it.frame();
5958
5959 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005960 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961
5962 // Try to convert the key to an index. If successful and within
5963 // index return the the argument from the frame.
5964 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005965 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 return frame->GetParameter(index);
5967 }
5968
ulan@chromium.org750145a2013-03-07 15:14:13 +00005969 if (args[0]->IsSymbol()) {
5970 // Lookup in the initial Object.prototype object.
5971 return isolate->initial_object_prototype()->GetProperty(
5972 Symbol::cast(args[0]));
5973 }
5974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977 bool exception = false;
5978 Handle<Object> converted =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00005979 Execution::ToString(isolate, args.at<Object>(0), &exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980 if (exception) return Failure::Exception();
5981 Handle<String> key = Handle<String>::cast(converted);
5982
5983 // Try to convert the string key into an array index.
5984 if (key->AsArrayIndex(&index)) {
5985 if (index < n) {
5986 return frame->GetParameter(index);
5987 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00005988 return isolate->initial_object_prototype()->GetElement(isolate, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 }
5990 }
5991
5992 // Handle special arguments properties.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005993 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
5994 if (key->Equals(isolate->heap()->callee_string())) {
danno@chromium.org169691d2013-07-15 08:01:13 +00005995 JSFunction* function = frame->function();
5996 if (!function->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005997 return isolate->Throw(*isolate->factory()->NewTypeError(
5998 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5999 }
6000 return function;
6001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002
6003 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006004 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005}
6006
6007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006008RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006009 HandleScope scope(isolate);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00006010 ASSERT(args.length() == 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006011 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
6012 if (object->IsJSObject() && !object->IsGlobalObject()) {
6013 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0);
6014 }
6015 return *object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00006016}
6017
6018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006019RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006020 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 ASSERT(args.length() == 1);
6022
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00006023 return isolate->heap()->ToBoolean(args[0]->BooleanValue());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024}
6025
6026
6027// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
6028// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006029RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006030 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031
6032 Object* obj = args[0];
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006033 if (obj->IsNumber()) return isolate->heap()->number_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 HeapObject* heap_obj = HeapObject::cast(obj);
6035
6036 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006037 if (heap_obj->map()->is_undetectable()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006038 return isolate->heap()->undefined_string();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040
6041 InstanceType instance_type = heap_obj->map()->instance_type();
6042 if (instance_type < FIRST_NONSTRING_TYPE) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006043 return isolate->heap()->string_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006044 }
6045
6046 switch (instance_type) {
6047 case ODDBALL_TYPE:
6048 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006049 return isolate->heap()->boolean_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050 }
6051 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006052 return FLAG_harmony_typeof
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006053 ? isolate->heap()->null_string()
6054 : isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055 }
6056 ASSERT(heap_obj->IsUndefined());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006057 return isolate->heap()->undefined_string();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006058 case SYMBOL_TYPE:
6059 return isolate->heap()->symbol_string();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006060 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00006061 case JS_FUNCTION_PROXY_TYPE:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006062 return isolate->heap()->function_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 default:
6064 // For any kind of object not handled above, the spec rule for
6065 // host objects gives that it is okay to return "object"
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006066 return isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 }
6068}
6069
6070
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006071static bool AreDigits(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006072 for (int i = from; i < to; i++) {
6073 if (s[i] < '0' || s[i] > '9') return false;
6074 }
6075
6076 return true;
6077}
6078
6079
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006080static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006081 ASSERT(to - from < 10); // Overflow is not possible.
6082 ASSERT(from < to);
6083 int d = s[from] - '0';
6084
6085 for (int i = from + 1; i < to; i++) {
6086 d = 10 * d + (s[i] - '0');
6087 }
6088
6089 return d;
6090}
6091
6092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006093RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006094 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006095 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006096 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006097 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006098
6099 // Fast case: short integer or some sorts of junk values.
6100 int len = subject->length();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006101 if (subject->IsSeqOneByteString()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00006102 if (len == 0) return Smi::FromInt(0);
6103
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006104 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006105 bool minus = (data[0] == '-');
6106 int start_pos = (minus ? 1 : 0);
6107
6108 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006110 } else if (data[start_pos] > '9') {
6111 // Fast check for a junk value. A valid string may start from a
6112 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
6113 // the 'I' character ('Infinity'). All of that have codes not greater than
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00006114 // '9' except 'I' and &nbsp;.
6115 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006117 }
6118 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
6119 // The maximal/minimal smi has 10 digits. If the string has less digits we
6120 // know it will fit into the smi-data type.
6121 int d = ParseDecimalInteger(data, start_pos, len);
6122 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006123 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00006124 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006125 } else if (!subject->HasHashCode() &&
6126 len <= String::kMaxArrayIndexSize &&
6127 (len == 1 || data[0] != '0')) {
6128 // String hash is not calculated yet but all the data are present.
6129 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006130 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006131#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006132 subject->Hash(); // Force hash calculation.
6133 ASSERT_EQ(static_cast<int>(subject->hash_field()),
6134 static_cast<int>(hash));
6135#endif
6136 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00006137 }
6138 return Smi::FromInt(d);
6139 }
6140 }
6141
6142 // Slower case.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006143 int flags = ALLOW_HEX;
6144 if (FLAG_harmony_numeric_literals) {
6145 // The current spec draft has not updated "ToNumber Applied to the String
6146 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584
6147 flags |= ALLOW_OCTAL | ALLOW_BINARY;
6148 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006149 return isolate->heap()->NumberFromDouble(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006150 StringToDouble(isolate->unicode_cache(), subject, flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006151}
6152
6153
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006154RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006155 SealHandleScope shs(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006156 CONVERT_SMI_ARG_CHECKED(length, 0);
6157 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
6158 if (length == 0) return isolate->heap()->empty_string();
6159 if (is_one_byte) {
6160 return isolate->heap()->AllocateRawOneByteString(length);
6161 } else {
6162 return isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006164}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006166
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006167RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006168 HandleScope scope(isolate);
6169 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00006170 CONVERT_SMI_ARG_CHECKED(new_length, 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006171 return *SeqString::Truncate(string, new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172}
6173
6174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006175RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006176 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006177 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006178 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6179 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006180 ASSERT(string->IsFlat());
6181 Handle<String> result = string->IsOneByteRepresentationUnderneath()
6182 ? URIEscape::Escape<uint8_t>(isolate, source)
6183 : URIEscape::Escape<uc16>(isolate, source);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006184 if (result.is_null()) return Failure::OutOfMemoryException(0x12);
6185 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186}
6187
6188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006189RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006190 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006191 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006192 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
6193 Handle<String> string = FlattenGetString(source);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006194 ASSERT(string->IsFlat());
6195 return string->IsOneByteRepresentationUnderneath()
6196 ? *URIUnescape::Unescape<uint8_t>(isolate, source)
6197 : *URIUnescape::Unescape<uc16>(isolate, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198}
6199
6200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006201RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006202 HandleScope scope(isolate);
6203 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006204 ASSERT(args.length() == 1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006205 return BasicJsonStringifier::StringifyString(isolate, string);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006206}
6207
6208
danno@chromium.org72204d52012-10-31 10:02:10 +00006209RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
danno@chromium.org72204d52012-10-31 10:02:10 +00006210 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006211 ASSERT(args.length() == 1);
danno@chromium.org72204d52012-10-31 10:02:10 +00006212 BasicJsonStringifier stringifier(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006213 return stringifier.Stringify(Handle<Object>(args[0], isolate));
danno@chromium.org72204d52012-10-31 10:02:10 +00006214}
6215
6216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006217RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006218 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006220 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006221 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224
lrn@chromium.org25156de2010-04-06 13:10:27 +00006225 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006226 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006227 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228}
6229
6230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006231RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006232 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006233 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234
6235 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006236 double value = StringToDouble(isolate->unicode_cache(),
6237 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238
6239 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241}
6242
6243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006244template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006246 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006247 String* s,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006248 String::Encoding result_encoding,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 int length,
6250 int input_string_length,
6251 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006252 // We try this twice, once with the assumption that the result is no longer
6253 // than the input and, if that assumption breaks, again with the exact
6254 // length. This may not be pretty, but it is nicer than what was here before
6255 // and I hereby claim my vaffel-is.
6256 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006257 // Allocate the resulting string.
6258 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006259 // NOTE: This assumes that the upper/lower case of an ASCII
6260 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006261 // might break in the future if we implement more context and locale
6262 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006263 Object* o;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006264 { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006265 ? isolate->heap()->AllocateRawOneByteString(length)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267 if (!maybe_o->ToObject(&o)) return maybe_o;
6268 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269 String* result = String::cast(o);
6270 bool has_changed_character = false;
6271
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006272 DisallowHeapAllocation no_gc;
6273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274 // Convert all characters to upper case, assuming that they will fit
6275 // in the buffer
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006276 Access<ConsStringIteratorOp> op(
6277 isolate->runtime_state()->string_iterator());
6278 StringCharacterStream stream(s, op.value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006279 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280 // We can assume that the string is not empty
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006281 uc32 current = stream.GetNext();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006282 // y with umlauts is the only character that stops fitting into one-byte
6283 // when converting to uppercase.
6284 static const uc32 yuml_code = 0xff;
6285 bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006286 for (int i = 0; i < length;) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006287 bool has_next = stream.HasMore();
6288 uc32 next = has_next ? stream.GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289 int char_length = mapping->get(current, next, chars);
6290 if (char_length == 0) {
6291 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006292 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 i++;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006294 } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006295 // Common case: converting the letter resulted in one character.
6296 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006297 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006298 has_changed_character = true;
6299 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006300 } else if (length == input_string_length) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006301 bool found_yuml = (current == yuml_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 // We've assumed that the result would be as long as the
6303 // input but here is a character that converts to several
6304 // characters. No matter, we calculate the exact length
6305 // of the result and try the whole thing again.
6306 //
6307 // Note that this leaves room for optimization. We could just
6308 // memcpy what we already have to the result string. Also,
6309 // the result string is the last object allocated we could
6310 // "realloc" it and probably, in the vast majority of cases,
6311 // extend the existing string to be able to hold the full
6312 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006313 int next_length = 0;
6314 if (has_next) {
6315 next_length = mapping->get(next, 0, chars);
6316 if (next_length == 0) next_length = 1;
6317 }
6318 int current_length = i + char_length + next_length;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006319 while (stream.HasMore()) {
6320 current = stream.GetNext();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006321 found_yuml |= (current == yuml_code);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006322 // NOTE: we use 0 as the next character here because, while
6323 // the next character may affect what a character converts to,
6324 // it does not in any case affect the length of what it convert
6325 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326 int char_length = mapping->get(current, 0, chars);
6327 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006328 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006329 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006331 return Failure::OutOfMemoryException(0x13);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006332 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006334 // Try again with the real length. Return signed if we need
6335 // to allocate a two-byte string for y-umlaut to uppercase.
6336 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length)
6337 : Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006338 } else {
6339 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006340 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 i++;
6342 }
6343 has_changed_character = true;
6344 }
6345 current = next;
6346 }
6347 if (has_changed_character) {
6348 return result;
6349 } else {
6350 // If we didn't actually change anything in doing the conversion
6351 // we simple return the result and let the converted string
6352 // become garbage; there is no reason to keep two identical strings
6353 // alive.
6354 return s;
6355 }
6356}
6357
6358
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006359namespace {
6360
lrn@chromium.org303ada72010-10-27 09:33:13 +00006361static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006362static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006363
6364// Given a word and two range boundaries returns a word with high bit
6365// set in every byte iff the corresponding input byte was strictly in
6366// the range (m, n). All the other bits in the result are cleared.
6367// This function is only useful when it can be inlined and the
6368// boundaries are statically known.
6369// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006370// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006371static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006372 // Use strict inequalities since in edge cases the function could be
6373 // further simplified.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006374 ASSERT(0 < m && m < n);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006375 // Has high bit set in every w byte less than n.
6376 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6377 // Has high bit set in every w byte greater than m.
6378 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6379 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6380}
6381
6382
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006383#ifdef DEBUG
6384static bool CheckFastAsciiConvert(char* dst,
6385 char* src,
6386 int length,
6387 bool changed,
6388 bool is_to_lower) {
6389 bool expected_changed = false;
6390 for (int i = 0; i < length; i++) {
6391 if (dst[i] == src[i]) continue;
6392 expected_changed = true;
6393 if (is_to_lower) {
6394 ASSERT('A' <= src[i] && src[i] <= 'Z');
6395 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6396 } else {
6397 ASSERT('a' <= src[i] && src[i] <= 'z');
6398 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6399 }
6400 }
6401 return (expected_changed == changed);
6402}
6403#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00006404
6405
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006406template<class Converter>
6407static bool FastAsciiConvert(char* dst,
6408 char* src,
6409 int length,
6410 bool* changed_out) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006411#ifdef DEBUG
6412 char* saved_dst = dst;
6413 char* saved_src = src;
6414#endif
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006415 DisallowHeapAllocation no_gc;
6416 // We rely on the distance between upper and lower case letters
6417 // being a known power of 2.
6418 ASSERT('a' - 'A' == (1 << 5));
6419 // Boundaries for the range of input characters than require conversion.
6420 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1;
6421 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1;
6422 bool changed = false;
6423 uintptr_t or_acc = 0;
6424 char* const limit = src + length;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006425#ifdef V8_HOST_CAN_READ_UNALIGNED
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006426 // Process the prefix of the input that requires no conversion one
6427 // (machine) word at a time.
6428 while (src <= limit - sizeof(uintptr_t)) {
6429 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6430 or_acc |= w;
6431 if (AsciiRangeMask(w, lo, hi) != 0) {
6432 changed = true;
6433 break;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006434 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006435 *reinterpret_cast<uintptr_t*>(dst) = w;
6436 src += sizeof(uintptr_t);
6437 dst += sizeof(uintptr_t);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006438 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006439 // Process the remainder of the input performing conversion when
6440 // required one word at a time.
6441 while (src <= limit - sizeof(uintptr_t)) {
6442 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6443 or_acc |= w;
6444 uintptr_t m = AsciiRangeMask(w, lo, hi);
6445 // The mask has high (7th) bit set in every byte that needs
6446 // conversion and we know that the distance between cases is
6447 // 1 << 5.
6448 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6449 src += sizeof(uintptr_t);
6450 dst += sizeof(uintptr_t);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006451 }
6452#endif
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006453 // Process the last few bytes of the input (or the whole input if
6454 // unaligned access is not supported).
6455 while (src < limit) {
6456 char c = *src;
6457 or_acc |= c;
6458 if (lo < c && c < hi) {
6459 c ^= (1 << 5);
6460 changed = true;
6461 }
6462 *dst = c;
6463 ++src;
6464 ++dst;
6465 }
6466 if ((or_acc & kAsciiMask) != 0) {
6467 return false;
6468 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006469
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006470 ASSERT(CheckFastAsciiConvert(
6471 saved_dst, saved_src, length, changed, Converter::kIsToLower));
lrn@chromium.org303ada72010-10-27 09:33:13 +00006472
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006473 *changed_out = changed;
6474 return true;
6475}
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006476
6477} // namespace
6478
6479
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006480template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006481MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006482 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006483 Isolate* isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006484 unibrow::Mapping<Converter, 128>* mapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006485 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006486 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006487 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006488
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006489 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006490 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006491 if (length == 0) return s;
6492
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006493 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006494 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006495 // NOTE: This assumes that the upper/lower case of an ASCII
6496 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006497 // might break in the future if we implement more context and locale
6498 // dependent upper/lower conversions.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006499 if (s->IsSeqOneByteString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006500 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006501 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006502 if (!maybe_o->ToObject(&o)) return maybe_o;
6503 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006504 SeqOneByteString* result = SeqOneByteString::cast(o);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006505 bool has_changed_character;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006506 bool is_ascii = FastAsciiConvert<Converter>(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006507 reinterpret_cast<char*>(result->GetChars()),
6508 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
6509 length,
6510 &has_changed_character);
6511 // If not ASCII, we discard the result and take the 2 byte path.
6512 if (is_ascii) {
6513 return has_changed_character ? result : s;
6514 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006515 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006516
machenbach@chromium.org12014a42013-11-11 16:29:16 +00006517 String::Encoding result_encoding = s->IsOneByteRepresentation()
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006518 ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006519 Object* answer;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006520 { MaybeObject* maybe_answer = ConvertCaseHelper(
6521 isolate, s, result_encoding, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006522 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6523 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006524 if (answer->IsSmi()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006525 int new_length = Smi::cast(answer)->value();
6526 if (new_length < 0) {
6527 result_encoding = String::TWO_BYTE_ENCODING;
6528 new_length = -new_length;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006529 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006530 MaybeObject* maybe_answer = ConvertCaseHelper(
6531 isolate, s, result_encoding, new_length, length, mapping);
6532 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006533 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006534 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006535}
6536
6537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006538RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006539 return ConvertCase(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006540 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541}
6542
6543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006545 return ConvertCase(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006546 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547}
6548
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006549
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006550static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006551 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006552}
6553
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006555RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006556 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006557 ASSERT(args.length() == 3);
6558
yangguo@chromium.org49546742013-12-23 16:17:49 +00006559 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006560 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6561 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006562
yangguo@chromium.org49546742013-12-23 16:17:49 +00006563 string = FlattenGetString(string);
6564 int length = string->length();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006565
6566 int left = 0;
6567 if (trimLeft) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006568 while (left < length && IsTrimWhiteSpace(string->Get(left))) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006569 left++;
6570 }
6571 }
6572
6573 int right = length;
6574 if (trimRight) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006575 while (right > left && IsTrimWhiteSpace(string->Get(right - 1))) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006576 right--;
6577 }
6578 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00006579
6580 return *isolate->factory()->NewSubString(string, left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006581}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006584RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006586 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006587 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6588 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006589 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6590
6591 int subject_length = subject->length();
6592 int pattern_length = pattern->length();
6593 RUNTIME_ASSERT(pattern_length > 0);
6594
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006595 if (limit == 0xffffffffu) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006596 Handle<Object> cached_answer(
6597 RegExpResultsCache::Lookup(isolate->heap(),
6598 *subject,
6599 *pattern,
6600 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
6601 isolate);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006602 if (*cached_answer != Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006603 // The cache FixedArray is a COW-array and can therefore be reused.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006604 Handle<JSArray> result =
6605 isolate->factory()->NewJSArrayWithElements(
6606 Handle<FixedArray>::cast(cached_answer));
6607 return *result;
6608 }
6609 }
6610
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006611 // The limit can be very large (0xffffffffu), but since the pattern
6612 // isn't empty, we can never create more parts than ~half the length
6613 // of the subject.
6614
6615 if (!subject->IsFlat()) FlattenString(subject);
6616
6617 static const int kMaxInitialListCapacity = 16;
6618
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006619 ZoneScope zone_scope(isolate->runtime_zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006620
6621 // Find (up to limit) indices of separator and end-of-string in subject
6622 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006623 ZoneList<int> indices(initial_capacity, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006624 if (!pattern->IsFlat()) FlattenString(pattern);
6625
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006626 FindStringIndicesDispatch(isolate, *subject, *pattern,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006627 &indices, limit, zone_scope.zone());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006628
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006629 if (static_cast<uint32_t>(indices.length()) < limit) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006630 indices.Add(subject_length, zone_scope.zone());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006631 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006632
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006633 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006634
6635 // Create JSArray of substrings separated by separator.
6636 int part_count = indices.length();
6637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006638 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006639 JSObject::EnsureCanContainHeapObjectElements(result);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006640 result->set_length(Smi::FromInt(part_count));
6641
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006642 ASSERT(result->HasFastObjectElements());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006643
6644 if (part_count == 1 && indices.at(0) == subject_length) {
6645 FixedArray::cast(result->elements())->set(0, *subject);
6646 return *result;
6647 }
6648
6649 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6650 int part_start = 0;
6651 for (int i = 0; i < part_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00006652 HandleScope local_loop_handle(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006653 int part_end = indices.at(i);
6654 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006655 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006656 elements->set(i, *substring);
6657 part_start = part_end + pattern_length;
6658 }
6659
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006660 if (limit == 0xffffffffu) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006661 if (result->HasFastObjectElements()) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00006662 RegExpResultsCache::Enter(isolate->heap(),
6663 *subject,
6664 *pattern,
6665 *elements,
6666 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006667 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006668 }
6669
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006670 return *result;
6671}
6672
6673
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006674// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006675// one-char strings in the cache. Gives up on the first char that is
6676// not in the cache and fills the remainder with smi zeros. Returns
6677// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678static int CopyCachedAsciiCharsToArray(Heap* heap,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006679 const uint8_t* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006680 FixedArray* elements,
6681 int length) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006682 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006683 FixedArray* ascii_cache = heap->single_character_string_cache();
6684 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006685 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006686 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006687 for (i = 0; i < length; ++i) {
6688 Object* value = ascii_cache->get(chars[i]);
6689 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006690 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006691 }
6692 if (i < length) {
6693 ASSERT(Smi::FromInt(0) == 0);
6694 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6695 }
6696#ifdef DEBUG
6697 for (int j = 0; j < length; ++j) {
6698 Object* element = elements->get(j);
6699 ASSERT(element == Smi::FromInt(0) ||
6700 (element->IsString() && String::cast(element)->LooksValid()));
6701 }
6702#endif
6703 return i;
6704}
6705
6706
6707// Converts a String to JSArray.
6708// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006709RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006711 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006712 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006713 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006714
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006715 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006716 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006717
6718 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006719 int position = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006720 if (s->IsFlat() && s->IsOneByteRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006721 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006722 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006723 { MaybeObject* maybe_obj =
6724 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006725 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6726 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006728 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006729 String::FlatContent content = s->GetFlatContent();
6730 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006731 Vector<const uint8_t> chars = content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006732 // Note, this will initialize all elements (not only the prefix)
6733 // to prevent GC from seeing partially initialized array.
6734 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6735 chars.start(),
6736 *elements,
6737 length);
6738 } else {
6739 MemsetPointer(elements->data_start(),
6740 isolate->heap()->undefined_value(),
6741 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006742 }
6743 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006745 }
6746 for (int i = position; i < length; ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006747 Handle<Object> str =
6748 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006749 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006750 }
6751
6752#ifdef DEBUG
6753 for (int i = 0; i < length; ++i) {
6754 ASSERT(String::cast(elements->get(i))->length() == 1);
6755 }
6756#endif
6757
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006758 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006759}
6760
6761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006762RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006763 SealHandleScope shs(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006764 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006765 CONVERT_ARG_CHECKED(String, value, 0);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006766 return value->ToObject(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006767}
6768
6769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006770bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006771 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006772 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006773 return char_length == 0;
6774}
6775
6776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006778 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 ASSERT(args.length() == 1);
6780
6781 Object* number = args[0];
6782 RUNTIME_ASSERT(number->IsNumber());
6783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006785}
6786
6787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006788RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006789 SealHandleScope shs(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00006790 ASSERT(args.length() == 1);
6791
6792 Object* number = args[0];
6793 RUNTIME_ASSERT(number->IsNumber());
6794
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006795 return isolate->heap()->NumberToString(
6796 number, false, isolate->heap()->GetPretenureMode());
ager@chromium.org357bf652010-04-12 11:30:10 +00006797}
6798
6799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006800RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
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
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006804 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006805
6806 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6807 if (number > 0 && number <= Smi::kMaxValue) {
6808 return Smi::FromInt(static_cast<int>(number));
6809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811}
6812
6813
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006814// ES6 draft 9.1.11
6815RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006816 SealHandleScope shs(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006817 ASSERT(args.length() == 1);
6818
6819 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6820
6821 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6822 if (number > 0 && number <= Smi::kMaxValue) {
6823 return Smi::FromInt(static_cast<int>(number));
6824 }
6825 if (number <= 0) {
6826 return Smi::FromInt(0);
6827 }
6828 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6829}
6830
6831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006832RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006833 SealHandleScope shs(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006834 ASSERT(args.length() == 1);
6835
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006836 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006837
6838 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6839 if (number > 0 && number <= Smi::kMaxValue) {
6840 return Smi::FromInt(static_cast<int>(number));
6841 }
6842
6843 double double_value = DoubleToInteger(number);
6844 // Map both -0 and +0 to +0.
6845 if (double_value == 0) double_value = 0;
6846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006847 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006848}
6849
6850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006851RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006852 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853 ASSERT(args.length() == 1);
6854
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006855 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006856 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857}
6858
6859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006860RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006861 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006862 ASSERT(args.length() == 1);
6863
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006864 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006865
6866 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6867 if (number > 0 && number <= Smi::kMaxValue) {
6868 return Smi::FromInt(static_cast<int>(number));
6869 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006870 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006871}
6872
6873
ager@chromium.org870a0b62008-11-04 11:43:05 +00006874// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6875// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006876RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006877 SealHandleScope shs(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006878 ASSERT(args.length() == 1);
6879
6880 Object* obj = args[0];
6881 if (obj->IsSmi()) {
6882 return obj;
6883 }
6884 if (obj->IsHeapNumber()) {
6885 double value = HeapNumber::cast(obj)->value();
6886 int int_value = FastD2I(value);
6887 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6888 return Smi::FromInt(int_value);
6889 }
6890 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006892}
6893
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006895RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006896 SealHandleScope shs(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006897 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006898 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006899}
6900
6901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006902RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006903 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904 ASSERT(args.length() == 2);
6905
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006906 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6907 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006908 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909}
6910
6911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006912RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006913 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914 ASSERT(args.length() == 2);
6915
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006916 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6917 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006918 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919}
6920
6921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006923 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924 ASSERT(args.length() == 2);
6925
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006926 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6927 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006928 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929}
6930
6931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006932RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006933 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006934 ASSERT(args.length() == 1);
6935
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006936 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006937 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938}
6939
6940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006941RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006942 SealHandleScope shs(isolate);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006943 ASSERT(args.length() == 0);
6944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006945 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006946}
6947
6948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006949RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006950 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951 ASSERT(args.length() == 2);
6952
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006953 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6954 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956}
6957
6958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006959RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006960 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961 ASSERT(args.length() == 2);
6962
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006963 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6964 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006965
ager@chromium.org3811b432009-10-28 14:53:37 +00006966 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006967 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006968 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006969}
6970
6971
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006972RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00006973 SealHandleScope shs(isolate);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00006974 ASSERT(args.length() == 2);
6975
6976 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6977 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
6978 return isolate->heap()->NumberFromInt32(x * y);
6979}
6980
6981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006982RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00006983 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984 ASSERT(args.length() == 2);
yangguo@chromium.org49546742013-12-23 16:17:49 +00006985 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
6986 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006987 isolate->counters()->string_add_runtime()->Increment();
yangguo@chromium.org49546742013-12-23 16:17:49 +00006988 return *isolate->factory()->NewConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989}
6990
6991
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006992template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006993static inline void StringBuilderConcatHelper(String* special,
6994 sinkchar* sink,
6995 FixedArray* fixed_array,
6996 int array_length) {
6997 int position = 0;
6998 for (int i = 0; i < array_length; i++) {
6999 Object* element = fixed_array->get(i);
7000 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007001 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007002 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007003 int pos;
7004 int len;
7005 if (encoded_slice > 0) {
7006 // Position and length encoded in one smi.
7007 pos = StringBuilderSubstringPosition::decode(encoded_slice);
7008 len = StringBuilderSubstringLength::decode(encoded_slice);
7009 } else {
7010 // Position and length encoded in two smis.
7011 Object* obj = fixed_array->get(++i);
7012 ASSERT(obj->IsSmi());
7013 pos = Smi::cast(obj)->value();
7014 len = -encoded_slice;
7015 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00007016 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00007017 sink + position,
7018 pos,
7019 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007020 position += len;
7021 } else {
7022 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007023 int element_length = string->length();
7024 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007025 position += element_length;
7026 }
7027 }
7028}
7029
7030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007032 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007033 ASSERT(args.length() == 3);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007034 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007035 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007036 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007037 return Failure::OutOfMemoryException(0x14);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007038 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007039 int array_length = args.smi_at(1);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007040 CONVERT_ARG_HANDLE_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007041
7042 // This assumption is used by the slice encoding in one or two smis.
7043 ASSERT(Smi::kMaxValue >= String::kMaxLength);
7044
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007045 JSObject::EnsureCanContainHeapObjectElements(array);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007046
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007047 int special_length = special->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007048 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007049 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 }
7051 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007052 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055
7056 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 } else if (array_length == 1) {
7059 Object* first = fixed_array->get(0);
7060 if (first->IsString()) return first;
7061 }
7062
danno@chromium.orgf005df62013-04-30 16:36:45 +00007063 bool one_byte = special->HasOnlyOneByteChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 int position = 0;
7065 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007066 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067 Object* elt = fixed_array->get(i);
7068 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007069 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007070 int smi_value = Smi::cast(elt)->value();
7071 int pos;
7072 int len;
7073 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007074 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007075 pos = StringBuilderSubstringPosition::decode(smi_value);
7076 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007077 } else {
7078 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007079 len = -smi_value;
7080 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007081 i++;
7082 if (i >= array_length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007083 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007084 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007085 Object* next_smi = fixed_array->get(i);
7086 if (!next_smi->IsSmi()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007087 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007088 }
7089 pos = Smi::cast(next_smi)->value();
7090 if (pos < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007091 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007094 ASSERT(pos >= 0);
7095 ASSERT(len >= 0);
7096 if (pos > special_length || len > special_length - pos) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007097 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00007098 }
7099 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 } else if (elt->IsString()) {
7101 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007102 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007103 increment = element_length;
danno@chromium.orgf005df62013-04-30 16:36:45 +00007104 if (one_byte && !element->HasOnlyOneByteChars()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007105 one_byte = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007106 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007108 ASSERT(!elt->IsTheHole());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007109 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007111 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007112 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007113 return Failure::OutOfMemoryException(0x15);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00007114 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007115 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 }
7117
7118 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007120
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007121 if (one_byte) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007122 { MaybeObject* maybe_object =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007123 isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007124 if (!maybe_object->ToObject(&object)) return maybe_object;
7125 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007126 SeqOneByteString* answer = SeqOneByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007127 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007128 answer->GetChars(),
7129 fixed_array,
7130 array_length);
7131 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007132 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007133 { MaybeObject* maybe_object =
7134 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007135 if (!maybe_object->ToObject(&object)) return maybe_object;
7136 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007137 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00007138 StringBuilderConcatHelper(*special,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007139 answer->GetChars(),
7140 fixed_array,
7141 array_length);
7142 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007144}
7145
7146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007147RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007148 SealHandleScope shs(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007149 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007150 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007151 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007152 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007153 return Failure::OutOfMemoryException(0x16);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007154 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007155 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007156 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007157
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007158 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007159 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007160 }
7161 FixedArray* fixed_array = FixedArray::cast(array->elements());
7162 if (fixed_array->length() < array_length) {
7163 array_length = fixed_array->length();
7164 }
7165
7166 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007167 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007168 } else if (array_length == 1) {
7169 Object* first = fixed_array->get(0);
7170 if (first->IsString()) return first;
7171 }
7172
7173 int separator_length = separator->length();
7174 int max_nof_separators =
7175 (String::kMaxLength + separator_length - 1) / separator_length;
7176 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007177 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007178 return Failure::OutOfMemoryException(0x17);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007179 }
7180 int length = (array_length - 1) * separator_length;
7181 for (int i = 0; i < array_length; i++) {
7182 Object* element_obj = fixed_array->get(i);
7183 if (!element_obj->IsString()) {
7184 // TODO(1161): handle this case.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007185 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007186 }
7187 String* element = String::cast(element_obj);
7188 int increment = element->length();
7189 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007191 return Failure::OutOfMemoryException(0x18);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007192 }
7193 length += increment;
7194 }
7195
7196 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007197 { MaybeObject* maybe_object =
7198 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007199 if (!maybe_object->ToObject(&object)) return maybe_object;
7200 }
7201 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
7202
7203 uc16* sink = answer->GetChars();
7204#ifdef DEBUG
7205 uc16* end = sink + length;
7206#endif
7207
7208 String* first = String::cast(fixed_array->get(0));
7209 int first_length = first->length();
7210 String::WriteToFlat(first, sink, 0, first_length);
7211 sink += first_length;
7212
7213 for (int i = 1; i < array_length; i++) {
7214 ASSERT(sink + separator_length <= end);
7215 String::WriteToFlat(separator, sink, 0, separator_length);
7216 sink += separator_length;
7217
7218 String* element = String::cast(fixed_array->get(i));
7219 int element_length = element->length();
7220 ASSERT(sink + element_length <= end);
7221 String::WriteToFlat(element, sink, 0, element_length);
7222 sink += element_length;
7223 }
7224 ASSERT(sink == end);
7225
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007226 // Use %_FastAsciiArrayJoin instead.
7227 ASSERT(!answer->IsOneByteRepresentation());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007228 return answer;
7229}
7230
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007231template <typename Char>
7232static void JoinSparseArrayWithSeparator(FixedArray* elements,
7233 int elements_length,
7234 uint32_t array_length,
7235 String* separator,
7236 Vector<Char> buffer) {
7237 int previous_separator_position = 0;
7238 int separator_length = separator->length();
7239 int cursor = 0;
7240 for (int i = 0; i < elements_length; i += 2) {
7241 int position = NumberToInt32(elements->get(i));
7242 String* string = String::cast(elements->get(i + 1));
7243 int string_length = string->length();
7244 if (string->length() > 0) {
7245 while (previous_separator_position < position) {
7246 String::WriteToFlat<Char>(separator, &buffer[cursor],
7247 0, separator_length);
7248 cursor += separator_length;
7249 previous_separator_position++;
7250 }
7251 String::WriteToFlat<Char>(string, &buffer[cursor],
7252 0, string_length);
7253 cursor += string->length();
7254 }
7255 }
7256 if (separator_length > 0) {
7257 // Array length must be representable as a signed 32-bit number,
7258 // otherwise the total string length would have been too large.
7259 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
7260 int last_array_index = static_cast<int>(array_length - 1);
7261 while (previous_separator_position < last_array_index) {
7262 String::WriteToFlat<Char>(separator, &buffer[cursor],
7263 0, separator_length);
7264 cursor += separator_length;
7265 previous_separator_position++;
7266 }
7267 }
7268 ASSERT(cursor <= buffer.length());
7269}
7270
7271
7272RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007273 SealHandleScope shs(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007274 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007275 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007276 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007277 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007278 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007279 // elements_array is fast-mode JSarray of alternating positions
7280 // (increasing order) and strings.
7281 // array_length is length of original array (used to add separators);
7282 // separator is string to put between elements. Assumed to be non-empty.
7283
7284 // Find total length of join result.
7285 int string_length = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007286 bool is_ascii = separator->IsOneByteRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007287 int max_string_length;
7288 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007289 max_string_length = SeqOneByteString::kMaxLength;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007290 } else {
7291 max_string_length = SeqTwoByteString::kMaxLength;
7292 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007293 bool overflow = false;
7294 CONVERT_NUMBER_CHECKED(int, elements_length,
7295 Int32, elements_array->length());
7296 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7297 FixedArray* elements = FixedArray::cast(elements_array->elements());
7298 for (int i = 0; i < elements_length; i += 2) {
7299 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007300 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7301 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007302 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007303 if (is_ascii && !string->IsOneByteRepresentation()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007304 is_ascii = false;
7305 max_string_length = SeqTwoByteString::kMaxLength;
7306 }
7307 if (length > max_string_length ||
7308 max_string_length - length < string_length) {
7309 overflow = true;
7310 break;
7311 }
7312 string_length += length;
7313 }
7314 int separator_length = separator->length();
7315 if (!overflow && separator_length > 0) {
7316 if (array_length <= 0x7fffffffu) {
7317 int separator_count = static_cast<int>(array_length) - 1;
7318 int remaining_length = max_string_length - string_length;
7319 if ((remaining_length / separator_length) >= separator_count) {
7320 string_length += separator_length * (array_length - 1);
7321 } else {
7322 // Not room for the separators within the maximal string length.
7323 overflow = true;
7324 }
7325 } else {
7326 // Nonempty separator and at least 2^31-1 separators necessary
7327 // means that the string is too large to create.
7328 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7329 overflow = true;
7330 }
7331 }
7332 if (overflow) {
7333 // Throw OutOfMemory exception for creating too large a string.
7334 V8::FatalProcessOutOfMemory("Array join result too large.");
7335 }
7336
7337 if (is_ascii) {
7338 MaybeObject* result_allocation =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007339 isolate->heap()->AllocateRawOneByteString(string_length);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007340 if (result_allocation->IsFailure()) return result_allocation;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007341 SeqOneByteString* result_string =
7342 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007343 JoinSparseArrayWithSeparator<uint8_t>(elements,
7344 elements_length,
7345 array_length,
7346 separator,
7347 Vector<uint8_t>(
7348 result_string->GetChars(),
7349 string_length));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007350 return result_string;
7351 } else {
7352 MaybeObject* result_allocation =
7353 isolate->heap()->AllocateRawTwoByteString(string_length);
7354 if (result_allocation->IsFailure()) return result_allocation;
7355 SeqTwoByteString* result_string =
7356 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7357 JoinSparseArrayWithSeparator<uc16>(elements,
7358 elements_length,
7359 array_length,
7360 separator,
7361 Vector<uc16>(result_string->GetChars(),
7362 string_length));
7363 return result_string;
7364 }
7365}
7366
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007369 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370 ASSERT(args.length() == 2);
7371
7372 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7373 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375}
7376
7377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007378RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007379 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380 ASSERT(args.length() == 2);
7381
7382 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7383 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007388RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007389 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390 ASSERT(args.length() == 2);
7391
7392 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7393 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007399 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 ASSERT(args.length() == 2);
7401
7402 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7403 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007409 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410 ASSERT(args.length() == 2);
7411
7412 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7413 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007414 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415}
7416
7417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007418RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007419 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 ASSERT(args.length() == 2);
7421
7422 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7423 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425}
7426
7427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007428RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007429 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430 ASSERT(args.length() == 2);
7431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007432 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7433 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007434 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL);
7435 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007436 if (x == y) return Smi::FromInt(EQUAL);
7437 Object* result;
7438 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7439 result = Smi::FromInt(EQUAL);
7440 } else {
7441 result = Smi::FromInt(NOT_EQUAL);
7442 }
7443 return result;
7444}
7445
7446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007447RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007448 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 ASSERT(args.length() == 2);
7450
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007451 CONVERT_ARG_CHECKED(String, x, 0);
7452 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007454 bool not_equal = !x->Equals(y);
7455 // This is slightly convoluted because the value that signifies
7456 // equality is 0 and inequality is 1 so we have to negate the result
7457 // from String::Equals.
7458 ASSERT(not_equal == 0 || not_equal == 1);
7459 STATIC_CHECK(EQUAL == 0);
7460 STATIC_CHECK(NOT_EQUAL == 1);
7461 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007462}
7463
7464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007465RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007466 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 ASSERT(args.length() == 3);
7468
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007469 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7470 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007471 if (std::isnan(x) || std::isnan(y)) return args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472 if (x == y) return Smi::FromInt(EQUAL);
7473 if (isless(x, y)) return Smi::FromInt(LESS);
7474 return Smi::FromInt(GREATER);
7475}
7476
7477
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007478// Compare two Smis as if they were converted to strings and then
7479// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007480RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007481 SealHandleScope shs(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007482 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007483 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7484 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007485
7486 // If the integers are equal so are the string representations.
7487 if (x_value == y_value) return Smi::FromInt(EQUAL);
7488
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007489 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007490 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007491 if (x_value == 0 || y_value == 0)
7492 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007493
ager@chromium.org32912102009-01-16 10:38:43 +00007494 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007495 // smallest because the char code of '-' is less than the char code
7496 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007497
7498 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7499 // architectures using 32-bit Smis.
7500 uint32_t x_scaled = x_value;
7501 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007502 if (x_value < 0 || y_value < 0) {
7503 if (y_value >= 0) return Smi::FromInt(LESS);
7504 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007505 x_scaled = -x_value;
7506 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007507 }
7508
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007509 static const uint32_t kPowersOf10[] = {
7510 1, 10, 100, 1000, 10*1000, 100*1000,
7511 1000*1000, 10*1000*1000, 100*1000*1000,
7512 1000*1000*1000
7513 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007515 // If the integers have the same number of decimal digits they can be
7516 // compared directly as the numeric order is the same as the
7517 // lexicographic order. If one integer has fewer digits, it is scaled
7518 // by some power of 10 to have the same number of digits as the longer
7519 // integer. If the scaled integers are equal it means the shorter
7520 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007522 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7523 int x_log2 = IntegerLog2(x_scaled);
7524 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7525 x_log10 -= x_scaled < kPowersOf10[x_log10];
7526
7527 int y_log2 = IntegerLog2(y_scaled);
7528 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7529 y_log10 -= y_scaled < kPowersOf10[y_log10];
7530
7531 int tie = EQUAL;
7532
7533 if (x_log10 < y_log10) {
7534 // X has fewer digits. We would like to simply scale up X but that
7535 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7536 // be scaled up to 9_000_000_000. So we scale up by the next
7537 // smallest power and scale down Y to drop one digit. It is OK to
7538 // drop one digit from the longer integer since the final digit is
7539 // past the length of the shorter integer.
7540 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7541 y_scaled /= 10;
7542 tie = LESS;
7543 } else if (y_log10 < x_log10) {
7544 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7545 x_scaled /= 10;
7546 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007547 }
7548
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007549 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7550 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7551 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007552}
7553
7554
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007555static Object* StringCharacterStreamCompare(RuntimeState* state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 String* x,
7557 String* y) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007558 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
7559 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
7560 while (stream_x.HasMore() && stream_y.HasMore()) {
7561 int d = stream_x.GetNext() - stream_y.GetNext();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007562 if (d < 0) return Smi::FromInt(LESS);
7563 else if (d > 0) return Smi::FromInt(GREATER);
7564 }
7565
7566 // x is (non-trivial) prefix of y:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007567 if (stream_y.HasMore()) return Smi::FromInt(LESS);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007568 // y is prefix of x:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007569 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007570}
7571
7572
7573static Object* FlatStringCompare(String* x, String* y) {
7574 ASSERT(x->IsFlat());
7575 ASSERT(y->IsFlat());
7576 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7577 int prefix_length = x->length();
7578 if (y->length() < prefix_length) {
7579 prefix_length = y->length();
7580 equal_prefix_result = Smi::FromInt(GREATER);
7581 } else if (y->length() > prefix_length) {
7582 equal_prefix_result = Smi::FromInt(LESS);
7583 }
7584 int r;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007585 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007586 String::FlatContent x_content = x->GetFlatContent();
7587 String::FlatContent y_content = y->GetFlatContent();
7588 if (x_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007589 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007590 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007591 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007592 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007593 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007594 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007595 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7596 }
7597 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007598 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7599 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007600 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007601 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7602 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007603 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007604 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7605 }
7606 }
7607 Object* result;
7608 if (r == 0) {
7609 result = equal_prefix_result;
7610 } else {
7611 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007613 ASSERT(result ==
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007614 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007615 return result;
7616}
7617
7618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007619RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007620 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007621 ASSERT(args.length() == 2);
7622
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007623 CONVERT_ARG_CHECKED(String, x, 0);
7624 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007626 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007628 // A few fast case tests before we flatten.
7629 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007630 if (y->length() == 0) {
7631 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007632 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007633 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007634 return Smi::FromInt(LESS);
7635 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007636
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007637 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007638 if (d < 0) return Smi::FromInt(LESS);
7639 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007640
lrn@chromium.org303ada72010-10-27 09:33:13 +00007641 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007642 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007643 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7644 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007645 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007646 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007649 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007650 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007651}
7652
7653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007654RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007655 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007656 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007657 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007659 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007660 return isolate->heap()->AllocateHeapNumber(acos(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007661}
7662
7663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007664RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007665 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007666 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007669 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007670 return isolate->heap()->AllocateHeapNumber(asin(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007671}
7672
7673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007674RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007675 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007676 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007679 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00007680 return isolate->heap()->AllocateHeapNumber(atan(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007681}
7682
7683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007684static const double kPiDividedBy4 = 0.78539816339744830962;
7685
7686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007687RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007688 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007689 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007690 isolate->counters()->math_atan2()->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);
7693 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694 double result;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007695 if (std::isinf(x) && std::isinf(y)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007696 // Make sure that the result in case of two infinite arguments
7697 // is a multiple of Pi / 4. The sign of the result is determined
7698 // by the first argument (x) and the sign of the second argument
7699 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007700 int multiplier = (x < 0) ? -1 : 1;
7701 if (y < 0) multiplier *= 3;
7702 result = multiplier * kPiDividedBy4;
7703 } else {
7704 result = atan2(x, y);
7705 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007706 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007707}
7708
7709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007710RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007711 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007712 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007713 isolate->counters()->math_exp()->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);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00007716 lazily_initialize_fast_exp();
7717 return isolate->heap()->NumberFromDouble(fast_exp(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718}
7719
7720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007721RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007722 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007724 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007725
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007726 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007727 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728}
7729
7730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007731RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007732 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007733 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007734 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007736 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00007737 return isolate->heap()->AllocateHeapNumber(log(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738}
7739
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00007740
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007741// Slow version of Math.pow. We check for fast paths for special cases.
7742// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007743RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007744 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007746 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007747
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007748 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007749
7750 // If the second argument is a smi, it is much faster to call the
7751 // custom powi() function than the generic pow().
7752 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007753 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007755 }
7756
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007757 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00007758 double result = power_helper(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007759 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007760 return isolate->heap()->AllocateHeapNumber(result);
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// 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 +00007765// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007766RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007767 SealHandleScope shs(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007768 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007769 isolate->counters()->math_pow()->Increment();
7770
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007771 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7772 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007773 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007774 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007775 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007776 double result = power_double_double(x, y);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007777 if (std::isnan(result)) return isolate->heap()->nan_value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007778 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007779 }
7780}
7781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007783RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007784 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007785 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007786 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007787
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007788 if (!args[0]->IsHeapNumber()) {
7789 // Must be smi. Return the argument unchanged for all the other types
7790 // to make fuzz-natives test happy.
7791 return args[0];
7792 }
7793
7794 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7795
7796 double value = number->value();
7797 int exponent = number->get_exponent();
7798 int sign = number->get_sign();
7799
danno@chromium.org160a7b02011-04-18 15:51:38 +00007800 if (exponent < -1) {
7801 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7802 if (sign) return isolate->heap()->minus_zero_value();
7803 return Smi::FromInt(0);
7804 }
7805
7806 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7807 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007808 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007809 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007810 return Smi::FromInt(static_cast<int>(value + 0.5));
7811 }
7812
7813 // If the magnitude is big enough, there's no place for fraction part. If we
7814 // try to add 0.5 to this number, 1.0 will be added instead.
7815 if (exponent >= 52) {
7816 return number;
7817 }
7818
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007819 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007820
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007821 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007822 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007823}
7824
7825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007826RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007827 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007828 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007830
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007831 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007832 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007833}
7834
7835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007836RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007837 SealHandleScope shs(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007838 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007839
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007840 CONVERT_SMI_ARG_CHECKED(year, 0);
7841 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007842
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007843 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007844}
7845
7846
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007847RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7848 HandleScope scope(isolate);
7849 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007850
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007851 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7852 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7853 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007854
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007855 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007856
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007857 Object* value = NULL;
7858 bool is_value_nan = false;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00007859 if (std::isnan(time)) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007860 value = isolate->heap()->nan_value();
7861 is_value_nan = true;
7862 } else if (!is_utc &&
7863 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7864 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7865 value = isolate->heap()->nan_value();
7866 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007867 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007868 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7869 if (time < -DateCache::kMaxTimeInMs ||
7870 time > DateCache::kMaxTimeInMs) {
7871 value = isolate->heap()->nan_value();
7872 is_value_nan = true;
7873 } else {
7874 MaybeObject* maybe_result =
7875 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7876 if (!maybe_result->ToObject(&value)) return maybe_result;
7877 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007878 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007879 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007880 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007881}
7882
7883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007884RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007885 HandleScope scope(isolate);
7886 ASSERT(args.length() == 3);
7887
7888 Handle<JSFunction> callee = args.at<JSFunction>(0);
7889 Object** parameters = reinterpret_cast<Object**>(args[1]);
7890 const int argument_count = Smi::cast(args[2])->value();
7891
7892 Handle<JSObject> result =
7893 isolate->factory()->NewArgumentsObject(callee, argument_count);
7894 // Allocate the elements if needed.
7895 int parameter_count = callee->shared()->formal_parameter_count();
7896 if (argument_count > 0) {
7897 if (parameter_count > 0) {
7898 int mapped_count = Min(argument_count, parameter_count);
7899 Handle<FixedArray> parameter_map =
7900 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7901 parameter_map->set_map(
7902 isolate->heap()->non_strict_arguments_elements_map());
7903
7904 Handle<Map> old_map(result->map());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007905 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007906 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007907
7908 result->set_map(*new_map);
7909 result->set_elements(*parameter_map);
7910
7911 // Store the context and the arguments array at the beginning of the
7912 // parameter map.
7913 Handle<Context> context(isolate->context());
7914 Handle<FixedArray> arguments =
7915 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7916 parameter_map->set(0, *context);
7917 parameter_map->set(1, *arguments);
7918
7919 // Loop over the actual parameters backwards.
7920 int index = argument_count - 1;
7921 while (index >= mapped_count) {
7922 // These go directly in the arguments array and have no
7923 // corresponding slot in the parameter map.
7924 arguments->set(index, *(parameters - index - 1));
7925 --index;
7926 }
7927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007928 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007929 while (index >= 0) {
7930 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007931 Handle<String> name(scope_info->ParameterName(index));
7932 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007933 bool duplicate = false;
7934 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007935 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007936 duplicate = true;
7937 break;
7938 }
7939 }
7940
7941 if (duplicate) {
7942 // This goes directly in the arguments array with a hole in the
7943 // parameter map.
7944 arguments->set(index, *(parameters - index - 1));
7945 parameter_map->set_the_hole(index + 2);
7946 } else {
7947 // The context index goes in the parameter map with a hole in the
7948 // arguments array.
7949 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007950 for (int j = 0; j < context_local_count; ++j) {
7951 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007952 context_index = j;
7953 break;
7954 }
7955 }
7956 ASSERT(context_index >= 0);
7957 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007958 parameter_map->set(index + 2, Smi::FromInt(
7959 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007960 }
7961
7962 --index;
7963 }
7964 } else {
7965 // If there is no aliasing, the arguments object elements are not
7966 // special in any way.
7967 Handle<FixedArray> elements =
7968 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7969 result->set_elements(*elements);
7970 for (int i = 0; i < argument_count; ++i) {
7971 elements->set(i, *(parameters - i - 1));
7972 }
7973 }
7974 }
7975 return *result;
7976}
7977
7978
7979RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007980 SealHandleScope shs(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007981 ASSERT(args.length() == 3);
7982
7983 JSFunction* callee = JSFunction::cast(args[0]);
7984 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007985 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007986
lrn@chromium.org303ada72010-10-27 09:33:13 +00007987 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 { MaybeObject* maybe_result =
7989 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007990 if (!maybe_result->ToObject(&result)) return maybe_result;
7991 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007992 // Allocate the elements if needed.
7993 if (length > 0) {
7994 // Allocate the fixed array.
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00007995 FixedArray* array;
7996 { MaybeObject* maybe_obj =
7997 isolate->heap()->AllocateUninitializedFixedArray(length);
7998 if (!maybe_obj->To(&array)) return maybe_obj;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007999 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008000
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008001 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008002 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008003 for (int i = 0; i < length; i++) {
8004 array->set(i, *--parameters, mode);
8005 }
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +00008006 JSObject::cast(result)->set_elements(array);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008007 }
8008 return result;
8009}
8010
8011
verwaest@chromium.org662436e2013-08-28 08:41:27 +00008012RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) {
8013 HandleScope scope(isolate);
8014 ASSERT(args.length() == 1);
8015 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
8016 Handle<Context> context(isolate->context());
8017 PretenureFlag pretenure_flag = NOT_TENURED;
8018 Handle<JSFunction> result =
8019 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8020 context,
8021 pretenure_flag);
8022 return *result;
8023}
8024
8025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008026RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008028 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008029 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8030 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8031 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032
whesse@chromium.org7b260152011-06-20 15:33:18 +00008033 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008034 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008035 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8038 context,
8039 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 return *result;
8041}
8042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008043
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008044// Find the arguments of the JavaScript function invocation that called
8045// into C++ code. Collect these in a newly allocated array of handles (possibly
8046// prefixed by a number of empty handles).
8047static SmartArrayPointer<Handle<Object> > GetCallerArguments(
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008048 Isolate* isolate,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008049 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008050 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008051 // Find frame containing arguments passed to the caller.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008052 JavaScriptFrameIterator it(isolate);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008053 JavaScriptFrame* frame = it.frame();
8054 List<JSFunction*> functions(2);
8055 frame->GetFunctions(&functions);
8056 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008057 int inlined_jsframe_index = functions.length() - 1;
8058 JSFunction* inlined_function = functions[inlined_jsframe_index];
8059 Vector<SlotRef> args_slots =
8060 SlotRef::ComputeSlotMappingForArguments(
8061 frame,
8062 inlined_jsframe_index,
8063 inlined_function->shared()->formal_parameter_count());
8064
8065 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008067 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008068 SmartArrayPointer<Handle<Object> > param_data(
8069 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008071 Handle<Object> val = args_slots[i].GetValue(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008072 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008074
8075 args_slots.Dispose();
8076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008077 return param_data;
8078 } else {
8079 it.AdvanceToArgumentsFrame();
8080 frame = it.frame();
8081 int args_count = frame->ComputeParametersCount();
8082
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008083 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008084 SmartArrayPointer<Handle<Object> > param_data(
8085 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008087 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008088 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008089 }
8090 return param_data;
8091 }
8092}
8093
8094
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008095RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8096 HandleScope scope(isolate);
8097 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008098 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008099 RUNTIME_ASSERT(args[3]->IsNumber());
8100 Handle<Object> bindee = args.at<Object>(1);
8101
8102 // TODO(lrn): Create bound function in C++ code from premade shared info.
8103 bound_function->shared()->set_bound(true);
8104 // Get all arguments of calling function (Function.prototype.bind).
8105 int argc = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008106 SmartArrayPointer<Handle<Object> > arguments =
8107 GetCallerArguments(isolate, 0, &argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008108 // Don't count the this-arg.
8109 if (argc > 0) {
8110 ASSERT(*arguments[0] == args[2]);
8111 argc--;
8112 } else {
8113 ASSERT(args[2]->IsUndefined());
8114 }
8115 // Initialize array of bindings (function, this, and any existing arguments
8116 // if the function was already bound).
8117 Handle<FixedArray> new_bindings;
8118 int i;
8119 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8120 Handle<FixedArray> old_bindings(
8121 JSFunction::cast(*bindee)->function_bindings());
8122 new_bindings =
8123 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008124 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
8125 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008126 i = 0;
8127 for (int n = old_bindings->length(); i < n; i++) {
8128 new_bindings->set(i, old_bindings->get(i));
8129 }
8130 } else {
8131 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8132 new_bindings = isolate->factory()->NewFixedArray(array_size);
8133 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8134 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8135 i = 2;
8136 }
8137 // Copy arguments, skipping the first which is "this_arg".
8138 for (int j = 0; j < argc; j++, i++) {
8139 new_bindings->set(i, *arguments[j + 1]);
8140 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008141 new_bindings->set_map_no_write_barrier(
8142 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008143 bound_function->set_function_bindings(*new_bindings);
8144
8145 // Update length.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008146 Handle<String> length_string = isolate->factory()->length_string();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008147 Handle<Object> new_length(args.at<Object>(3));
8148 PropertyAttributes attr =
8149 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008150 ForceSetProperty(bound_function, length_string, new_length, attr);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008151 return *bound_function;
8152}
8153
8154
8155RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8156 HandleScope handles(isolate);
8157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008158 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008159 if (callable->IsJSFunction()) {
8160 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8161 if (function->shared()->bound()) {
8162 Handle<FixedArray> bindings(function->function_bindings());
8163 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8164 return *isolate->factory()->NewJSArrayWithElements(bindings);
8165 }
8166 }
8167 return isolate->heap()->undefined_value();
8168}
8169
8170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008171RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008173 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008174 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008175 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008176 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008177
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008178 // The argument is a bound function. Extract its bound arguments
8179 // and callable.
8180 Handle<FixedArray> bound_args =
8181 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8182 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8183 Handle<Object> bound_function(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008184 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
8185 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008186 ASSERT(!bound_function->IsJSFunction() ||
8187 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008189 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008190 SmartArrayPointer<Handle<Object> > param_data =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008191 GetCallerArguments(isolate, bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008192 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008193 param_data[i] = Handle<Object>(bound_args->get(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008194 JSFunction::kBoundArgumentsStartIndex + i), isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008195 }
8196
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008197 if (!bound_function->IsJSFunction()) {
8198 bool exception_thrown;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008199 bound_function = Execution::TryGetConstructorDelegate(isolate,
8200 bound_function,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008201 &exception_thrown);
8202 if (exception_thrown) return Failure::Exception();
8203 }
8204 ASSERT(bound_function->IsJSFunction());
8205
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008206 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008207 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008208 Execution::New(Handle<JSFunction>::cast(bound_function),
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008209 total_argc, param_data.get(), &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008210 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008211 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008212 }
8213 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008214 return *result;
8215}
8216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008218RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008220 ASSERT(args.length() == 1);
8221
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008222 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008224 // If the constructor isn't a proper function we throw a type error.
8225 if (!constructor->IsJSFunction()) {
8226 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8227 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 isolate->factory()->NewTypeError("not_constructor", arguments);
8229 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008230 }
8231
8232 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008233
8234 // If function should not have prototype, construction is not allowed. In this
8235 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008236 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008237 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8238 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 isolate->factory()->NewTypeError("not_constructor", arguments);
8240 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008241 }
8242
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008243#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008245 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 if (debug->StepInActive()) {
8247 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008248 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008249#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008251 if (function->has_initial_map()) {
8252 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 // The 'Function' function ignores the receiver object when
8254 // called using 'new' and creates a new JSFunction object that
8255 // is returned. The receiver object is only used for error
8256 // reporting if an error occurs when constructing the new
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00008257 // JSFunction. Factory::NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258 // allocate JSFunctions since it does not properly initialize
8259 // the shared part of the function. Since the receiver is
8260 // ignored anyway, we use the global object as the receiver
8261 // instead of a new JSFunction object. This way, errors are
8262 // reported the same way whether or not 'Function' is called
8263 // using 'new'.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008264 return isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266 }
8267
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008268 // The function should be compiled for the optimization hints to be
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008269 // available.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008270 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008271
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008272 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008273 if (!function->has_initial_map() &&
8274 shared->IsInobjectSlackTrackingInProgress()) {
8275 // The tracking is already in progress for another function. We can only
8276 // track one initial_map at a time, so we force the completion before the
8277 // function is called as a constructor for the first time.
8278 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008279 }
8280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8282 RETURN_IF_EMPTY_HANDLE(isolate, result);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 isolate->counters()->constructed_objects()->Increment();
8285 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008286
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008287 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288}
8289
8290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008291RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008292 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008293 ASSERT(args.length() == 1);
8294
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008295 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008296 function->shared()->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008299}
8300
8301
yangguo@chromium.org49546742013-12-23 16:17:49 +00008302RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileUnoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304 ASSERT(args.length() == 1);
8305
8306 Handle<JSFunction> function = args.at<JSFunction>(0);
8307#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008308 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008309 PrintF("[unoptimized: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008310 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311 PrintF("]\n");
8312 }
8313#endif
8314
lrn@chromium.org34e60782011-09-15 07:25:40 +00008315 // Compile the target function.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008316 ASSERT(function->shared()->allows_lazy_compilation());
8317
8318 Handle<Code> code = Compiler::GetUnoptimizedCode(function);
8319 RETURN_IF_EMPTY_HANDLE(isolate, code);
8320 function->ReplaceCode(*code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008322 // All done. Return the compiled code.
8323 ASSERT(function->is_compiled());
yangguo@chromium.org49546742013-12-23 16:17:49 +00008324 ASSERT(function->code()->kind() == Code::FUNCTION ||
8325 (FLAG_always_opt &&
8326 function->code()->kind() == Code::OPTIMIZED_FUNCTION));
8327 return *code;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328}
8329
8330
yangguo@chromium.org49546742013-12-23 16:17:49 +00008331RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileOptimized) {
8332 HandleScope scope(isolate);
8333 ASSERT(args.length() == 2);
8334 Handle<JSFunction> function = args.at<JSFunction>(0);
8335 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008336
yangguo@chromium.org49546742013-12-23 16:17:49 +00008337 Handle<Code> unoptimized(function->shared()->code());
8338 if (!function->shared()->is_compiled()) {
8339 // If the function is not compiled, do not optimize.
8340 // This can happen if the debugger is activated and
8341 // the function is returned to the not compiled state.
8342 // TODO(yangguo): reconsider this.
8343 function->ReplaceCode(function->shared()->code());
8344 } else if (!isolate->use_crankshaft() ||
8345 function->shared()->optimization_disabled() ||
8346 isolate->DebuggerHasBreakPoints()) {
8347 // If the function is not optimizable or debugger is active continue
8348 // using the code from the full compiler.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008349 if (FLAG_trace_opt) {
8350 PrintF("[failed to optimize ");
8351 function->PrintName();
8352 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
ulan@chromium.org750145a2013-03-07 15:14:13 +00008353 function->shared()->optimization_disabled() ? "F" : "T",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008354 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008355 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008356 function->ReplaceCode(*unoptimized);
8357 } else {
8358 Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT
8359 : Compiler::NOT_CONCURRENT;
8360 Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized, mode);
8361 function->ReplaceCode(code.is_null() ? *unoptimized : *code);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008362 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00008363
yangguo@chromium.org49546742013-12-23 16:17:49 +00008364 ASSERT(function->code()->kind() == Code::FUNCTION ||
8365 function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
8366 function->IsInOptimizationQueue());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008367 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008368}
8369
8370
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008371class ActivationsFinder : public ThreadVisitor {
8372 public:
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008373 Code* code_;
8374 bool has_code_activations_;
8375
8376 explicit ActivationsFinder(Code* code)
8377 : code_(code),
8378 has_code_activations_(false) { }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008379
8380 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008381 JavaScriptFrameIterator it(isolate, top);
8382 VisitFrames(&it);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008383 }
8384
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008385 void VisitFrames(JavaScriptFrameIterator* it) {
8386 for (; !it->done(); it->Advance()) {
8387 JavaScriptFrame* frame = it->frame();
8388 if (code_->contains(frame->pc())) has_code_activations_ = true;
8389 }
8390 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008391};
8392
8393
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008394RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008395 HandleScope scope(isolate);
8396 ASSERT(args.length() == 0);
8397 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008398 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008399 delete deoptimizer;
8400 return isolate->heap()->undefined_value();
8401}
8402
8403
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008404RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8405 HandleScope scope(isolate);
8406 ASSERT(args.length() == 1);
8407 RUNTIME_ASSERT(args[0]->IsSmi());
8408 Deoptimizer::BailoutType type =
8409 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8410 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008411 ASSERT(AllowHeapAllocation::IsAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008412
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008413 Handle<JSFunction> function = deoptimizer->function();
8414 Handle<Code> optimized_code = deoptimizer->compiled_code();
8415
8416 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
8417 ASSERT(type == deoptimizer->bailout_type());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008418
8419 // Make sure to materialize objects before causing any allocation.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008420 JavaScriptFrameIterator it(isolate);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008421 deoptimizer->MaterializeHeapObjects(&it);
8422 delete deoptimizer;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008423
8424 JavaScriptFrame* frame = it.frame();
8425 RUNTIME_ASSERT(frame->function()->IsJSFunction());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008426 ASSERT(frame->function() == *function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008427
8428 // Avoid doing too much work when running with --always-opt and keep
8429 // the optimized code around.
8430 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 }
8433
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008434 // Search for other activations of the same function and code.
8435 ActivationsFinder activations_finder(*optimized_code);
8436 activations_finder.VisitFrames(&it);
8437 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008439 if (!activations_finder.has_code_activations_) {
8440 if (function->code() == *optimized_code) {
8441 if (FLAG_trace_deopt) {
8442 PrintF("[removing optimized code for: ");
8443 function->PrintName();
8444 PrintF("]\n");
8445 }
8446 function->ReplaceCode(function->shared()->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00008448 } else {
titzer@chromium.org3f7dfd62013-08-22 14:10:03 +00008449 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
8450 // unconditionally if the code is not already marked for deoptimization.
8451 // If there is an index by shared function info, all the better.
lrn@chromium.org34e60782011-09-15 07:25:40 +00008452 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008453 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008454 // Evict optimized code for this function from the cache so that it doesn't
8455 // get used for new closures.
8456 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
8457 "notify deoptimized");
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008459 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008460}
8461
8462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008463RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008465 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008466 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008467 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008468
8469 Deoptimizer::DeoptimizeFunction(*function);
8470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008472}
8473
8474
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008475RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8476 HandleScope scope(isolate);
8477 ASSERT(args.length() == 1);
8478 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8479 Code* unoptimized = function->shared()->code();
8480 if (unoptimized->kind() == Code::FUNCTION) {
8481 unoptimized->ClearInlineCaches();
8482 unoptimized->ClearTypeFeedbackCells(isolate->heap());
8483 }
8484 return isolate->heap()->undefined_value();
8485}
8486
8487
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008489 SealHandleScope shs(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008490#if defined(USE_SIMULATOR)
8491 return isolate->heap()->true_value();
8492#else
8493 return isolate->heap()->false_value();
8494#endif
8495}
8496
8497
rossberg@chromium.org92597162013-08-23 13:28:00 +00008498RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008499 HandleScope scope(isolate);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00008500 return isolate->concurrent_recompilation_enabled()
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00008501 ? isolate->heap()->true_value() : isolate->heap()->false_value();
8502}
8503
8504
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008505RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8506 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008507 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008508 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008509
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008510 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008511 function->MarkForOptimization();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008512
8513 Code* unoptimized = function->shared()->code();
8514 if (args.length() == 2 &&
8515 unoptimized->kind() == Code::FUNCTION) {
8516 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
ulan@chromium.org750145a2013-03-07 15:14:13 +00008517 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008518 // Start patching from the currently patched loop nesting level.
8519 int current_level = unoptimized->allow_osr_at_loop_nesting_level();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008520 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level));
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008521 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00008522 unoptimized->set_allow_osr_at_loop_nesting_level(i);
8523 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8524 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008525 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) &&
8526 isolate->concurrent_recompilation_enabled()) {
8527 function->MarkForConcurrentOptimization();
ulan@chromium.org750145a2013-03-07 15:14:13 +00008528 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008529 }
8530
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008531 return isolate->heap()->undefined_value();
8532}
8533
8534
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008535RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008536 HandleScope scope(isolate);
8537 ASSERT(args.length() == 1);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008538 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8539 ASSERT(!function->IsOptimized());
8540 function->shared()->set_optimization_disabled(true);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008541 return isolate->heap()->undefined_value();
8542}
8543
8544
lrn@chromium.org1c092762011-05-09 09:42:16 +00008545RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8546 HandleScope scope(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008547 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008548 if (!isolate->use_crankshaft()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00008549 return Smi::FromInt(4); // 4 == "never".
8550 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008551 bool sync_with_compiler_thread = true;
8552 if (args.length() == 2) {
8553 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1);
8554 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) {
8555 sync_with_compiler_thread = false;
8556 }
8557 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008558 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00008559 if (isolate->concurrent_recompilation_enabled() &&
8560 sync_with_compiler_thread) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008561 while (function->IsInOptimizationQueue()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008562 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
8563 OS::Sleep(50);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008564 }
8565 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00008566 if (FLAG_always_opt) {
8567 // We may have always opt, but that is more best-effort than a real
8568 // promise, so we still say "no" if it is not optimized.
8569 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8570 : Smi::FromInt(2); // 2 == "no".
8571 }
jkummerow@chromium.org10480472013-07-17 08:22:15 +00008572 if (FLAG_deopt_every_n_times) {
8573 return Smi::FromInt(6); // 6 == "maybe deopted".
8574 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00008575 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8576 : Smi::FromInt(2); // 2 == "no".
8577}
8578
8579
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00008580RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) {
8581 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation);
8582 isolate->optimizing_compiler_thread()->Unblock();
8583 return isolate->heap()->undefined_value();
8584}
8585
8586
lrn@chromium.org1c092762011-05-09 09:42:16 +00008587RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8588 HandleScope scope(isolate);
8589 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008590 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008591 return Smi::FromInt(function->shared()->opt_count());
8592}
8593
8594
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008595static bool IsSuitableForOnStackReplacement(Isolate* isolate,
8596 Handle<JSFunction> function,
yangguo@chromium.org49546742013-12-23 16:17:49 +00008597 Handle<Code> current_code) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008598 // Keep track of whether we've succeeded in optimizing.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008599 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008600 // If we are trying to do OSR when there are already optimized
8601 // activations of the function, it means (a) the function is directly or
8602 // indirectly recursive and (b) an optimized invocation has been
8603 // deoptimized so that we are currently in an unoptimized activation.
8604 // Check for optimized activations of this function.
8605 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
8606 JavaScriptFrame* frame = it.frame();
8607 if (frame->is_optimized() && frame->function() == *function) return false;
8608 }
8609
8610 return true;
8611}
8612
8613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008614RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 HandleScope scope(isolate);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008616 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008617 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +00008618 Handle<Code> caller_code(function->shared()->code());
8619
8620 // We're not prepared to handle a function with arguments object.
8621 ASSERT(!function->shared()->uses_arguments());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008622
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008623 // Passing the PC in the javascript frame from the caller directly is
8624 // not GC safe, so we walk the stack to get it.
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008625 JavaScriptFrameIterator it(isolate);
8626 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008627 if (!caller_code->contains(frame->pc())) {
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008628 // Code on the stack may not be the code object referenced by the shared
8629 // function info. It may have been replaced to include deoptimization data.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008630 caller_code = Handle<Code>(frame->LookupCode());
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008631 }
8632
yangguo@chromium.org49546742013-12-23 16:17:49 +00008633 uint32_t pc_offset = static_cast<uint32_t>(
8634 frame->pc() - caller_code->instruction_start());
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +00008635
8636#ifdef DEBUG
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008637 ASSERT_EQ(frame->function(), *function);
yangguo@chromium.org49546742013-12-23 16:17:49 +00008638 ASSERT_EQ(frame->LookupCode(), *caller_code);
8639 ASSERT(caller_code->contains(frame->pc()));
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008640#endif // DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008641
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008642
yangguo@chromium.org49546742013-12-23 16:17:49 +00008643 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
8644 ASSERT(!ast_id.IsNone());
8645
8646 Compiler::ConcurrencyMode mode = isolate->concurrent_osr_enabled()
8647 ? Compiler::CONCURRENT : Compiler::NOT_CONCURRENT;
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008648 Handle<Code> result = Handle<Code>::null();
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008649
yangguo@chromium.org49546742013-12-23 16:17:49 +00008650 OptimizedCompileJob* job = NULL;
8651 if (mode == Compiler::CONCURRENT) {
8652 // Gate the OSR entry with a stack check.
8653 BackEdgeTable::AddStackCheck(caller_code, pc_offset);
8654 // Poll already queued compilation jobs.
8655 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
8656 if (thread->IsQueuedForOSR(function, ast_id)) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008657 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008658 PrintF("[OSR - Still waiting for queued: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008659 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008660 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008661 }
8662 return NULL;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008663 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008664
yangguo@chromium.org49546742013-12-23 16:17:49 +00008665 job = thread->FindReadyOSRCandidate(function, ast_id);
8666 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008667
yangguo@chromium.org49546742013-12-23 16:17:49 +00008668 if (job != NULL) {
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008669 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008670 PrintF("[OSR - Found ready: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008671 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008672 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008673 }
yangguo@chromium.org49546742013-12-23 16:17:49 +00008674 result = Compiler::GetConcurrentlyOptimizedCode(job);
8675 } else if (result.is_null() &&
8676 IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
8677 if (FLAG_trace_osr) {
8678 PrintF("[OSR - Compiling: ");
8679 function->PrintName();
8680 PrintF(" at AST id %d]\n", ast_id.ToInt());
8681 }
8682 result = Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
8683 if (result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
8684 // Optimization is queued. Return to check later.
8685 return NULL;
8686 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008687 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008688
machenbach@chromium.org528ce022013-09-23 14:09:36 +00008689 // Revert the patched back edge table, regardless of whether OSR succeeds.
yangguo@chromium.org49546742013-12-23 16:17:49 +00008690 BackEdgeTable::Revert(isolate, *caller_code);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008691
8692 // Check whether we ended up with usable optimized code.
8693 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
8694 DeoptimizationInputData* data =
8695 DeoptimizationInputData::cast(result->deoptimization_data());
8696
8697 if (data->OsrPcOffset()->value() >= 0) {
8698 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
8699 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008700 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008701 ast_id.ToInt(), data->OsrPcOffset()->value());
8702 }
8703 // TODO(titzer): this is a massive hack to make the deopt counts
8704 // match. Fix heuristics for reenabling optimizations!
8705 function->shared()->increment_deopt_count();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008706
8707 // TODO(titzer): Do not install code into the function.
8708 function->ReplaceCode(*result);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008709 return *result;
8710 }
8711 }
8712
yangguo@chromium.org49546742013-12-23 16:17:49 +00008713 // Failed.
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008714 if (FLAG_trace_osr) {
yangguo@chromium.org49546742013-12-23 16:17:49 +00008715 PrintF("[OSR - Failed: ");
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008716 function->PrintName();
yangguo@chromium.org49546742013-12-23 16:17:49 +00008717 PrintF(" at AST id %d]\n", ast_id.ToInt());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008718 }
8719
yangguo@chromium.org49546742013-12-23 16:17:49 +00008720 function->ReplaceCode(function->shared()->code());
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00008721 return NULL;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008722}
8723
8724
rossberg@chromium.orgebeba022013-08-19 09:36:44 +00008725RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) {
8726 SealHandleScope shs(isolate);
8727 ASSERT(args.length() == 2);
8728#ifdef DEBUG
8729 CONVERT_SMI_ARG_CHECKED(interval, 0);
8730 CONVERT_SMI_ARG_CHECKED(timeout, 1);
8731 isolate->heap()->set_allocation_timeout(timeout);
8732 FLAG_gc_interval = interval;
8733#endif
8734 return isolate->heap()->undefined_value();
8735}
8736
8737
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008738RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008739 SealHandleScope shs(isolate);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008740 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8741 return isolate->heap()->undefined_value();
8742}
8743
8744
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008745RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008746 SealHandleScope shs(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008747 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8748 return isolate->heap()->nan_value();
8749}
8750
8751
danno@chromium.orgc612e022011-11-10 11:38:15 +00008752RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8753 HandleScope scope(isolate);
8754 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008755 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008756 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8757 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008758
8759 // If there are too many arguments, allocate argv via malloc.
8760 const int argv_small_size = 10;
8761 Handle<Object> argv_small_buffer[argv_small_size];
8762 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8763 Handle<Object>* argv = argv_small_buffer;
8764 if (argc > argv_small_size) {
8765 argv = new Handle<Object>[argc];
8766 if (argv == NULL) return isolate->StackOverflow();
8767 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8768 }
8769
8770 for (int i = 0; i < argc; ++i) {
8771 MaybeObject* maybe = args[1 + i];
8772 Object* object;
8773 if (!maybe->To<Object>(&object)) return maybe;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008774 argv[i] = Handle<Object>(object, isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008775 }
8776
8777 bool threw;
8778 Handle<JSReceiver> hfun(fun);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008779 Handle<Object> hreceiver(receiver, isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008780 Handle<Object> result = Execution::Call(
8781 isolate, hfun, hreceiver, argc, argv, &threw, true);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008782
8783 if (threw) return Failure::Exception();
8784 return *result;
8785}
8786
8787
lrn@chromium.org34e60782011-09-15 07:25:40 +00008788RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8789 HandleScope scope(isolate);
8790 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008791 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008792 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008793 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008794 CONVERT_SMI_ARG_CHECKED(offset, 3);
8795 CONVERT_SMI_ARG_CHECKED(argc, 4);
danno@chromium.org59400602013-08-13 17:09:37 +00008796 RUNTIME_ASSERT(offset >= 0);
8797 RUNTIME_ASSERT(argc >= 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008798
8799 // If there are too many arguments, allocate argv via malloc.
8800 const int argv_small_size = 10;
8801 Handle<Object> argv_small_buffer[argv_small_size];
8802 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8803 Handle<Object>* argv = argv_small_buffer;
8804 if (argc > argv_small_size) {
8805 argv = new Handle<Object>[argc];
8806 if (argv == NULL) return isolate->StackOverflow();
8807 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8808 }
8809
8810 for (int i = 0; i < argc; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008811 argv[i] = Object::GetElement(isolate, arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008812 }
8813
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008814 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00008815 Handle<Object> result = Execution::Call(
8816 isolate, fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008817
8818 if (threw) return Failure::Exception();
8819 return *result;
8820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 ASSERT(args.length() == 1);
8826 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008827 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828}
8829
8830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008832 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008833 ASSERT(args.length() == 1);
8834 RUNTIME_ASSERT(!args[0]->IsJSFunction());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008835 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0));
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008836}
8837
8838
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008839RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008840 SealHandleScope shs(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008841 ASSERT(args.length() == 2);
8842
8843 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8844 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
8845 Context* result;
8846 MaybeObject* maybe_result =
8847 isolate->heap()->AllocateGlobalContext(function, scope_info);
8848 if (!maybe_result->To(&result)) return maybe_result;
8849
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008850 ASSERT(function->context() == isolate->context());
8851 ASSERT(function->context()->global_object() == result->global_object());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008852 isolate->set_context(result);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008853 result->global_object()->set_global_context(result);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008854
8855 return result; // non-failure
8856}
8857
8858
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008859RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008860 SealHandleScope shs(isolate);
kasper.lund7276f142008-07-30 08:49:36 +00008861 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008862
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008863 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008864 int length = function->shared()->scope_info()->ContextLength();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008865 Context* result;
8866 MaybeObject* maybe_result =
8867 isolate->heap()->AllocateFunctionContext(length, function);
8868 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008870 isolate->set_context(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871
kasper.lund7276f142008-07-30 08:49:36 +00008872 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873}
8874
lrn@chromium.org303ada72010-10-27 09:33:13 +00008875
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008876RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008877 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008878 ASSERT(args.length() == 2);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00008879 JSReceiver* extension_object;
8880 if (args[0]->IsJSReceiver()) {
8881 extension_object = JSReceiver::cast(args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008882 } else {
8883 // Convert the object to a proper JavaScript object.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008884 MaybeObject* maybe_js_object = args[0]->ToObject(isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008885 if (!maybe_js_object->To(&extension_object)) {
8886 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8887 HandleScope scope(isolate);
8888 Handle<Object> handle = args.at<Object>(0);
8889 Handle<Object> result =
8890 isolate->factory()->NewTypeError("with_expression",
8891 HandleVector(&handle, 1));
8892 return isolate->Throw(*result);
8893 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008894 return maybe_js_object;
8895 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896 }
8897 }
8898
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008899 JSFunction* function;
8900 if (args[1]->IsSmi()) {
8901 // A smi sentinel indicates a context nested inside global code rather
8902 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008903 // gotten from the native context.
8904 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008905 } else {
8906 function = JSFunction::cast(args[1]);
8907 }
8908
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008909 Context* context;
8910 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008911 isolate->heap()->AllocateWithContext(function,
8912 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008913 extension_object);
8914 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008916 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008917}
8918
8919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008920RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008921 SealHandleScope shs(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008922 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008923 String* name = String::cast(args[0]);
8924 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008925 JSFunction* function;
8926 if (args[2]->IsSmi()) {
8927 // A smi sentinel indicates a context nested inside global code rather
8928 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008929 // gotten from the native context.
8930 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008931 } else {
8932 function = JSFunction::cast(args[2]);
8933 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008934 Context* context;
8935 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008936 isolate->heap()->AllocateCatchContext(function,
8937 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008938 name,
8939 thrown_object);
8940 if (!maybe_context->To(&context)) return maybe_context;
8941 isolate->set_context(context);
8942 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008943}
8944
8945
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008946RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008947 SealHandleScope shs(isolate);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008948 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008949 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008950 JSFunction* function;
8951 if (args[1]->IsSmi()) {
8952 // A smi sentinel indicates a context nested inside global code rather
8953 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008954 // gotten from the native context.
8955 function = isolate->context()->native_context()->closure();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008956 } else {
8957 function = JSFunction::cast(args[1]);
8958 }
8959 Context* context;
8960 MaybeObject* maybe_context =
8961 isolate->heap()->AllocateBlockContext(function,
8962 isolate->context(),
8963 scope_info);
8964 if (!maybe_context->To(&context)) return maybe_context;
8965 isolate->set_context(context);
8966 return context;
8967}
8968
8969
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008970RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008971 SealHandleScope shs(isolate);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008972 ASSERT(args.length() == 1);
8973 Object* obj = args[0];
8974 return isolate->heap()->ToBoolean(obj->IsJSModule());
8975}
8976
8977
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008978RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008979 SealHandleScope shs(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008980 ASSERT(args.length() == 2);
8981 CONVERT_SMI_ARG_CHECKED(index, 0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008982
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008983 if (!args[1]->IsScopeInfo()) {
8984 // Module already initialized. Find hosting context and retrieve context.
8985 Context* host = Context::cast(isolate->context())->global_context();
8986 Context* context = Context::cast(host->get(index));
8987 ASSERT(context->previous() == isolate->context());
8988 isolate->set_context(context);
8989 return context;
8990 }
8991
8992 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
8993
8994 // Allocate module context.
8995 HandleScope scope(isolate);
8996 Factory* factory = isolate->factory();
8997 Handle<Context> context = factory->NewModuleContext(scope_info);
8998 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
8999 context->set_module(*module);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009000 Context* previous = isolate->context();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00009001 context->set_previous(previous);
9002 context->set_closure(previous->closure());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009003 context->set_global_object(previous->global_object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009004 isolate->set_context(*context);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009005
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009006 // Find hosting scope and initialize internal variable holding module there.
9007 previous->global_context()->set(index, *context);
9008
9009 return *context;
9010}
9011
9012
9013RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) {
9014 HandleScope scope(isolate);
9015 ASSERT(args.length() == 1);
9016 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
9017 Context* host_context = isolate->context();
9018
9019 for (int i = 0; i < descriptions->length(); ++i) {
9020 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
9021 int host_index = description->host_index();
9022 Handle<Context> context(Context::cast(host_context->get(host_index)));
9023 Handle<JSModule> module(context->module());
9024
9025 for (int j = 0; j < description->length(); ++j) {
9026 Handle<String> name(description->name(j));
9027 VariableMode mode = description->mode(j);
9028 int index = description->index(j);
9029 switch (mode) {
9030 case VAR:
9031 case LET:
9032 case CONST:
9033 case CONST_HARMONY: {
9034 PropertyAttributes attr =
9035 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
9036 Handle<AccessorInfo> info =
9037 Accessors::MakeModuleExport(name, index, attr);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00009038 Handle<Object> result = JSObject::SetAccessor(module, info);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00009039 ASSERT(!(result.is_null() || result->IsUndefined()));
9040 USE(result);
9041 break;
9042 }
9043 case MODULE: {
9044 Object* referenced_context = Context::cast(host_context)->get(index);
9045 Handle<JSModule> value(Context::cast(referenced_context)->module());
9046 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode);
9047 break;
9048 }
9049 case INTERNAL:
9050 case TEMPORARY:
9051 case DYNAMIC:
9052 case DYNAMIC_GLOBAL:
9053 case DYNAMIC_LOCAL:
9054 UNREACHABLE();
9055 }
9056 }
9057
9058 JSObject::PreventExtensions(module);
9059 }
9060
9061 ASSERT(!isolate->has_pending_exception());
9062 return isolate->heap()->undefined_value();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00009063}
9064
9065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009066RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 ASSERT(args.length() == 2);
9069
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009070 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
9071 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009072
9073 int index;
9074 PropertyAttributes attributes;
9075 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009076 BindingFlags binding_flags;
9077 Handle<Object> holder = context->Lookup(name,
9078 flags,
9079 &index,
9080 &attributes,
9081 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009083 // If the slot was not found the result is true.
9084 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009086 }
9087
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009088 // If the slot was found in a context, it should be DONT_DELETE.
9089 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009091 }
9092
9093 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009094 // the global object, or the subject of a with. Try to delete it
9095 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00009096 Handle<JSObject> object = Handle<JSObject>::cast(holder);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009097 Handle<Object> result = JSReceiver::DeleteProperty(object, name);
9098 RETURN_IF_EMPTY_HANDLE(isolate, result);
9099 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100}
9101
9102
ager@chromium.orga1645e22009-09-09 19:27:10 +00009103// A mechanism to return a pair of Object pointers in registers (if possible).
9104// How this is achieved is calling convention-dependent.
9105// All currently supported x86 compiles uses calling conventions that are cdecl
9106// variants where a 64-bit value is returned in two 32-bit registers
9107// (edx:eax on ia32, r1:r0 on ARM).
9108// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
9109// In Win64 calling convention, a struct of two pointers is returned in memory,
9110// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009111#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009112struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009113 MaybeObject* x;
9114 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009115};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009116
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009117
lrn@chromium.org303ada72010-10-27 09:33:13 +00009118static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009119 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009120 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9121 // In Win64 they are assigned to a hidden first argument.
9122 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009123}
9124#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009125typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009126static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009128 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009130#endif
9131
9132
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133static inline MaybeObject* Unhole(Heap* heap,
9134 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009135 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9137 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139}
9140
9141
danno@chromium.org40cb8782011-05-25 07:58:50 +00009142static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9143 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009144 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009145 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009146 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009147 JSFunction* context_extension_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009148 top->native_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009149 // If the holder isn't a context extension object, we just return it
9150 // as the receiver. This allows arguments objects to be used as
9151 // receivers, but only if they are put in the context scope chain
9152 // explicitly via a with-statement.
9153 Object* constructor = holder->map()->constructor();
9154 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009155 // Fall back to using the global object as the implicit receiver if
9156 // the property turns out to be a local variable allocated in a
9157 // context extension object - introduced via eval. Implicit global
9158 // receivers are indicated with the hole value.
9159 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009160}
9161
9162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163static ObjectPair LoadContextSlotHelper(Arguments args,
9164 Isolate* isolate,
9165 bool throw_error) {
9166 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009167 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009169 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009172 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009173 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174
9175 int index;
9176 PropertyAttributes attributes;
9177 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009178 BindingFlags binding_flags;
9179 Handle<Object> holder = context->Lookup(name,
9180 flags,
9181 &index,
9182 &attributes,
9183 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009184 if (isolate->has_pending_exception()) {
9185 return MakePair(Failure::Exception(), NULL);
9186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009188 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009190 ASSERT(holder->IsContext());
9191 // If the "property" we were looking for is a local variable, the
9192 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009193 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009194 // Use the hole as the receiver to signal that the receiver is implicit
9195 // and that the global receiver should be used (as distinguished from an
9196 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009197 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009198 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009199 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009200 switch (binding_flags) {
9201 case MUTABLE_CHECK_INITIALIZED:
9202 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9203 if (value->IsTheHole()) {
9204 Handle<Object> reference_error =
9205 isolate->factory()->NewReferenceError("not_defined",
9206 HandleVector(&name, 1));
9207 return MakePair(isolate->Throw(*reference_error), NULL);
9208 }
9209 // FALLTHROUGH
9210 case MUTABLE_IS_INITIALIZED:
9211 case IMMUTABLE_IS_INITIALIZED:
9212 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9213 ASSERT(!value->IsTheHole());
9214 return MakePair(value, *receiver);
9215 case IMMUTABLE_CHECK_INITIALIZED:
9216 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9217 case MISSING_BINDING:
9218 UNREACHABLE();
9219 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221 }
9222
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009223 // Otherwise, if the slot was found the holder is a context extension
9224 // object, subject of a with, or a global object. We read the named
9225 // property from it.
9226 if (!holder.is_null()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009227 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00009228 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009229 // GetProperty below can cause GC.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009230 Handle<Object> receiver_handle(
9231 object->IsGlobalObject()
9232 ? GlobalObject::cast(*object)->global_receiver()
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009233 : object->IsJSProxy() ? static_cast<Object*>(*object)
9234 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009235 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009236
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009237 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009238 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009239 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009240 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 }
9242
9243 if (throw_error) {
9244 // The property doesn't exist - throw exception.
9245 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 isolate->factory()->NewReferenceError("not_defined",
9247 HandleVector(&name, 1));
9248 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009250 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 return MakePair(isolate->heap()->undefined_value(),
9252 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253 }
9254}
9255
9256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009257RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259}
9260
9261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009262RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264}
9265
9266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009267RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009268 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009269 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009271 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009272 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9273 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009274 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9275 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9276 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277
9278 int index;
9279 PropertyAttributes attributes;
9280 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009281 BindingFlags binding_flags;
9282 Handle<Object> holder = context->Lookup(name,
9283 flags,
9284 &index,
9285 &attributes,
9286 &binding_flags);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009287 if (isolate->has_pending_exception()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288
9289 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009290 // The property was found in a context slot.
9291 Handle<Context> context = Handle<Context>::cast(holder);
9292 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9293 context->get(index)->IsTheHole()) {
9294 Handle<Object> error =
9295 isolate->factory()->NewReferenceError("not_defined",
9296 HandleVector(&name, 1));
9297 return isolate->Throw(*error);
9298 }
9299 // Ignore if read_only variable.
9300 if ((attributes & READ_ONLY) == 0) {
9301 // Context is a fixed array and set cannot fail.
9302 context->set(index, *value);
9303 } else if (strict_mode == kStrictMode) {
9304 // Setting read only property in strict mode.
9305 Handle<Object> error =
9306 isolate->factory()->NewTypeError("strict_cannot_assign",
9307 HandleVector(&name, 1));
9308 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 }
9310 return *value;
9311 }
9312
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009313 // Slow case: The property is not in a context slot. It is either in a
9314 // context extension object, a property of the subject of a with, or a
9315 // property of the global object.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009316 Handle<JSReceiver> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009317
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009318 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009319 // The property exists on the holder.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009320 object = Handle<JSReceiver>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009322 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009324
9325 if (strict_mode == kStrictMode) {
9326 // Throw in strict mode (assignment to undefined variable).
9327 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009328 isolate->factory()->NewReferenceError(
9329 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009330 return isolate->Throw(*error);
9331 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009332 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 attributes = NONE;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009334 object = Handle<JSReceiver>(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335 }
9336
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009337 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009338 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009339 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009340 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009342 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009343 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009344 // Setting read only property in strict mode.
9345 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 isolate->factory()->NewTypeError(
9347 "strict_cannot_assign", HandleVector(&name, 1));
9348 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 }
9350 return *value;
9351}
9352
9353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009354RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009355 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356 ASSERT(args.length() == 1);
9357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359}
9360
9361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009362RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364 ASSERT(args.length() == 1);
9365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367}
9368
9369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009370RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009371 SealHandleScope shs(isolate);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009372 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009373 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009374}
9375
9376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009377RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
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 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009382 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383 isolate->factory()->NewReferenceError("not_defined",
9384 HandleVector(&name, 1));
9385 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386}
9387
9388
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009389RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) {
9390 HandleScope scope(isolate);
9391 ASSERT(args.length() == 0);
9392 return isolate->Throw(*isolate->factory()->NewTypeError(
9393 "not_date_object", HandleVector<Object>(NULL, 0)));
9394}
9395
9396
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00009397RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) {
9398 HandleScope scope(isolate);
9399 ASSERT(args.length() == 1);
9400 CONVERT_SMI_ARG_CHECKED(message_id, 0);
9401 const char* message = GetBailoutReason(
9402 static_cast<BailoutReason>(message_id));
9403 Handle<Name> message_handle =
9404 isolate->factory()->NewStringFromAscii(CStrVector(message));
9405 return isolate->Throw(*message_handle);
9406}
9407
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009409RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009410 SealHandleScope shs(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009411 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412
9413 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 if (isolate->stack_guard()->IsStackOverflow()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009417
ulan@chromium.org812308e2012-02-29 15:58:45 +00009418 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419}
9420
9421
yangguo@chromium.org49546742013-12-23 16:17:49 +00009422RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallOptimizedCode) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00009423 HandleScope scope(isolate);
9424 ASSERT(args.length() == 1);
9425 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
9426
9427 // First check if this is a real stack overflow.
9428 if (isolate->stack_guard()->IsStackOverflow()) {
9429 SealHandleScope shs(isolate);
9430 return isolate->StackOverflow();
9431 }
9432
9433 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
9434 return (function->IsOptimized()) ? function->code()
9435 : function->shared()->code();
9436}
9437
9438
yangguo@chromium.org56454712012-02-16 15:33:53 +00009439RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009440 SealHandleScope shs(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009441 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009442 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009443}
9444
9445
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009446static int StackSize(Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447 int n = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009448 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 return n;
9450}
9451
9452
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009453static void PrintTransition(Isolate* isolate, Object* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 // indentation
9455 { const int nmax = 80;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009456 int n = StackSize(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457 if (n <= nmax)
9458 PrintF("%4d:%*s", n, n, "");
9459 else
9460 PrintF("%4d:%*s", n, nmax, "...");
9461 }
9462
9463 if (result == NULL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009464 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009465 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466 } else {
9467 // function result
9468 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009469 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009470 PrintF("\n");
9471 }
9472}
9473
9474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009475RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009476 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009477 ASSERT(args.length() == 0);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009478 PrintTransition(isolate, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480}
9481
9482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009483RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009484 SealHandleScope shs(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009485 PrintTransition(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486 return args[0]; // return TOS
9487}
9488
9489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009490RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009491 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 ASSERT(args.length() == 1);
9493
9494#ifdef DEBUG
9495 if (args[0]->IsString()) {
9496 // If we have a string, assume it's a code "marker"
9497 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009498 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009500 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9501 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 } else {
9503 PrintF("DebugPrint: ");
9504 }
9505 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009506 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009507 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009508 HeapObject::cast(args[0])->map()->Print();
9509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009511 // ShortPrint is available in release mode. Print is not.
9512 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513#endif
9514 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009515 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516
9517 return args[0]; // return TOS
9518}
9519
9520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009521RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009522 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009523 ASSERT(args.length() == 0);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00009524 isolate->PrintStack(stdout);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526}
9527
9528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009530 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +00009531 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532
9533 // According to ECMA-262, section 15.9.1, page 117, the precision of
9534 // the number in a Date object representing a particular instant in
9535 // time is milliseconds. Therefore, we floor the result of getting
9536 // the OS time.
9537 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009539}
9540
9541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009542RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009544 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009546 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009547 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009549 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009550
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009551 JSObject::EnsureCanContainHeapObjectElements(output);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009552 RUNTIME_ASSERT(output->HasFastObjectElements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009553
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009554 DisallowHeapAllocation no_gc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009555
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009556 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009557 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9558 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009559 String::FlatContent str_content = str->GetFlatContent();
9560 if (str_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009561 result = DateParser::Parse(str_content.ToOneByteVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009562 output_array,
9563 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009565 ASSERT(str_content.IsTwoByte());
9566 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009567 output_array,
9568 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009569 }
9570
9571 if (result) {
9572 return *output;
9573 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009575 }
9576}
9577
9578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009579RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009580 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 ASSERT(args.length() == 1);
9582
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009583 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009584 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9585 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587}
9588
9589
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009590RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009591 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009592 ASSERT(args.length() == 1);
9593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009595 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9596
9597 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598}
9599
9600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009601RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009602 SealHandleScope shs(isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009603 ASSERT(args.length() == 1);
9604 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009605 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009606 return JSGlobalObject::cast(global)->global_receiver();
9607}
9608
9609
jkummerow@chromium.org113035e2013-12-13 15:13:40 +00009610RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) {
9611 SealHandleScope shs(isolate);
9612 ASSERT(args.length() == 1);
9613 Object* global = args[0];
9614 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
9615 return isolate->heap()->ToBoolean(
9616 !JSGlobalObject::cast(global)->IsDetached());
9617}
9618
9619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009620RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009622 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009623 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009624
danno@chromium.org59400602013-08-13 17:09:37 +00009625 source = Handle<String>(FlattenGetString(source));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009626 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009627 Handle<Object> result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009628 if (source->IsSeqOneByteString()) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009629 result = JsonParser<true>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009630 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009631 result = JsonParser<false>::Parse(source);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009632 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009633 if (result.is_null()) {
9634 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009636 return Failure::Exception();
9637 }
9638 return *result;
9639}
9640
9641
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009642bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9643 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009644 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9645 // Check with callback if set.
9646 AllowCodeGenerationFromStringsCallback callback =
9647 isolate->allow_code_gen_callback();
9648 if (callback == NULL) {
9649 // No callback set and code generation disallowed.
9650 return false;
9651 } else {
9652 // Callback set. Let it decide if code generation is allowed.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009653 VMState<EXTERNAL> state(isolate);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009654 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009655 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009656}
9657
9658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009659RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009660 HandleScope scope(isolate);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009661 ASSERT_EQ(2, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009662 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009663 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009664
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009665 // Extract native context.
9666 Handle<Context> context(isolate->context()->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009667
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009668 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009669 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009670 if (context->allow_code_gen_from_strings()->IsFalse() &&
9671 !CodeGenerationFromStringsAllowed(isolate, context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009672 Handle<Object> error_message =
9673 context->ErrorMessageForCodeGenerationFromStrings();
9674 return isolate->Throw(*isolate->factory()->NewEvalError(
9675 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009676 }
9677
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009678 // Compile source string in the native context.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00009679 ParseRestriction restriction = function_literal_only
9680 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
yangguo@chromium.org49546742013-12-23 16:17:49 +00009681 Handle<JSFunction> fun = Compiler::GetFunctionFromEval(
9682 source, context, CLASSIC_MODE, restriction, RelocInfo::kNoPosition);
9683 RETURN_IF_EMPTY_HANDLE(isolate, fun);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684 return *fun;
9685}
9686
9687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009688static ObjectPair CompileGlobalEval(Isolate* isolate,
9689 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009690 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009691 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009692 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009693 Handle<Context> context = Handle<Context>(isolate->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009694 Handle<Context> native_context = Handle<Context>(context->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009695
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009696 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009697 // strings. Throw an exception if it doesn't.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009698 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
9699 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009700 Handle<Object> error_message =
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00009701 native_context->ErrorMessageForCodeGenerationFromStrings();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00009702 isolate->Throw(*isolate->factory()->NewEvalError(
9703 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009704 return MakePair(Failure::Exception(), NULL);
9705 }
9706
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009707 // Deal with a normal eval call with a string argument. Compile it
9708 // and return the compiled function bound in the local context.
yangguo@chromium.org49546742013-12-23 16:17:49 +00009709 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
9710 Handle<JSFunction> compiled = Compiler::GetFunctionFromEval(
9711 source, context, language_mode, restriction, scope_position);
9712 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, compiled,
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00009713 MakePair(Failure::Exception(), NULL));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009714 return MakePair(*compiled, *receiver);
9715}
9716
9717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009718RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009719 HandleScope scope(isolate);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009720 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009721
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009722 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009723
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009724 // If "eval" didn't refer to the original GlobalEval, it's not a
9725 // direct call to eval.
9726 // (And even if it is, but the first argument isn't a string, just let
9727 // execution default to an indirect call to eval, which will also return
9728 // the first argument without doing anything).
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009729 if (*callee != isolate->native_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009730 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009731 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009732 }
9733
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009734 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009735 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009736 return CompileGlobalEval(isolate,
9737 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009738 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009739 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009740 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009741}
9742
9743
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009744// Allocate a block of memory in the given space (filled with a filler).
9745// Used as a fall-back for generated code when the space is full.
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009746static MaybeObject* Allocate(Isolate* isolate,
9747 int size,
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009748 bool double_align,
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009749 AllocationSpace space) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009750 Heap* heap = isolate->heap();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009751 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9752 RUNTIME_ASSERT(size > 0);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009753 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009754 HeapObject* allocation;
9755 { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space);
9756 if (!maybe_allocation->To(&allocation)) return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009757 }
machenbach@chromium.org935a7792013-11-12 09:05:18 +00009758#ifdef DEBUG
9759 MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address());
9760 ASSERT(chunk->owner()->identity() == space);
9761#endif
9762 heap->CreateFillerObjectAt(allocation->address(), size);
9763 return allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009764}
9765
9766
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009767RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009768 SealHandleScope shs(isolate);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009769 ASSERT(args.length() == 1);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009770 CONVERT_SMI_ARG_CHECKED(size, 0);
9771 return Allocate(isolate, size, false, NEW_SPACE);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00009772}
9773
9774
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009775RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInTargetSpace) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009776 SealHandleScope shs(isolate);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00009777 ASSERT(args.length() == 2);
9778 CONVERT_SMI_ARG_CHECKED(size, 0);
9779 CONVERT_SMI_ARG_CHECKED(flags, 1);
9780 bool double_align = AllocateDoubleAlignFlag::decode(flags);
9781 AllocationSpace space = AllocateTargetSpace::decode(flags);
9782 return Allocate(isolate, size, double_align, space);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00009783}
9784
9785
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009786// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009787// array. Returns true if the element was pushed on the stack and
9788// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009789RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009790 HandleScope scope(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009791 ASSERT(args.length() == 2);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009792 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
9793 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009794 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009795 int length = Smi::cast(array->length())->value();
9796 FixedArray* elements = FixedArray::cast(array->elements());
9797 for (int i = 0; i < length; i++) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009798 if (elements->get(i) == *element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009799 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009800
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009801 // Strict not needed. Used for cycle detection in Array join implementation.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00009802 RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length,
9803 element,
9804 kNonStrictMode,
9805 true));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009806 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009807}
9808
9809
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009810/**
9811 * A simple visitor visits every element of Array's.
9812 * The backend storage can be a fixed array for fast elements case,
9813 * or a dictionary for sparse array. Since Dictionary is a subtype
9814 * of FixedArray, the class can be used by both fast and slow cases.
9815 * The second parameter of the constructor, fast_elements, specifies
9816 * whether the storage is a FixedArray or Dictionary.
9817 *
9818 * An index limit is used to deal with the situation that a result array
9819 * length overflows 32-bit non-negative integer.
9820 */
9821class ArrayConcatVisitor {
9822 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009823 ArrayConcatVisitor(Isolate* isolate,
9824 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009825 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 isolate_(isolate),
9827 storage_(Handle<FixedArray>::cast(
9828 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009829 index_offset_(0u),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009830 fast_elements_(fast_elements),
9831 exceeds_array_limit_(false) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009832
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009833 ~ArrayConcatVisitor() {
9834 clear_storage();
9835 }
9836
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009837 void visit(uint32_t i, Handle<Object> elm) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009838 if (i > JSObject::kMaxElementCount - index_offset_) {
9839 exceeds_array_limit_ = true;
9840 return;
9841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009842 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009843
9844 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 if (index < static_cast<uint32_t>(storage_->length())) {
9846 storage_->set(index, *elm);
9847 return;
9848 }
9849 // Our initial estimate of length was foiled, possibly by
9850 // getters on the arrays increasing the length of later arrays
9851 // during iteration.
9852 // This shouldn't happen in anything but pathological cases.
9853 SetDictionaryMode(index);
9854 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009855 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009856 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009857 Handle<SeededNumberDictionary> dict(
9858 SeededNumberDictionary::cast(*storage_));
9859 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009860 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009861 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009862 // Dictionary needed to grow.
9863 clear_storage();
9864 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009865 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009866 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009867
9868 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009869 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9870 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009871 } else {
9872 index_offset_ += delta;
9873 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009874 }
9875
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009876 bool exceeds_array_limit() {
9877 return exceeds_array_limit_;
9878 }
9879
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009880 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009882 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009883 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009884 Handle<Map> map;
9885 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009886 map = isolate_->factory()->GetElementsTransitionMap(array,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009887 FAST_HOLEY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009889 map = isolate_->factory()->GetElementsTransitionMap(array,
9890 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009891 }
9892 array->set_map(*map);
9893 array->set_length(*length);
9894 array->set_elements(*storage_);
9895 return array;
9896 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009897
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009898 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009899 // Convert storage to dictionary mode.
9900 void SetDictionaryMode(uint32_t index) {
9901 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009902 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009903 Handle<SeededNumberDictionary> slow_storage(
9904 isolate_->factory()->NewSeededNumberDictionary(
9905 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009906 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9907 for (uint32_t i = 0; i < current_length; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009908 HandleScope loop_scope(isolate_);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009909 Handle<Object> element(current_storage->get(i), isolate_);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009910 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009911 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009913 if (!new_storage.is_identical_to(slow_storage)) {
9914 slow_storage = loop_scope.CloseAndEscape(new_storage);
9915 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009916 }
9917 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009918 clear_storage();
9919 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009920 fast_elements_ = false;
9921 }
9922
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009923 inline void clear_storage() {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00009924 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009925 }
9926
9927 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 storage_ = Handle<FixedArray>::cast(
9929 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009930 }
9931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009932 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009933 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009934 // Index after last seen index. Always less than or equal to
9935 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009936 uint32_t index_offset_;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009937 bool fast_elements_ : 1;
9938 bool exceeds_array_limit_ : 1;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009939};
9940
9941
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942static uint32_t EstimateElementCount(Handle<JSArray> array) {
9943 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9944 int element_count = 0;
9945 switch (array->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009946 case FAST_SMI_ELEMENTS:
9947 case FAST_HOLEY_SMI_ELEMENTS:
9948 case FAST_ELEMENTS:
9949 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009950 // Fast elements can't have lengths that are not representable by
9951 // a 32-bit signed integer.
9952 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9953 int fast_length = static_cast<int>(length);
9954 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9955 for (int i = 0; i < fast_length; i++) {
9956 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009957 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009958 break;
9959 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009960 case FAST_DOUBLE_ELEMENTS:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009961 case FAST_HOLEY_DOUBLE_ELEMENTS: {
9962 // Fast elements can't have lengths that are not representable by
9963 // a 32-bit signed integer.
9964 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
9965 int fast_length = static_cast<int>(length);
9966 if (array->elements()->IsFixedArray()) {
9967 ASSERT(FixedArray::cast(array->elements())->length() == 0);
9968 break;
9969 }
9970 Handle<FixedDoubleArray> elements(
9971 FixedDoubleArray::cast(array->elements()));
9972 for (int i = 0; i < fast_length; i++) {
9973 if (!elements->is_the_hole(i)) element_count++;
9974 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009975 break;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009976 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009977 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009978 Handle<SeededNumberDictionary> dictionary(
9979 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 int capacity = dictionary->Capacity();
9981 for (int i = 0; i < capacity; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009982 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009983 if (dictionary->IsKey(*key)) {
9984 element_count++;
9985 }
9986 }
9987 break;
9988 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009989 case NON_STRICT_ARGUMENTS_ELEMENTS:
9990 case EXTERNAL_BYTE_ELEMENTS:
9991 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9992 case EXTERNAL_SHORT_ELEMENTS:
9993 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9994 case EXTERNAL_INT_ELEMENTS:
9995 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9996 case EXTERNAL_FLOAT_ELEMENTS:
9997 case EXTERNAL_DOUBLE_ELEMENTS:
9998 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 // External arrays are always dense.
10000 return length;
10001 }
10002 // As an estimate, we assume that the prototype doesn't contain any
10003 // inherited elements.
10004 return element_count;
10005}
10006
10007
10008
10009template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010static void IterateExternalArrayElements(Isolate* isolate,
10011 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 bool elements_are_ints,
10013 bool elements_are_guaranteed_smis,
10014 ArrayConcatVisitor* visitor) {
10015 Handle<ExternalArrayClass> array(
10016 ExternalArrayClass::cast(receiver->elements()));
10017 uint32_t len = static_cast<uint32_t>(array->length());
10018
10019 ASSERT(visitor != NULL);
10020 if (elements_are_ints) {
10021 if (elements_are_guaranteed_smis) {
10022 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010023 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010024 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
10025 isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010026 visitor->visit(j, e);
10027 }
10028 } else {
10029 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010030 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010031 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 if (Smi::IsValid(static_cast<intptr_t>(val))) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010033 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010034 visitor->visit(j, e);
10035 } else {
10036 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010038 visitor->visit(j, e);
10039 }
10040 }
10041 }
10042 } else {
10043 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010045 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010046 visitor->visit(j, e);
10047 }
10048 }
10049}
10050
10051
10052// Used for sorting indices in a List<uint32_t>.
10053static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
10054 uint32_t a = *ap;
10055 uint32_t b = *bp;
10056 return (a == b) ? 0 : (a < b) ? -1 : 1;
10057}
10058
10059
10060static void CollectElementIndices(Handle<JSObject> object,
10061 uint32_t range,
10062 List<uint32_t>* indices) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010063 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010064 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010065 switch (kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010066 case FAST_SMI_ELEMENTS:
10067 case FAST_ELEMENTS:
10068 case FAST_HOLEY_SMI_ELEMENTS:
10069 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010070 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
10071 uint32_t length = static_cast<uint32_t>(elements->length());
10072 if (range < length) length = range;
10073 for (uint32_t i = 0; i < length; i++) {
10074 if (!elements->get(i)->IsTheHole()) {
10075 indices->Add(i);
10076 }
10077 }
10078 break;
10079 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010080 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010081 case FAST_DOUBLE_ELEMENTS: {
10082 // TODO(1810): Decide if it's worthwhile to implement this.
10083 UNREACHABLE();
10084 break;
10085 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010086 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010087 Handle<SeededNumberDictionary> dict(
10088 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010089 uint32_t capacity = dict->Capacity();
10090 for (uint32_t j = 0; j < capacity; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010091 HandleScope loop_scope(isolate);
10092 Handle<Object> k(dict->KeyAt(j), isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010093 if (dict->IsKey(*k)) {
10094 ASSERT(k->IsNumber());
10095 uint32_t index = static_cast<uint32_t>(k->Number());
10096 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010097 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010098 }
10099 }
10100 }
10101 break;
10102 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010103 default: {
10104 int dense_elements_length;
10105 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010106 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010107 dense_elements_length =
10108 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010109 break;
10110 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010111 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010112 dense_elements_length =
10113 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010114 break;
10115 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010116 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010117 dense_elements_length =
10118 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010119 break;
10120 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010121 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010122 dense_elements_length =
10123 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010124 break;
10125 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010126 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010127 dense_elements_length =
10128 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010129 break;
10130 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010131 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010132 dense_elements_length =
10133 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010134 break;
10135 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010136 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010137 dense_elements_length =
10138 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010139 break;
10140 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010141 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010142 dense_elements_length =
10143 ExternalFloatArray::cast(object->elements())->length();
10144 break;
10145 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010146 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010147 dense_elements_length =
10148 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010149 break;
10150 }
10151 default:
10152 UNREACHABLE();
10153 dense_elements_length = 0;
10154 break;
10155 }
10156 uint32_t length = static_cast<uint32_t>(dense_elements_length);
10157 if (range <= length) {
10158 length = range;
10159 // We will add all indices, so we might as well clear it first
10160 // and avoid duplicates.
10161 indices->Clear();
10162 }
10163 for (uint32_t i = 0; i < length; i++) {
10164 indices->Add(i);
10165 }
10166 if (length == range) return; // All indices accounted for already.
10167 break;
10168 }
10169 }
10170
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010171 Handle<Object> prototype(object->GetPrototype(), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010172 if (prototype->IsJSObject()) {
10173 // The prototype will usually have no inherited element indices,
10174 // but we have to check.
10175 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
10176 }
10177}
10178
10179
10180/**
10181 * A helper function that visits elements of a JSArray in numerical
10182 * order.
10183 *
10184 * The visitor argument called for each existing element in the array
10185 * with the element index and the element's value.
10186 * Afterwards it increments the base-index of the visitor by the array
10187 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010188 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010189 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190static bool IterateElements(Isolate* isolate,
10191 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010192 ArrayConcatVisitor* visitor) {
10193 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10194 switch (receiver->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010195 case FAST_SMI_ELEMENTS:
10196 case FAST_ELEMENTS:
10197 case FAST_HOLEY_SMI_ELEMENTS:
10198 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010199 // Run through the elements FixedArray and use HasElement and GetElement
10200 // to check the prototype for missing elements.
10201 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10202 int fast_length = static_cast<int>(length);
10203 ASSERT(fast_length <= elements->length());
10204 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010205 HandleScope loop_scope(isolate);
10206 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010207 if (!element_value->IsTheHole()) {
10208 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010209 } else if (JSReceiver::HasElement(receiver, j)) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010210 // Call GetElement on receiver, not its prototype, or getters won't
10211 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010212 element_value = Object::GetElement(isolate, receiver, j);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010213 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010214 visitor->visit(j, element_value);
10215 }
10216 }
10217 break;
10218 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010219 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010220 case FAST_DOUBLE_ELEMENTS: {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010221 // Run through the elements FixedArray and use HasElement and GetElement
10222 // to check the prototype for missing elements.
10223 Handle<FixedDoubleArray> elements(
10224 FixedDoubleArray::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++) {
10228 HandleScope loop_scope(isolate);
10229 if (!elements->is_the_hole(j)) {
10230 double double_value = elements->get_scalar(j);
10231 Handle<Object> element_value =
10232 isolate->factory()->NewNumber(double_value);
10233 visitor->visit(j, element_value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010234 } else if (JSReceiver::HasElement(receiver, j)) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010235 // Call GetElement on receiver, not its prototype, or getters won't
10236 // have the correct receiver.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010237 Handle<Object> element_value =
10238 Object::GetElement(isolate, receiver, j);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010239 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
10240 visitor->visit(j, element_value);
10241 }
10242 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010243 break;
10244 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010245 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010246 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010247 List<uint32_t> indices(dict->Capacity() / 2);
10248 // Collect all indices in the object and the prototypes less
10249 // than length. This might introduce duplicates in the indices list.
10250 CollectElementIndices(receiver, length, &indices);
10251 indices.Sort(&compareUInt32);
10252 int j = 0;
10253 int n = indices.length();
10254 while (j < n) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010255 HandleScope loop_scope(isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010256 uint32_t index = indices[j];
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010257 Handle<Object> element = Object::GetElement(isolate, receiver, index);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010258 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010259 visitor->visit(index, element);
10260 // Skip to next different index (i.e., omit duplicates).
10261 do {
10262 j++;
10263 } while (j < n && indices[j] == index);
10264 }
10265 break;
10266 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010267 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010268 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10269 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010270 for (uint32_t j = 0; j < length; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010271 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010272 visitor->visit(j, e);
10273 }
10274 break;
10275 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010276 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010277 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010279 break;
10280 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010281 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010282 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010284 break;
10285 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010286 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010287 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010289 break;
10290 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010291 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010292 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010293 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010294 break;
10295 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010296 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010297 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010298 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010299 break;
10300 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010301 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010302 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010304 break;
10305 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010306 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010307 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010309 break;
10310 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010311 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010312 IterateExternalArrayElements<ExternalDoubleArray, double>(
10313 isolate, receiver, false, false, visitor);
10314 break;
10315 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010316 default:
10317 UNREACHABLE();
10318 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010319 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010320 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010321 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010322}
10323
10324
10325/**
10326 * Array::concat implementation.
10327 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010328 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010329 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010330 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010331RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 HandleScope handle_scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010333 ASSERT(args.length() == 1);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010334
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010335 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010336 int argument_count = static_cast<int>(arguments->length()->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010337 RUNTIME_ASSERT(arguments->HasFastObjectElements());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010338 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010339
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010340 // Pass 1: estimate the length and number of elements of the result.
10341 // The actual length can be larger if any of the arguments have getters
10342 // that mutate other arguments (but will otherwise be precise).
10343 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010344
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010345 ElementsKind kind = FAST_SMI_ELEMENTS;
10346
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010347 uint32_t estimate_result_length = 0;
10348 uint32_t estimate_nof_elements = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010349 for (int i = 0; i < argument_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000010350 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010351 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010352 uint32_t length_estimate;
10353 uint32_t element_estimate;
10354 if (obj->IsJSArray()) {
10355 Handle<JSArray> array(Handle<JSArray>::cast(obj));
10356 length_estimate = static_cast<uint32_t>(array->length()->Number());
10357 if (length_estimate != 0) {
10358 ElementsKind array_kind =
10359 GetPackedElementsKind(array->map()->elements_kind());
10360 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
10361 kind = array_kind;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010362 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010363 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010364 element_estimate = EstimateElementCount(array);
10365 } else {
10366 if (obj->IsHeapObject()) {
10367 if (obj->IsNumber()) {
10368 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
10369 kind = FAST_DOUBLE_ELEMENTS;
10370 }
10371 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
10372 kind = FAST_ELEMENTS;
10373 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010374 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010375 length_estimate = 1;
10376 element_estimate = 1;
10377 }
10378 // Avoid overflows by capping at kMaxElementCount.
10379 if (JSObject::kMaxElementCount - estimate_result_length <
10380 length_estimate) {
10381 estimate_result_length = JSObject::kMaxElementCount;
10382 } else {
10383 estimate_result_length += length_estimate;
10384 }
10385 if (JSObject::kMaxElementCount - estimate_nof_elements <
10386 element_estimate) {
10387 estimate_nof_elements = JSObject::kMaxElementCount;
10388 } else {
10389 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010390 }
10391 }
10392
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010393 // If estimated number of elements is more than half of length, a
10394 // fixed array (fast case) is more time and space-efficient than a
10395 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010396 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010397
10398 Handle<FixedArray> storage;
10399 if (fast_case) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010400 if (kind == FAST_DOUBLE_ELEMENTS) {
10401 Handle<FixedDoubleArray> double_storage =
10402 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
10403 int j = 0;
10404 bool failure = false;
10405 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010406 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010407 if (obj->IsSmi()) {
10408 double_storage->set(j, Smi::cast(*obj)->value());
10409 j++;
10410 } else if (obj->IsNumber()) {
10411 double_storage->set(j, obj->Number());
10412 j++;
10413 } else {
10414 JSArray* array = JSArray::cast(*obj);
10415 uint32_t length = static_cast<uint32_t>(array->length()->Number());
10416 switch (array->map()->elements_kind()) {
10417 case FAST_HOLEY_DOUBLE_ELEMENTS:
10418 case FAST_DOUBLE_ELEMENTS: {
10419 // Empty fixed array indicates that there are no elements.
10420 if (array->elements()->IsFixedArray()) break;
10421 FixedDoubleArray* elements =
10422 FixedDoubleArray::cast(array->elements());
10423 for (uint32_t i = 0; i < length; i++) {
10424 if (elements->is_the_hole(i)) {
10425 failure = true;
10426 break;
10427 }
10428 double double_value = elements->get_scalar(i);
10429 double_storage->set(j, double_value);
10430 j++;
10431 }
10432 break;
10433 }
10434 case FAST_HOLEY_SMI_ELEMENTS:
10435 case FAST_SMI_ELEMENTS: {
10436 FixedArray* elements(
10437 FixedArray::cast(array->elements()));
10438 for (uint32_t i = 0; i < length; i++) {
10439 Object* element = elements->get(i);
10440 if (element->IsTheHole()) {
10441 failure = true;
10442 break;
10443 }
10444 int32_t int_value = Smi::cast(element)->value();
10445 double_storage->set(j, int_value);
10446 j++;
10447 }
10448 break;
10449 }
10450 case FAST_HOLEY_ELEMENTS:
10451 ASSERT_EQ(0, length);
10452 break;
10453 default:
10454 UNREACHABLE();
10455 }
10456 }
10457 if (failure) break;
10458 }
10459 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
10460 Smi* length = Smi::FromInt(j);
10461 Handle<Map> map;
10462 map = isolate->factory()->GetElementsTransitionMap(array, kind);
10463 array->set_map(*map);
10464 array->set_length(length);
10465 array->set_elements(*double_storage);
10466 return *array;
10467 }
10468 // The backing storage array must have non-existing elements to preserve
10469 // holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 storage = isolate->factory()->NewFixedArrayWithHoles(
10471 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010472 } else {
10473 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10474 uint32_t at_least_space_for = estimate_nof_elements +
10475 (estimate_nof_elements >> 2);
10476 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010477 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010478 }
10479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010481
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010482 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010483 Handle<Object> obj(elements->get(i), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010484 if (obj->IsJSArray()) {
10485 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010487 return Failure::Exception();
10488 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010489 } else {
10490 visitor.visit(0, obj);
10491 visitor.increase_index_offset(1);
10492 }
10493 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010494
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000010495 if (visitor.exceeds_array_limit()) {
10496 return isolate->Throw(
10497 *isolate->factory()->NewRangeError("invalid_array_length",
10498 HandleVector<Object>(NULL, 0)));
10499 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010500 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010501}
10502
10503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010504// This will not allocate (flatten the string), but it may run
10505// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010506RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010507 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 ASSERT(args.length() == 1);
10509
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010510 CONVERT_ARG_CHECKED(String, string, 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010511 ConsStringIteratorOp op;
10512 StringCharacterStream stream(string, &op);
10513 while (stream.HasMore()) {
10514 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515 PrintF("%c", character);
10516 }
10517 return string;
10518}
10519
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010520
ager@chromium.org5ec48922009-05-05 07:25:34 +000010521// Moves all own elements of an object, that are below a limit, to positions
10522// starting at zero. All undefined values are placed after non-undefined values,
10523// and are followed by non-existing element. Does not change the length
10524// property.
10525// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010526RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010527 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010528 ASSERT(args.length() == 2);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010529 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010530 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000010531 return *JSObject::PrepareElementsForSort(object, limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532}
10533
10534
10535// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010536RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010537 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010539 CONVERT_ARG_CHECKED(JSArray, from, 0);
10540 CONVERT_ARG_CHECKED(JSArray, to, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010541 from->ValidateElements();
10542 to->ValidateElements();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010543 FixedArrayBase* new_elements = from->elements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010544 ElementsKind from_kind = from->GetElementsKind();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010545 MaybeObject* maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010546 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010547 Object* new_map;
10548 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010549 to->set_map_and_elements(Map::cast(new_map), new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010551 Object* obj;
10552 { MaybeObject* maybe_obj = from->ResetElements();
10553 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10554 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010555 from->set_length(Smi::FromInt(0));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010556 to->ValidateElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 return to;
10558}
10559
10560
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010561// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010562RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010563 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010565 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010566 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010568 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10569 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010570 } else if (object->IsJSArray()) {
10571 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010573 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 }
10575}
10576
10577
10578// Returns an array that tells you where in the [0, length) interval an array
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010579// might have elements. Can either return an array of keys (positive integers
10580// or undefined) or a number representing the positive length of an interval
10581// starting at index 0.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010582// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010583RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010585 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010586 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010588 if (array->elements()->IsDictionary()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010589 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
10590 for (Handle<Object> p = array;
10591 !p->IsNull();
10592 p = Handle<Object>(p->GetPrototype(isolate), isolate)) {
10593 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) {
10594 // Bail out if we find a proxy or interceptor, likely not worth
10595 // collecting keys in that case.
10596 return *isolate->factory()->NewNumberFromUint(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010598 Handle<JSObject> current = Handle<JSObject>::cast(p);
10599 Handle<FixedArray> current_keys =
10600 isolate->factory()->NewFixedArray(
10601 current->NumberOfLocalElements(NONE));
10602 current->GetLocalElementKeys(*current_keys, NONE);
10603 keys = UnionOfKeys(keys, current_keys);
10604 }
10605 // Erase any keys >= length.
10606 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
10607 // is changed to let this happen on the JS side.
10608 for (int i = 0; i < keys->length(); i++) {
10609 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010611 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010613 ASSERT(array->HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010614 array->HasFastDoubleElements());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010615 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
10616 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617 }
10618}
10619
10620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010621RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010622 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 ASSERT(args.length() == 3);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010624 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
10625 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010626 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010627 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000010628 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000010629 Handle<Object> result =
10630 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component);
10631 RETURN_IF_EMPTY_HANDLE(isolate, result);
10632 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633}
10634
10635
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010636#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010637RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010638 SealHandleScope shs(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010639 ASSERT(args.length() == 0);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000010640 return Execution::DebugBreakHelper(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010641}
10642
10643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644// Helper functions for wrapping and unwrapping stack frame ids.
10645static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010646 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647 return Smi::FromInt(id >> 2);
10648}
10649
10650
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010651static StackFrame::Id UnwrapFrameId(int wrapped) {
10652 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653}
10654
10655
10656// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010657// args[0]: debug event listener function to set or null or undefined for
10658// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010660RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010661 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010662 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010663 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10664 args[0]->IsUndefined() ||
10665 args[0]->IsNull());
10666 Handle<Object> callback = args.at<Object>(0);
10667 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010668 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671}
10672
10673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010674RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010675 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010676 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010677 isolate->stack_guard()->DebugBreak();
10678 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679}
10680
10681
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682static MaybeObject* DebugLookupResultValue(Heap* heap,
10683 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000010684 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685 LookupResult* result,
10686 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010687 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010688 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010689 case NORMAL:
10690 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010691 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010692 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693 }
10694 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010695 case FIELD: {
10696 Object* value;
10697 MaybeObject* maybe_value =
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010698 JSObject::cast(result->holder())->FastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010699 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000010700 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010701 if (!maybe_value->To(&value)) return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010702 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010703 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010704 }
10705 return value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010706 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000010707 case CONSTANT:
10708 return result->GetConstant();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010709 case CALLBACKS: {
10710 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010711 if (structure->IsForeign() || structure->IsAccessorInfo()) {
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010712 Isolate* isolate = heap->isolate();
10713 HandleScope scope(isolate);
10714 Handle<Object> value = JSObject::GetPropertyWithCallback(
10715 handle(result->holder(), isolate),
10716 handle(receiver, isolate),
10717 handle(structure, isolate),
10718 handle(name, isolate));
10719 if (value.is_null()) {
10720 MaybeObject* exception = heap->isolate()->pending_exception();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010721 heap->isolate()->clear_pending_exception();
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010722 if (caught_exception != NULL) *caught_exception = true;
10723 return exception;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010724 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +000010725 return *value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010726 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010728 }
10729 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730 case INTERCEPTOR:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010731 case TRANSITION:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010733 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010734 case NONEXISTENT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010736 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010737 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010738 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010739 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740}
10741
10742
ager@chromium.org32912102009-01-16 10:38:43 +000010743// Get debugger related details for an object property.
10744// args[0]: object holding property
10745// args[1]: name of the property
10746//
10747// The array returned contains the following information:
10748// 0: Property value
10749// 1: Property details
10750// 2: Property value is exception
10751// 3: Getter function if defined
10752// 4: Setter function if defined
10753// Items 2-4 are only filled if the property has either a getter or a setter
10754// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010755RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010756 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757
10758 ASSERT(args.length() == 2);
10759
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010760 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010761 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010763 // Make sure to set the current context to the context before the debugger was
10764 // entered (if the debugger is entered). The reason for switching context here
10765 // is that for some property lookups (accessors and interceptors) callbacks
10766 // into the embedding application can occour, and the embedding application
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010767 // could have the assumption that its own native context is the current
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010768 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 SaveContext save(isolate);
10770 if (isolate->debug()->InDebugger()) {
10771 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010772 }
10773
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010774 // Skip the global proxy as it has no properties and always delegates to the
10775 // real global object.
10776 if (obj->IsJSGlobalProxy()) {
10777 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10778 }
10779
10780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781 // Check if the name is trivially convertible to an index and get the element
10782 // if so.
10783 uint32_t index;
10784 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010786 Object* element_or_char;
10787 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010789 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10790 return maybe_element_or_char;
10791 }
10792 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010793 details->set(0, element_or_char);
danno@chromium.orgf005df62013-04-30 16:36:45 +000010794 details->set(
10795 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797 }
10798
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010799 // Find the number of objects making up this.
10800 int length = LocalPrototypeChainLength(*obj);
10801
10802 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010803 Handle<JSObject> jsproto = obj;
10804 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010805 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010806 jsproto->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010807 if (result.IsFound()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010808 // LookupResult is not GC safe as it holds raw object pointers.
10809 // GC can happen later in this code so put the required fields into
10810 // local variables using handles when required for later use.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010811 Handle<Object> result_callback_obj;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010812 if (result.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10814 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010815 }
10816 Smi* property_details = result.GetPropertyDetails().AsSmi();
10817 // DebugLookupResultValue can cause GC so details from LookupResult needs
10818 // to be copied to handles before this.
10819 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010820 Object* raw_value;
10821 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822 DebugLookupResultValue(isolate->heap(), *obj, *name,
10823 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010824 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10825 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010827
10828 // If the callback object is a fixed array then it contains JavaScript
10829 // getter and/or setter.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010830 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010831 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010832 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010833 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010834 details->set(0, *value);
10835 details->set(1, property_details);
10836 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010837 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010838 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010839 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10840 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010841 }
10842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010844 }
10845 if (i < length - 1) {
10846 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10847 }
10848 }
10849
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851}
10852
10853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010854RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
10857 ASSERT(args.length() == 2);
10858
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010859 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +000010860 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010862 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863 obj->Lookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010864 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010867 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868}
10869
10870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871// Return the property type calculated from the property details.
10872// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010873RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010874 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010876 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10877 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878}
10879
10880
10881// Return the property attribute calculated from the property details.
10882// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010883RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010884 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010886 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10887 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888}
10889
10890
10891// Return the property insertion index calculated from the property details.
10892// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010893RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010894 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010896 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010897 // TODO(verwaest): Depends on the type of details.
10898 return Smi::FromInt(details.dictionary_index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899}
10900
10901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902// Return property value from named interceptor.
10903// args[0]: object
10904// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010905RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010906 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010908 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909 RUNTIME_ASSERT(obj->HasNamedInterceptor());
ulan@chromium.org750145a2013-03-07 15:14:13 +000010910 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010911
10912 PropertyAttributes attributes;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000010913 Handle<Object> result =
10914 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes);
10915 RETURN_IF_EMPTY_HANDLE(isolate, result);
10916 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917}
10918
10919
10920// Return element value from indexed interceptor.
10921// args[0]: object
10922// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010923RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010926 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10928 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10929
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010930 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931}
10932
10933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010934RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010935 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 ASSERT(args.length() >= 1);
10937 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010938 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010939 if (isolate->debug()->break_id() == 0 ||
10940 break_id != isolate->debug()->break_id()) {
10941 return isolate->Throw(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010942 isolate->heap()->illegal_execution_state_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 }
10944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946}
10947
10948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010949RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 ASSERT(args.length() == 1);
10952
10953 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010954 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010955 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10956 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010957 if (!maybe_result->ToObject(&result)) return maybe_result;
10958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959
10960 // Count all frames which are relevant to debugging stack trace.
10961 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010963 if (id == StackFrame::NO_ID) {
10964 // If there is no JavaScript stack frame count is 0.
10965 return Smi::FromInt(0);
10966 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010967
10968 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10969 n += it.frame()->GetInlineCount();
10970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971 return Smi::FromInt(n);
10972}
10973
10974
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010975class FrameInspector {
10976 public:
10977 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010978 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010979 Isolate* isolate)
10980 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10981 // Calculate the deoptimized frame.
10982 if (frame->is_optimized()) {
10983 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010984 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010985 }
10986 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010987 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010988 is_optimized_ = frame_->is_optimized();
10989 }
10990
10991 ~FrameInspector() {
10992 // Get rid of the calculated deoptimized frame if any.
10993 if (deoptimized_frame_ != NULL) {
10994 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10995 isolate_);
10996 }
10997 }
10998
10999 int GetParametersCount() {
11000 return is_optimized_
11001 ? deoptimized_frame_->parameters_count()
11002 : frame_->ComputeParametersCount();
11003 }
11004 int expression_count() { return deoptimized_frame_->expression_count(); }
11005 Object* GetFunction() {
11006 return is_optimized_
11007 ? deoptimized_frame_->GetFunction()
11008 : frame_->function();
11009 }
11010 Object* GetParameter(int index) {
11011 return is_optimized_
11012 ? deoptimized_frame_->GetParameter(index)
11013 : frame_->GetParameter(index);
11014 }
11015 Object* GetExpression(int index) {
11016 return is_optimized_
11017 ? deoptimized_frame_->GetExpression(index)
11018 : frame_->GetExpression(index);
11019 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011020 int GetSourcePosition() {
11021 return is_optimized_
11022 ? deoptimized_frame_->GetSourcePosition()
11023 : frame_->LookupCode()->SourcePosition(frame_->pc());
11024 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000011025 bool IsConstructor() {
11026 return is_optimized_ && !is_bottommost_
11027 ? deoptimized_frame_->HasConstructStub()
11028 : frame_->IsConstructor();
11029 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011030
11031 // To inspect all the provided arguments the frame might need to be
11032 // replaced with the arguments frame.
11033 void SetArgumentsFrame(JavaScriptFrame* frame) {
11034 ASSERT(has_adapted_arguments_);
11035 frame_ = frame;
11036 is_optimized_ = frame_->is_optimized();
11037 ASSERT(!is_optimized_);
11038 }
11039
11040 private:
11041 JavaScriptFrame* frame_;
11042 DeoptimizedFrameInfo* deoptimized_frame_;
11043 Isolate* isolate_;
11044 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000011045 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011046 bool has_adapted_arguments_;
11047
11048 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
11049};
11050
11051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011052static const int kFrameDetailsFrameIdIndex = 0;
11053static const int kFrameDetailsReceiverIndex = 1;
11054static const int kFrameDetailsFunctionIndex = 2;
11055static const int kFrameDetailsArgumentCountIndex = 3;
11056static const int kFrameDetailsLocalCountIndex = 4;
11057static const int kFrameDetailsSourcePositionIndex = 5;
11058static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011059static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011060static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011061static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011063
11064static SaveContext* FindSavedContextForFrame(Isolate* isolate,
11065 JavaScriptFrame* frame) {
11066 SaveContext* save = isolate->save_context();
11067 while (save != NULL && !save->IsBelowFrame(frame)) {
11068 save = save->prev();
11069 }
11070 ASSERT(save != NULL);
11071 return save;
11072}
11073
11074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011075// Return an array with frame details
11076// args[0]: number: break id
11077// args[1]: number: frame index
11078//
11079// The array returned contains the following information:
11080// 0: Frame id
11081// 1: Receiver
11082// 2: Function
11083// 3: Argument count
11084// 4: Local count
11085// 5: Source position
11086// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011087// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011088// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011089// Arguments name, value
11090// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011091// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011092RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011094 ASSERT(args.length() == 2);
11095
11096 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011097 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011098 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11099 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011100 if (!maybe_check->ToObject(&check)) return maybe_check;
11101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011102 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104
11105 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011107 if (id == StackFrame::NO_ID) {
11108 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011109 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000011110 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011113 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011115 if (index < count + it.frame()->GetInlineCount()) break;
11116 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011120 bool is_optimized = it.frame()->is_optimized();
11121
11122 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
11123 if (is_optimized) {
11124 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011125 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011126 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011127 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 // Traverse the saved contexts chain to find the active context for the
11130 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011131 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132
11133 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011134 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011135
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011136 // Find source position in unoptimized code.
11137 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138
ulan@chromium.org967e2702012-02-28 09:49:15 +000011139 // Check for constructor frame.
11140 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011142 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011143 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011144 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011145 Handle<ScopeInfo> scope_info(shared->scope_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011146 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011148 // Get the locals names and values into a temporary array.
11149 //
11150 // TODO(1240907): Hide compiler-introduced stack variables
11151 // (e.g. .result)? For users of the debugger, they will probably be
11152 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011153 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011154 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011156 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011157 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011158 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011159 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011160 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011161 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011162 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011163 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011164 // Get the context containing declarations.
11165 Handle<Context> context(
11166 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011167 for (; i < scope_info->LocalCount(); ++i) {
11168 Handle<String> name(scope_info->LocalName(i));
11169 VariableMode mode;
11170 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011171 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011172 locals->set(i * 2 + 1, context->get(
11173 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011174 }
11175 }
11176
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011177 // Check whether this frame is positioned at return. If not top
11178 // frame or if the frame is optimized it cannot be at a return.
11179 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011180 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011181 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011182 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011183
11184 // If positioned just before return find the value to be returned and add it
11185 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011186 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011187 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011188 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011189 Address internal_frame_sp = NULL;
11190 while (!it2.done()) {
11191 if (it2.frame()->is_internal()) {
11192 internal_frame_sp = it2.frame()->sp();
11193 } else {
11194 if (it2.frame()->is_java_script()) {
11195 if (it2.frame()->id() == it.frame()->id()) {
11196 // The internal frame just before the JavaScript frame contains the
11197 // value to return on top. A debug break at return will create an
11198 // internal frame to store the return value (eax/rax/r0) before
11199 // entering the debug break exit frame.
11200 if (internal_frame_sp != NULL) {
11201 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 Handle<Object>(Memory::Object_at(internal_frame_sp),
11203 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011204 break;
11205 }
11206 }
11207 }
11208
11209 // Indicate that the previous frame was not an internal frame.
11210 internal_frame_sp = NULL;
11211 }
11212 it2.Advance();
11213 }
11214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215
11216 // Now advance to the arguments adapter frame (if any). It contains all
11217 // the provided parameters whereas the function frame always have the number
11218 // of arguments matching the functions parameters. The rest of the
11219 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011220 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011221 it.AdvanceToArgumentsFrame();
11222 frame_inspector.SetArgumentsFrame(it.frame());
11223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011224
11225 // Find the number of arguments to fill. At least fill the number of
11226 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011227 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011228 if (argument_count < frame_inspector.GetParametersCount()) {
11229 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011230 }
11231
11232 // Calculate the size of the result.
11233 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011234 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011235 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011236 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011237
11238 // Add the frame id.
11239 details->set(kFrameDetailsFrameIdIndex, *frame_id);
11240
11241 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011242 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243
11244 // Add the arguments count.
11245 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
11246
11247 // Add the locals count
11248 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011249 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011250
11251 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000011252 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
11254 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011255 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256 }
11257
11258 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011259 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011261 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011262 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011263
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011264 // Add flags to indicate information on whether this frame is
11265 // bit 0: invoked in the debugger context.
11266 // bit 1: optimized frame.
11267 // bit 2: inlined in optimized frame
11268 int flags = 0;
11269 if (*save->context() == *isolate->debug()->debug_context()) {
11270 flags |= 1 << 0;
11271 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011272 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011273 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011274 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011275 }
11276 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277
11278 // Fill the dynamic part.
11279 int details_index = kFrameDetailsFirstDynamicIndex;
11280
11281 // Add arguments name and value.
11282 for (int i = 0; i < argument_count; i++) {
11283 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011284 if (i < scope_info->ParameterCount()) {
11285 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011286 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011288 }
11289
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011290 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011291 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011292 // Get the value from the stack.
11293 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011294 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011295 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011296 }
11297 }
11298
11299 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011300 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301 details->set(details_index++, locals->get(i));
11302 }
11303
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011304 // Add the value being returned.
11305 if (at_return) {
11306 details->set(details_index++, *return_value);
11307 }
11308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011309 // Add the receiver (same as in function frame).
11310 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11311 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011313 if (!receiver->IsJSObject() &&
11314 shared->is_classic_mode() &&
danno@chromium.orgbee51992013-07-10 14:57:15 +000011315 !function->IsBuiltin()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011316 // If the receiver is not a JSObject and the function is not a
11317 // builtin or strict-mode we have hit an optimization where a
11318 // value object is not converted into a wrapped JS objects. To
11319 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011320 // by creating correct wrapper object based on the calling frame's
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011321 // native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011322 it.Advance();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011323 Handle<Context> calling_frames_native_context(
11324 Context::cast(Context::cast(it.frame()->context())->native_context()));
danno@chromium.orgbee51992013-07-10 14:57:15 +000011325 ASSERT(!receiver->IsUndefined() && !receiver->IsNull());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 receiver =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011327 isolate->factory()->ToObject(receiver, calling_frames_native_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011328 }
11329 details->set(kFrameDetailsReceiverIndex, *receiver);
11330
11331 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333}
11334
11335
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011336// Create a plain JSObject which materializes the local scope for the specified
11337// frame.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011338static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011339 Isolate* isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011340 Handle<JSObject> target,
11341 Handle<JSFunction> function,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011342 FrameInspector* frame_inspector) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011343 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011344 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011345
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011346 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011347 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000011348 Handle<String> name(scope_info->ParameterName(i));
11349 VariableMode mode;
11350 InitializationFlag init_flag;
11351 // Do not materialize the parameter if it is shadowed by a context local.
11352 if (scope_info->ContextSlotIndex(*name, &mode, &init_flag) != -1) continue;
11353
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011354 Handle<Object> value(i < frame_inspector->GetParametersCount()
11355 ? frame_inspector->GetParameter(i)
11356 : isolate->heap()->undefined_value(),
11357 isolate);
danno@chromium.org59400602013-08-13 17:09:37 +000011358 ASSERT(!value->IsTheHole());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011359
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011360 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011361 isolate,
yangguo@chromium.org49546742013-12-23 16:17:49 +000011362 Runtime::SetObjectProperty(
11363 isolate, target, name, value, NONE, kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011364 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011365 }
11366
11367 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011368 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000011369 Handle<String> name(scope_info->StackLocalName(i));
danno@chromium.org59400602013-08-13 17:09:37 +000011370 Handle<Object> value(frame_inspector->GetExpression(i), isolate);
11371 if (value->IsTheHole()) continue;
11372
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011373 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011374 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011375 Runtime::SetObjectProperty(
yangguo@chromium.org49546742013-12-23 16:17:49 +000011376 isolate, target, name, value, NONE, kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011377 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011378 }
11379
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011380 return target;
11381}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011382
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011383
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011384static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
11385 Handle<JSObject> target,
11386 Handle<JSFunction> function,
11387 JavaScriptFrame* frame,
11388 int inlined_jsframe_index) {
11389 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11390 // Optimized frames are not supported.
11391 // TODO(yangguo): make sure all code deoptimized when debugger is active
11392 // and assert that this cannot happen.
11393 return;
11394 }
11395
11396 Handle<SharedFunctionInfo> shared(function->shared());
11397 Handle<ScopeInfo> scope_info(shared->scope_info());
11398
11399 // Parameters.
11400 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011401 ASSERT(!frame->GetParameter(i)->IsTheHole());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011402 HandleScope scope(isolate);
11403 Handle<Object> value = GetProperty(
11404 isolate, target, Handle<String>(scope_info->ParameterName(i)));
11405 frame->SetParameterValue(i, *value);
11406 }
11407
11408 // Stack locals.
11409 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
danno@chromium.org59400602013-08-13 17:09:37 +000011410 if (frame->GetExpression(i)->IsTheHole()) continue;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011411 HandleScope scope(isolate);
11412 Handle<Object> value = GetProperty(
11413 isolate, target, Handle<String>(scope_info->StackLocalName(i)));
11414 frame->SetExpression(i, *value);
11415 }
11416}
11417
11418
11419static Handle<JSObject> MaterializeLocalContext(Isolate* isolate,
11420 Handle<JSObject> target,
11421 Handle<JSFunction> function,
11422 JavaScriptFrame* frame) {
11423 HandleScope scope(isolate);
11424 Handle<SharedFunctionInfo> shared(function->shared());
11425 Handle<ScopeInfo> scope_info(shared->scope_info());
11426
11427 if (!scope_info->HasContext()) return target;
11428
11429 // Third fill all context locals.
11430 Handle<Context> frame_context(Context::cast(frame->context()));
11431 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011432 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11433 scope_info, function_context, target)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011434 return Handle<JSObject>();
11435 }
11436
11437 // Finally copy any properties from the function context extension.
11438 // These will be variables introduced by eval.
11439 if (function_context->closure() == *function) {
11440 if (function_context->has_extension() &&
11441 !function_context->IsNativeContext()) {
11442 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11443 bool threw = false;
11444 Handle<FixedArray> keys =
11445 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11446 if (threw) return Handle<JSObject>();
11447
11448 for (int i = 0; i < keys->length(); i++) {
11449 // Names of variables introduced by eval are strings.
11450 ASSERT(keys->get(i)->IsString());
11451 Handle<String> key(String::cast(keys->get(i)));
11452 RETURN_IF_EMPTY_HANDLE_VALUE(
11453 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011454 Runtime::SetObjectProperty(isolate,
11455 target,
11456 key,
11457 GetProperty(isolate, ext, key),
11458 NONE,
11459 kNonStrictMode),
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011460 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011461 }
11462 }
11463 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011464
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011465 return target;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011466}
11467
11468
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011469static Handle<JSObject> MaterializeLocalScope(
11470 Isolate* isolate,
11471 JavaScriptFrame* frame,
11472 int inlined_jsframe_index) {
11473 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000011474 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11475
11476 Handle<JSObject> local_scope =
11477 isolate->factory()->NewJSObject(isolate->object_function());
11478 local_scope = MaterializeStackLocalsWithFrameInspector(
11479 isolate, local_scope, function, &frame_inspector);
11480 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
11481
11482 return MaterializeLocalContext(isolate, local_scope, function, frame);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011483}
11484
11485
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011486// Set the context local variable value.
11487static bool SetContextLocalValue(Isolate* isolate,
11488 Handle<ScopeInfo> scope_info,
11489 Handle<Context> context,
11490 Handle<String> variable_name,
11491 Handle<Object> new_value) {
11492 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11493 Handle<String> next_name(scope_info->ContextLocalName(i));
11494 if (variable_name->Equals(*next_name)) {
11495 VariableMode mode;
11496 InitializationFlag init_flag;
11497 int context_index =
11498 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
11499 context->set(context_index, *new_value);
11500 return true;
11501 }
11502 }
11503
11504 return false;
11505}
11506
11507
11508static bool SetLocalVariableValue(Isolate* isolate,
11509 JavaScriptFrame* frame,
11510 int inlined_jsframe_index,
11511 Handle<String> variable_name,
11512 Handle<Object> new_value) {
11513 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
11514 // Optimized frames are not supported.
11515 return false;
11516 }
11517
danno@chromium.org169691d2013-07-15 08:01:13 +000011518 Handle<JSFunction> function(frame->function());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011519 Handle<SharedFunctionInfo> shared(function->shared());
11520 Handle<ScopeInfo> scope_info(shared->scope_info());
11521
11522 bool default_result = false;
11523
11524 // Parameters.
11525 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
11526 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
11527 frame->SetParameterValue(i, *new_value);
11528 // Argument might be shadowed in heap context, don't stop here.
11529 default_result = true;
11530 }
11531 }
11532
11533 // Stack locals.
11534 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
11535 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
11536 frame->SetExpression(i, *new_value);
11537 return true;
11538 }
11539 }
11540
11541 if (scope_info->HasContext()) {
11542 // Context locals.
11543 Handle<Context> frame_context(Context::cast(frame->context()));
11544 Handle<Context> function_context(frame_context->declaration_context());
11545 if (SetContextLocalValue(
11546 isolate, scope_info, function_context, variable_name, new_value)) {
11547 return true;
11548 }
11549
11550 // Function context extension. These are variables introduced by eval.
11551 if (function_context->closure() == *function) {
11552 if (function_context->has_extension() &&
11553 !function_context->IsNativeContext()) {
11554 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
11555
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011556 if (JSReceiver::HasProperty(ext, variable_name)) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011557 // We don't expect this to do anything except replacing
11558 // property value.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011559 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11560 NONE,
11561 kNonStrictMode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011562 return true;
11563 }
11564 }
11565 }
11566 }
11567
11568 return default_result;
11569}
11570
11571
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011572// Create a plain JSObject which materializes the closure content for the
11573// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11575 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011576 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011577
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011578 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011579 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011580
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011581 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011582 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 Handle<JSObject> closure_scope =
11584 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011585
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011586 // Fill all context locals to the context extension.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011587 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11588 scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011589 return Handle<JSObject>();
11590 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591
11592 // Finally copy any properties from the function context extension. This will
11593 // be variables introduced by eval.
11594 if (context->has_extension()) {
11595 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011596 bool threw = false;
11597 Handle<FixedArray> keys =
11598 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11599 if (threw) return Handle<JSObject>();
11600
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011601 for (int i = 0; i < keys->length(); i++) {
11602 // Names of variables introduced by eval are strings.
11603 ASSERT(keys->get(i)->IsString());
11604 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 RETURN_IF_EMPTY_HANDLE_VALUE(
11606 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011607 Runtime::SetObjectProperty(isolate, closure_scope, key,
11608 GetProperty(isolate, ext, key),
11609 NONE,
11610 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011611 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011612 }
11613 }
11614
11615 return closure_scope;
11616}
11617
11618
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011619// This method copies structure of MaterializeClosure method above.
11620static bool SetClosureVariableValue(Isolate* isolate,
11621 Handle<Context> context,
11622 Handle<String> variable_name,
11623 Handle<Object> new_value) {
11624 ASSERT(context->IsFunctionContext());
11625
11626 Handle<SharedFunctionInfo> shared(context->closure()->shared());
11627 Handle<ScopeInfo> scope_info(shared->scope_info());
11628
11629 // Context locals to the context extension.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011630 if (SetContextLocalValue(
11631 isolate, scope_info, context, variable_name, new_value)) {
11632 return true;
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011633 }
11634
11635 // Properties from the function context extension. This will
11636 // be variables introduced by eval.
11637 if (context->has_extension()) {
11638 Handle<JSObject> ext(JSObject::cast(context->extension()));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011639 if (JSReceiver::HasProperty(ext, variable_name)) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011640 // We don't expect this to do anything except replacing property value.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011641 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
11642 NONE,
11643 kNonStrictMode);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011644 return true;
11645 }
11646 }
11647
11648 return false;
11649}
11650
11651
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011652// Create a plain JSObject which materializes the scope for the specified
11653// catch context.
11654static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11655 Handle<Context> context) {
11656 ASSERT(context->IsCatchContext());
11657 Handle<String> name(String::cast(context->extension()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011658 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
11659 isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011660 Handle<JSObject> catch_scope =
11661 isolate->factory()->NewJSObject(isolate->object_function());
11662 RETURN_IF_EMPTY_HANDLE_VALUE(
11663 isolate,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011664 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object,
11665 NONE,
11666 kNonStrictMode),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011667 Handle<JSObject>());
11668 return catch_scope;
11669}
11670
11671
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011672static bool SetCatchVariableValue(Isolate* isolate,
11673 Handle<Context> context,
11674 Handle<String> variable_name,
11675 Handle<Object> new_value) {
11676 ASSERT(context->IsCatchContext());
11677 Handle<String> name(String::cast(context->extension()));
11678 if (!name->Equals(*variable_name)) {
11679 return false;
11680 }
11681 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
11682 return true;
11683}
11684
11685
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011686// Create a plain JSObject which materializes the block scope for the specified
11687// block context.
11688static Handle<JSObject> MaterializeBlockScope(
11689 Isolate* isolate,
11690 Handle<Context> context) {
11691 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011692 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011693
11694 // Allocate and initialize a JSObject with all the arguments, stack locals
11695 // heap locals and extension properties of the debugged function.
11696 Handle<JSObject> block_scope =
11697 isolate->factory()->NewJSObject(isolate->object_function());
11698
11699 // Fill all context locals.
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +000011700 if (!ScopeInfo::CopyContextLocalsToScopeObject(
11701 scope_info, context, block_scope)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011702 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011703 }
11704
11705 return block_scope;
11706}
11707
11708
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011709// Create a plain JSObject which materializes the module scope for the specified
11710// module context.
11711static Handle<JSObject> MaterializeModuleScope(
11712 Isolate* isolate,
11713 Handle<Context> context) {
11714 ASSERT(context->IsModuleContext());
11715 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11716
11717 // Allocate and initialize a JSObject with all the members of the debugged
11718 // module.
11719 Handle<JSObject> module_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, module_scope)) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011725 return Handle<JSObject>();
11726 }
11727
11728 return module_scope;
11729}
11730
11731
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011732// Iterate over the actual scopes visible from a stack frame or from a closure.
11733// The iteration proceeds from the innermost visible nested scope outwards.
11734// All scopes are backed by an actual context except the local scope,
11735// which is inserted "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011736class ScopeIterator {
11737 public:
11738 enum ScopeType {
11739 ScopeTypeGlobal = 0,
11740 ScopeTypeLocal,
11741 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011742 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011743 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011744 ScopeTypeBlock,
11745 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011746 };
11747
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011748 ScopeIterator(Isolate* isolate,
11749 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011750 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751 : isolate_(isolate),
11752 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011753 inlined_jsframe_index_(inlined_jsframe_index),
danno@chromium.org169691d2013-07-15 08:01:13 +000011754 function_(frame->function()),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011755 context_(Context::cast(frame->context())),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011756 nested_scope_chain_(4),
11757 failed_(false) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011758
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011759 // Catch the case when the debugger stops in an internal function.
11760 Handle<SharedFunctionInfo> shared_info(function_->shared());
11761 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11762 if (shared_info->script() == isolate->heap()->undefined_value()) {
11763 while (context_->closure() == *function_) {
11764 context_ = Handle<Context>(context_->previous(), isolate_);
11765 }
11766 return;
11767 }
11768
11769 // Get the debug info (create it if it does not exist).
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011770 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011771 // Return if ensuring debug info failed.
11772 return;
11773 }
11774 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11775
11776 // Find the break point where execution has stopped.
11777 BreakLocationIterator break_location_iterator(debug_info,
11778 ALL_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +000011779 // pc points to the instruction after the current one, possibly a break
11780 // location as well. So the "- 1" to exclude it from the search.
11781 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011782 if (break_location_iterator.IsExit()) {
11783 // We are within the return sequence. At the momemt it is not possible to
11784 // get a source position which is consistent with the current scope chain.
11785 // Thus all nested with, catch and block contexts are skipped and we only
11786 // provide the function scope.
11787 if (scope_info->HasContext()) {
11788 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11789 } else {
11790 while (context_->closure() == *function_) {
11791 context_ = Handle<Context>(context_->previous(), isolate_);
11792 }
11793 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011794 if (scope_info->scope_type() != EVAL_SCOPE) {
11795 nested_scope_chain_.Add(scope_info);
11796 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011797 } else {
11798 // Reparse the code and analyze the scopes.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011799 Handle<Script> script(Script::cast(shared_info->script()));
11800 Scope* scope = NULL;
11801
11802 // Check whether we are in global, eval or function code.
11803 Handle<ScopeInfo> scope_info(shared_info->scope_info());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011804 if (scope_info->scope_type() != FUNCTION_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011805 // Global or eval code.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011806 CompilationInfoWithZone info(script);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011807 if (scope_info->scope_type() == GLOBAL_SCOPE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011808 info.MarkAsGlobal();
11809 } else {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011810 ASSERT(scope_info->scope_type() == EVAL_SCOPE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011811 info.MarkAsEval();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011812 info.SetContext(Handle<Context>(function_->context()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011813 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011814 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011815 scope = info.function()->scope();
11816 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011817 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011818 } else {
11819 // Function code
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011820 CompilationInfoWithZone info(shared_info);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011821 if (Parser::Parse(&info) && Scope::Analyze(&info)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011822 scope = info.function()->scope();
11823 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011824 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011825 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011826 }
11827 }
11828
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011829 ScopeIterator(Isolate* isolate,
11830 Handle<JSFunction> function)
11831 : isolate_(isolate),
11832 frame_(NULL),
11833 inlined_jsframe_index_(0),
11834 function_(function),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011835 context_(function->context()),
11836 failed_(false) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011837 if (function->IsBuiltin()) {
11838 context_ = Handle<Context>();
11839 }
11840 }
11841
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011842 // More scopes?
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011843 bool Done() {
11844 ASSERT(!failed_);
11845 return context_.is_null();
11846 }
11847
11848 bool Failed() { return failed_; }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011849
11850 // Move to the next scope.
11851 void Next() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011852 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011853 ScopeType scope_type = Type();
11854 if (scope_type == ScopeTypeGlobal) {
11855 // The global scope is always the last in the chain.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011856 ASSERT(context_->IsNativeContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011857 context_ = Handle<Context>();
11858 return;
11859 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011860 if (nested_scope_chain_.is_empty()) {
11861 context_ = Handle<Context>(context_->previous(), isolate_);
11862 } else {
11863 if (nested_scope_chain_.last()->HasContext()) {
11864 ASSERT(context_->previous() != NULL);
11865 context_ = Handle<Context>(context_->previous(), isolate_);
11866 }
11867 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011868 }
11869 }
11870
11871 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011872 ScopeType Type() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011873 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011874 if (!nested_scope_chain_.is_empty()) {
11875 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000011876 switch (scope_info->scope_type()) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011877 case FUNCTION_SCOPE:
11878 ASSERT(context_->IsFunctionContext() ||
11879 !scope_info->HasContext());
11880 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011881 case MODULE_SCOPE:
11882 ASSERT(context_->IsModuleContext());
11883 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011884 case GLOBAL_SCOPE:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011885 ASSERT(context_->IsNativeContext());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011886 return ScopeTypeGlobal;
11887 case WITH_SCOPE:
11888 ASSERT(context_->IsWithContext());
11889 return ScopeTypeWith;
11890 case CATCH_SCOPE:
11891 ASSERT(context_->IsCatchContext());
11892 return ScopeTypeCatch;
11893 case BLOCK_SCOPE:
11894 ASSERT(!scope_info->HasContext() ||
11895 context_->IsBlockContext());
11896 return ScopeTypeBlock;
11897 case EVAL_SCOPE:
11898 UNREACHABLE();
11899 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011900 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011901 if (context_->IsNativeContext()) {
11902 ASSERT(context_->global_object()->IsGlobalObject());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011903 return ScopeTypeGlobal;
11904 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011905 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011906 return ScopeTypeClosure;
11907 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011908 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011909 return ScopeTypeCatch;
11910 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011911 if (context_->IsBlockContext()) {
11912 return ScopeTypeBlock;
11913 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011914 if (context_->IsModuleContext()) {
11915 return ScopeTypeModule;
11916 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011917 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011918 return ScopeTypeWith;
11919 }
11920
11921 // Return the JavaScript object with the content of the current scope.
11922 Handle<JSObject> ScopeObject() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011923 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011924 switch (Type()) {
11925 case ScopeIterator::ScopeTypeGlobal:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011926 return Handle<JSObject>(CurrentContext()->global_object());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011927 case ScopeIterator::ScopeTypeLocal:
11928 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011929 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011930 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011931 case ScopeIterator::ScopeTypeWith:
11932 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011933 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11934 case ScopeIterator::ScopeTypeCatch:
11935 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011936 case ScopeIterator::ScopeTypeClosure:
11937 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011938 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011939 case ScopeIterator::ScopeTypeBlock:
11940 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011941 case ScopeIterator::ScopeTypeModule:
11942 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011943 }
11944 UNREACHABLE();
11945 return Handle<JSObject>();
11946 }
11947
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011948 bool SetVariableValue(Handle<String> variable_name,
11949 Handle<Object> new_value) {
11950 ASSERT(!failed_);
11951 switch (Type()) {
11952 case ScopeIterator::ScopeTypeGlobal:
11953 break;
11954 case ScopeIterator::ScopeTypeLocal:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011955 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
11956 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011957 case ScopeIterator::ScopeTypeWith:
11958 break;
11959 case ScopeIterator::ScopeTypeCatch:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011960 return SetCatchVariableValue(isolate_, CurrentContext(),
11961 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011962 case ScopeIterator::ScopeTypeClosure:
11963 return SetClosureVariableValue(isolate_, CurrentContext(),
11964 variable_name, new_value);
11965 case ScopeIterator::ScopeTypeBlock:
11966 // TODO(2399): should we implement it?
11967 break;
11968 case ScopeIterator::ScopeTypeModule:
11969 // TODO(2399): should we implement it?
11970 break;
11971 }
11972 return false;
11973 }
11974
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011975 Handle<ScopeInfo> CurrentScopeInfo() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011976 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011977 if (!nested_scope_chain_.is_empty()) {
11978 return nested_scope_chain_.last();
11979 } else if (context_->IsBlockContext()) {
11980 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11981 } else if (context_->IsFunctionContext()) {
11982 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11983 }
11984 return Handle<ScopeInfo>::null();
11985 }
11986
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011987 // Return the context for this scope. For the local context there might not
11988 // be an actual context.
11989 Handle<Context> CurrentContext() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011990 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011991 if (Type() == ScopeTypeGlobal ||
11992 nested_scope_chain_.is_empty()) {
11993 return context_;
11994 } else if (nested_scope_chain_.last()->HasContext()) {
11995 return context_;
11996 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011997 return Handle<Context>();
11998 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011999 }
12000
12001#ifdef DEBUG
12002 // Debug print of the content of the current scope.
12003 void DebugPrint() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012004 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012005 switch (Type()) {
12006 case ScopeIterator::ScopeTypeGlobal:
12007 PrintF("Global:\n");
12008 CurrentContext()->Print();
12009 break;
12010
12011 case ScopeIterator::ScopeTypeLocal: {
12012 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012013 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012014 if (!CurrentContext().is_null()) {
12015 CurrentContext()->Print();
12016 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012017 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012018 if (extension->IsJSContextExtensionObject()) {
12019 extension->Print();
12020 }
12021 }
12022 }
12023 break;
12024 }
12025
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012026 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012027 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012028 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012029 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012030
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012031 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000012032 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012033 CurrentContext()->extension()->Print();
12034 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012035 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012036
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012037 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012038 PrintF("Closure:\n");
12039 CurrentContext()->Print();
12040 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012041 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012042 if (extension->IsJSContextExtensionObject()) {
12043 extension->Print();
12044 }
12045 }
12046 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012047
12048 default:
12049 UNREACHABLE();
12050 }
12051 PrintF("\n");
12052 }
12053#endif
12054
12055 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012056 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012057 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012058 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012059 Handle<JSFunction> function_;
12060 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012061 List<Handle<ScopeInfo> > nested_scope_chain_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012062 bool failed_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012063
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012064 void RetrieveScopeChain(Scope* scope,
12065 Handle<SharedFunctionInfo> shared_info) {
12066 if (scope != NULL) {
12067 int source_position = shared_info->code()->SourcePosition(frame_->pc());
12068 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
12069 } else {
12070 // A failed reparse indicates that the preparser has diverged from the
12071 // parser or that the preparse data given to the initial parse has been
12072 // faulty. We fail in debug mode but in release mode we only provide the
12073 // information we get from the context chain but nothing about
12074 // completely stack allocated scopes or stack allocated locals.
ulan@chromium.org56c14af2012-09-20 12:51:09 +000012075 // Or it could be due to stack overflow.
12076 ASSERT(isolate_->has_pending_exception());
12077 failed_ = true;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012078 }
12079 }
12080
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012081 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
12082};
12083
12084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012085RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012087 ASSERT(args.length() == 2);
12088
12089 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012090 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012091 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12092 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012093 if (!maybe_check->ToObject(&check)) return maybe_check;
12094 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012095 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012096
12097 // Get the frame where the debugging is performed.
12098 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012099 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012100 JavaScriptFrame* frame = it.frame();
12101
12102 // Count the visible scopes.
12103 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012104 for (ScopeIterator it(isolate, frame, 0);
12105 !it.Done();
12106 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012107 n++;
12108 }
12109
12110 return Smi::FromInt(n);
12111}
12112
12113
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012114// Returns the list of step-in positions (text offset) in a function of the
12115// stack frame in a range from the current debug break position to the end
12116// of the corresponding statement.
12117RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) {
12118 HandleScope scope(isolate);
12119 ASSERT(args.length() == 2);
12120
12121 // Check arguments.
12122 Object* check;
12123 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12124 RUNTIME_ARGUMENTS(isolate, args));
12125 if (!maybe_check->ToObject(&check)) return maybe_check;
12126 }
12127 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12128
12129 // Get the frame where the debugging is performed.
12130 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12131 JavaScriptFrameIterator frame_it(isolate, id);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012132 RUNTIME_ASSERT(!frame_it.done());
12133
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012134 JavaScriptFrame* frame = frame_it.frame();
12135
danno@chromium.org59400602013-08-13 17:09:37 +000012136 Handle<JSFunction> fun =
12137 Handle<JSFunction>(frame->function());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012138 Handle<SharedFunctionInfo> shared =
danno@chromium.org59400602013-08-13 17:09:37 +000012139 Handle<SharedFunctionInfo>(fun->shared());
12140
12141 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
12142 return isolate->heap()->undefined_value();
12143 }
12144
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012145 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
12146
12147 int len = 0;
12148 Handle<JSArray> array(isolate->factory()->NewJSArray(10));
12149 // Find the break point where execution has stopped.
12150 BreakLocationIterator break_location_iterator(debug_info,
12151 ALL_BREAK_LOCATIONS);
12152
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012153 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012154 int current_statement_pos = break_location_iterator.statement_position();
12155
12156 while (!break_location_iterator.Done()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012157 bool accept;
danno@chromium.org59400602013-08-13 17:09:37 +000012158 if (break_location_iterator.pc() > frame->pc()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012159 accept = true;
12160 } else {
12161 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
12162 // The break point is near our pc. Could be a step-in possibility,
12163 // that is currently taken by active debugger call.
12164 if (break_frame_id == StackFrame::NO_ID) {
12165 // We are not stepping.
12166 accept = false;
12167 } else {
12168 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
12169 // If our frame is a top frame and we are stepping, we can do step-in
12170 // at this place.
12171 accept = additional_frame_it.frame()->id() == id;
12172 }
12173 }
12174 if (accept) {
danno@chromium.org59400602013-08-13 17:09:37 +000012175 if (break_location_iterator.IsStepInLocation(isolate)) {
12176 Smi* position_value = Smi::FromInt(break_location_iterator.position());
12177 JSObject::SetElement(array, len,
12178 Handle<Object>(position_value, isolate),
12179 NONE, kNonStrictMode);
12180 len++;
12181 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012182 }
12183 // Advance iterator.
12184 break_location_iterator.Next();
12185 if (current_statement_pos !=
12186 break_location_iterator.statement_position()) {
12187 break;
12188 }
12189 }
12190 return *array;
12191}
12192
12193
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012194static const int kScopeDetailsTypeIndex = 0;
12195static const int kScopeDetailsObjectIndex = 1;
12196static const int kScopeDetailsSize = 2;
12197
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012198
12199static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
12200 ScopeIterator* it) {
12201 // Calculate the size of the result.
12202 int details_size = kScopeDetailsSize;
12203 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
12204
12205 // Fill in scope details.
12206 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
12207 Handle<JSObject> scope_object = it->ScopeObject();
12208 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
12209 details->set(kScopeDetailsObjectIndex, *scope_object);
12210
12211 return *isolate->factory()->NewJSArrayWithElements(details);
12212}
12213
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000012214
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012215// Return an array with scope details
12216// args[0]: number: break id
12217// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012218// args[2]: number: inlined frame index
12219// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012220//
12221// The array returned contains the following information:
12222// 0: Scope type
12223// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012225 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012226 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012227
12228 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012229 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012230 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12231 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012232 if (!maybe_check->ToObject(&check)) return maybe_check;
12233 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012234 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012235 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012236 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012237
12238 // Get the frame where the debugging is performed.
12239 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012240 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012241 JavaScriptFrame* frame = frame_it.frame();
12242
12243 // Find the requested scope.
12244 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012245 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012246 for (; !it.Done() && n < index; it.Next()) {
12247 n++;
12248 }
12249 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012250 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012251 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012252 return MaterializeScopeDetails(isolate, &it);
12253}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012254
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012255
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012256RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
12257 HandleScope scope(isolate);
12258 ASSERT(args.length() == 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012259
danno@chromium.org1044a4d2012-04-30 12:34:39 +000012260 // Check arguments.
12261 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12262
12263 // Count the visible scopes.
12264 int n = 0;
12265 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
12266 n++;
12267 }
12268
12269 return Smi::FromInt(n);
12270}
12271
12272
12273RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
12274 HandleScope scope(isolate);
12275 ASSERT(args.length() == 2);
12276
12277 // Check arguments.
12278 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12279 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12280
12281 // Find the requested scope.
12282 int n = 0;
12283 ScopeIterator it(isolate, fun);
12284 for (; !it.Done() && n < index; it.Next()) {
12285 n++;
12286 }
12287 if (it.Done()) {
12288 return isolate->heap()->undefined_value();
12289 }
12290
12291 return MaterializeScopeDetails(isolate, &it);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012292}
12293
12294
mmassi@chromium.org49a44672012-12-04 13:52:03 +000012295static bool SetScopeVariableValue(ScopeIterator* it, int index,
12296 Handle<String> variable_name,
12297 Handle<Object> new_value) {
12298 for (int n = 0; !it->Done() && n < index; it->Next()) {
12299 n++;
12300 }
12301 if (it->Done()) {
12302 return false;
12303 }
12304 return it->SetVariableValue(variable_name, new_value);
12305}
12306
12307
12308// Change variable value in closure or local scope
12309// args[0]: number or JsFunction: break id or function
12310// args[1]: number: frame index (when arg[0] is break id)
12311// args[2]: number: inlined frame index (when arg[0] is break id)
12312// args[3]: number: scope index
12313// args[4]: string: variable name
12314// args[5]: object: new value
12315//
12316// Return true if success and false otherwise
12317RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
12318 HandleScope scope(isolate);
12319 ASSERT(args.length() == 6);
12320
12321 // Check arguments.
12322 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
12323 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
12324 Handle<Object> new_value = args.at<Object>(5);
12325
12326 bool res;
12327 if (args[0]->IsNumber()) {
12328 Object* check;
12329 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12330 RUNTIME_ARGUMENTS(isolate, args));
12331 if (!maybe_check->ToObject(&check)) return maybe_check;
12332 }
12333 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
12334 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
12335
12336 // Get the frame where the debugging is performed.
12337 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12338 JavaScriptFrameIterator frame_it(isolate, id);
12339 JavaScriptFrame* frame = frame_it.frame();
12340
12341 ScopeIterator it(isolate, frame, inlined_jsframe_index);
12342 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12343 } else {
12344 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12345 ScopeIterator it(isolate, fun);
12346 res = SetScopeVariableValue(&it, index, variable_name, new_value);
12347 }
12348
12349 return isolate->heap()->ToBoolean(res);
12350}
12351
12352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012353RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012354 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012355 ASSERT(args.length() == 0);
12356
12357#ifdef DEBUG
12358 // Print the scopes for the top frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000012359 StackFrameLocator locator(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012360 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012361 for (ScopeIterator it(isolate, frame, 0);
12362 !it.Done();
12363 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012364 it.DebugPrint();
12365 }
12366#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012367 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012368}
12369
12370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012371RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012372 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012373 ASSERT(args.length() == 1);
12374
12375 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012376 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012377 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
12378 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012379 if (!maybe_result->ToObject(&result)) return maybe_result;
12380 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012381
12382 // Count all archived V8 threads.
12383 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012384 for (ThreadState* thread =
12385 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012386 thread != NULL;
12387 thread = thread->Next()) {
12388 n++;
12389 }
12390
12391 // Total number of threads is current thread and archived threads.
12392 return Smi::FromInt(n + 1);
12393}
12394
12395
12396static const int kThreadDetailsCurrentThreadIndex = 0;
12397static const int kThreadDetailsThreadIdIndex = 1;
12398static const int kThreadDetailsSize = 2;
12399
12400// Return an array with thread details
12401// args[0]: number: break id
12402// args[1]: number: thread index
12403//
12404// The array returned contains the following information:
12405// 0: Is current thread?
12406// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012407RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012408 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012409 ASSERT(args.length() == 2);
12410
12411 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012412 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012413 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12414 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012415 if (!maybe_check->ToObject(&check)) return maybe_check;
12416 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012417 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12418
12419 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012420 Handle<FixedArray> details =
12421 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012422
12423 // Thread index 0 is current thread.
12424 if (index == 0) {
12425 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012426 details->set(kThreadDetailsCurrentThreadIndex,
12427 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012428 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012429 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012430 } else {
12431 // Find the thread with the requested index.
12432 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012433 ThreadState* thread =
12434 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012435 while (index != n && thread != NULL) {
12436 thread = thread->Next();
12437 n++;
12438 }
12439 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012440 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012441 }
12442
12443 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 details->set(kThreadDetailsCurrentThreadIndex,
12445 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000012446 details->set(kThreadDetailsThreadIdIndex,
12447 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012448 }
12449
12450 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012452}
12453
12454
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012455// Sets the disable break state
12456// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012457RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012458 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012459 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012460 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012461 isolate->debug()->set_disable_break(disable_break);
12462 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000012463}
12464
12465
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012466static bool IsPositionAlignmentCodeCorrect(int alignment) {
12467 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED;
12468}
12469
12470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012471RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012472 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012473 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012475 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012476 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]);
12477
12478 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12479 return isolate->ThrowIllegalOperation();
12480 }
12481 BreakPositionAlignment alignment =
12482 static_cast<BreakPositionAlignment>(statement_aligned_code);
12483
ager@chromium.org5aa501c2009-06-23 07:57:28 +000012484 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012485 // Find the number of break points
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012486 Handle<Object> break_locations =
12487 Debug::GetSourceBreakLocations(shared, alignment);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012488 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012489 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491 Handle<FixedArray>::cast(break_locations));
12492}
12493
12494
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012495// Set a break point in a function.
12496// args[0]: function
12497// args[1]: number: break source position (within the function source)
12498// args[2]: number: break point object
12499RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
12500 HandleScope scope(isolate);
12501 ASSERT(args.length() == 3);
12502 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12503 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12504 RUNTIME_ASSERT(source_position >= 0);
12505 Handle<Object> break_point_object_arg = args.at<Object>(2);
12506
12507 // Set break point.
12508 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
12509 &source_position);
12510
12511 return Smi::FromInt(source_position);
12512}
12513
12514
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012515// Changes the state of a break point in a script and returns source position
12516// where break point was set. NOTE: Regarding performance see the NOTE for
12517// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012518// args[0]: script to set break point in
12519// args[1]: number: break source position (within the script source)
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012520// args[2]: number, breakpoint position alignment
12521// args[3]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012522RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012523 HandleScope scope(isolate);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012524 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012525 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012526 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12527 RUNTIME_ASSERT(source_position >= 0);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012528 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]);
12529 Handle<Object> break_point_object_arg = args.at<Object>(3);
12530
12531 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) {
12532 return isolate->ThrowIllegalOperation();
12533 }
12534 BreakPositionAlignment alignment =
12535 static_cast<BreakPositionAlignment>(statement_aligned_code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536
12537 // Get the script from the script wrapper.
12538 RUNTIME_ASSERT(wrapper->value()->IsScript());
12539 Handle<Script> script(Script::cast(wrapper->value()));
12540
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012541 // Set break point.
12542 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000012543 &source_position,
12544 alignment)) {
yangguo@chromium.org49546742013-12-23 16:17:49 +000012545 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012546 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012547
12548 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012549}
12550
12551
12552// Clear a break point
12553// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012554RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556 ASSERT(args.length() == 1);
12557 Handle<Object> break_point_object_arg = args.at<Object>(0);
12558
12559 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012560 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012563}
12564
12565
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012566// Change the state of break on exceptions.
12567// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
12568// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012569RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012571 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012572 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012573 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012574
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012575 // If the number doesn't match an enum value, the ChangeBreakOnException
12576 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012577 ExceptionBreakType type =
12578 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012579 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012580 isolate->debug()->ChangeBreakOnException(type, enable);
12581 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012582}
12583
12584
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012585// Returns the state of break on exceptions
12586// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012587RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012589 ASSERT(args.length() == 1);
12590 RUNTIME_ASSERT(args[0]->IsNumber());
12591
12592 ExceptionBreakType type =
12593 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000012595 return Smi::FromInt(result);
12596}
12597
12598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012599// Prepare for stepping
12600// args[0]: break id for checking execution state
12601// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000012602// args[2]: number of times to perform the step, for step out it is the number
12603// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012604RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012605 HandleScope scope(isolate);
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012606 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012607 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012608 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012609 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12610 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012611 if (!maybe_check->ToObject(&check)) return maybe_check;
12612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012613 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012614 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012615 }
12616
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012617 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]);
12618
12619 StackFrame::Id frame_id;
12620 if (wrapped_frame_id == 0) {
12621 frame_id = StackFrame::NO_ID;
12622 } else {
12623 frame_id = UnwrapFrameId(wrapped_frame_id);
12624 }
12625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012626 // Get the step action and check validity.
12627 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12628 if (step_action != StepIn &&
12629 step_action != StepNext &&
12630 step_action != StepOut &&
12631 step_action != StepInMin &&
12632 step_action != StepMin) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012633 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012634 }
12635
mvstanton@chromium.org63ea3d22013-10-10 09:24:12 +000012636 if (frame_id != StackFrame::NO_ID && step_action != StepNext &&
12637 step_action != StepMin && step_action != StepOut) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012638 return isolate->ThrowIllegalOperation();
12639 }
12640
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012641 // Get the number of steps.
12642 int step_count = NumberToInt32(args[2]);
12643 if (step_count < 1) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012644 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012645 }
12646
ager@chromium.orga1645e22009-09-09 19:27:10 +000012647 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012648 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012650 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012651 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
dslomov@chromium.org639bac02013-09-09 11:58:54 +000012652 step_count,
12653 frame_id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012655}
12656
12657
12658// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012659RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012660 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012661 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 isolate->debug()->ClearStepping();
12663 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012664}
12665
12666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012667// Helper function to find or create the arguments object for
12668// Runtime_DebugEvaluate.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012669static Handle<JSObject> MaterializeArgumentsObject(
12670 Isolate* isolate,
12671 Handle<JSObject> target,
12672 Handle<JSFunction> function) {
12673 // Do not materialize the arguments object for eval or top-level code.
12674 // Skip if "arguments" is already taken.
12675 if (!function->shared()->is_function() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012676 JSReceiver::HasLocalProperty(target,
12677 isolate->factory()->arguments_string())) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012678 return target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012679 }
12680
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012681 // FunctionGetArguments can't throw an exception.
12682 Handle<JSObject> arguments = Handle<JSObject>::cast(
12683 Accessors::FunctionGetArguments(function));
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000012684 Runtime::SetObjectProperty(isolate, target,
12685 isolate->factory()->arguments_string(),
12686 arguments,
12687 ::NONE,
12688 kNonStrictMode);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012689 return target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012690}
12691
12692
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012693// Compile and evaluate source for the given context.
12694static MaybeObject* DebugEvaluate(Isolate* isolate,
12695 Handle<Context> context,
12696 Handle<Object> context_extension,
12697 Handle<Object> receiver,
12698 Handle<String> source) {
12699 if (context_extension->IsJSObject()) {
12700 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
12701 Handle<JSFunction> closure(context->closure(), isolate);
12702 context = isolate->factory()->NewWithContext(closure, context, extension);
12703 }
12704
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012705 Handle<JSFunction> eval_fun =
yangguo@chromium.org49546742013-12-23 16:17:49 +000012706 Compiler::GetFunctionFromEval(source,
12707 context,
12708 CLASSIC_MODE,
12709 NO_PARSE_RESTRICTION,
12710 RelocInfo::kNoPosition);
12711 RETURN_IF_EMPTY_HANDLE(isolate, eval_fun);
12712
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012713 bool pending_exception;
12714 Handle<Object> result = Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000012715 isolate, eval_fun, receiver, 0, NULL, &pending_exception);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012716
12717 if (pending_exception) return Failure::Exception();
12718
12719 // Skip the global proxy as it has no properties and always delegates to the
12720 // real global object.
12721 if (result->IsJSGlobalProxy()) {
12722 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
12723 }
12724
12725 // Clear the oneshot breakpoints so that the debugger does not step further.
12726 isolate->debug()->ClearStepping();
12727 return *result;
12728}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012729
12730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012731// Evaluate a piece of JavaScript in the context of a stack frame for
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012732// debugging. Things that need special attention are:
12733// - Parameters and stack-allocated locals need to be materialized. Altered
12734// values need to be written back to the stack afterwards.
12735// - The arguments object needs to materialized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012736RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012737 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012738
12739 // Check the execution state and decode arguments frame and source to be
12740 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012741 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012742 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012743 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012744 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012745 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012746 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012747 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012748 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012749 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12750 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012751 Handle<Object> context_extension(args[5], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012752
12753 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012754 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012755
12756 // Get the frame where the debugging is performed.
12757 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012758 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012759 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012760 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12761 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012762
12763 // Traverse the saved contexts chain to find the active context for the
12764 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012765 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12766
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012767 SaveContext savex(isolate);
12768 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012769
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012770 // Evaluate on the context of the frame.
12771 Handle<Context> context(Context::cast(frame->context()));
12772 ASSERT(!context.is_null());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012773
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012774 // Materialize stack locals and the arguments object.
12775 Handle<JSObject> materialized =
12776 isolate->factory()->NewJSObject(isolate->object_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012777
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012778 materialized = MaterializeStackLocalsWithFrameInspector(
12779 isolate, materialized, function, &frame_inspector);
12780 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012781
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012782 materialized = MaterializeArgumentsObject(isolate, materialized, function);
12783 RETURN_IF_EMPTY_HANDLE(isolate, materialized);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012784
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012785 // Add the materialized object in a with-scope to shadow the stack locals.
12786 context = isolate->factory()->NewWithContext(function, context, materialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 Handle<Object> receiver(frame->receiver(), isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012789 Object* evaluate_result_object;
12790 { MaybeObject* maybe_result =
12791 DebugEvaluate(isolate, context, context_extension, receiver, source);
12792 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result;
12793 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012794
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012795 Handle<Object> result(evaluate_result_object, isolate);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012796
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012797 // Write back potential changes to materialized stack locals to the stack.
12798 UpdateStackLocalsFromMaterializedObject(
12799 isolate, materialized, function, frame, inlined_jsframe_index);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012800
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012801 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012802}
12803
12804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012805RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012807
12808 // Check the execution state and decode arguments frame and source to be
12809 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012810 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012811 Object* check_result;
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012812 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813 RUNTIME_ARGUMENTS(isolate, args));
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012814 if (!maybe_result->ToObject(&check_result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012815 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012816 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12817 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012818 Handle<Object> context_extension(args[3], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012819
12820 // Handle the processing of break.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012821 DisableBreak disable_break_save(isolate, disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012822
12823 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012824 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012825 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012826 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012827 top = top->prev();
12828 }
12829 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012831 }
12832
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012833 // Get the native context now set to the top context from before the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012834 // debugger was invoked.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012835 Handle<Context> context = isolate->native_context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012836 Handle<Object> receiver = isolate->global_object();
danno@chromium.orgc99cd482013-03-21 15:26:42 +000012837 return DebugEvaluate(isolate, context, context_extension, receiver, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012838}
12839
12840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012841RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012843 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012845 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012846 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012847
12848 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012849 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012850 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12851 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12852 // because using
12853 // instances->set(i, *GetScriptWrapper(script))
12854 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012855 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012856 Handle<JSValue> wrapper = GetScriptWrapper(script);
12857 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012858 }
12859
12860 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012861 Handle<JSObject> result =
12862 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012863 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012864 return *result;
12865}
12866
12867
12868// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012869static int DebugReferencedBy(HeapIterator* iterator,
12870 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012871 Object* instance_filter, int max_references,
12872 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012873 JSFunction* arguments_function) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012874 Isolate* isolate = target->GetIsolate();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012875 SealHandleScope shs(isolate);
12876 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012877
12878 // Iterate the heap.
12879 int count = 0;
12880 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012881 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012882 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012883 (max_references == 0 || count < max_references)) {
12884 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012885 if (heap_obj->IsJSObject()) {
12886 // Skip context extension objects and argument arrays as these are
12887 // checked in the context of functions using them.
12888 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012889 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012890 obj->map()->constructor() == arguments_function) {
12891 continue;
12892 }
12893
12894 // Check if the JS object has a reference to the object looked for.
12895 if (obj->ReferencesObject(target)) {
12896 // Check instance filter if supplied. This is normally used to avoid
12897 // references from mirror objects (see Runtime_IsInPrototypeChain).
12898 if (!instance_filter->IsUndefined()) {
12899 Object* V = obj;
12900 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012901 Object* prototype = V->GetPrototype(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012902 if (prototype->IsNull()) {
12903 break;
12904 }
12905 if (instance_filter == prototype) {
12906 obj = NULL; // Don't add this object.
12907 break;
12908 }
12909 V = prototype;
12910 }
12911 }
12912
12913 if (obj != NULL) {
12914 // Valid reference found add to instance array if supplied an update
12915 // count.
12916 if (instances != NULL && count < instances_size) {
12917 instances->set(count, obj);
12918 }
12919 last = obj;
12920 count++;
12921 }
12922 }
12923 }
12924 }
12925
12926 // Check for circular reference only. This can happen when the object is only
12927 // referenced from mirrors and has a circular reference in which case the
12928 // object is not really alive and would have been garbage collected if not
12929 // referenced from the mirror.
12930 if (count == 1 && last == target) {
12931 count = 0;
12932 }
12933
12934 // Return the number of referencing objects found.
12935 return count;
12936}
12937
12938
12939// Scan the heap for objects with direct references to an object
12940// args[0]: the object to find references to
12941// args[1]: constructor function for instances to exclude (Mirror)
12942// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012943RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000012944 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012945 ASSERT(args.length() == 3);
12946
12947 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012948 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12949 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012950 // The heap iterator reserves the right to do a GC to make the heap iterable.
12951 // Due to the GC above we know it won't need to do that, but it seems cleaner
12952 // to get the heap iterator constructed before we start having unprotected
12953 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012954
12955 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012956 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012957 Object* instance_filter = args[1];
12958 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12959 instance_filter->IsJSObject());
12960 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12961 RUNTIME_ASSERT(max_references >= 0);
12962
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012964 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012965 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012966 isolate->context()->native_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012967 JSFunction* arguments_function =
12968 JSFunction::cast(arguments_boilerplate->map()->constructor());
12969
12970 // Get the number of referencing objects.
12971 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012972 Heap* heap = isolate->heap();
12973 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012974 count = DebugReferencedBy(&heap_iterator,
12975 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012976 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012977
12978 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012979 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012980 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012981 if (!maybe_object->ToObject(&object)) return maybe_object;
12982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012983 FixedArray* instances = FixedArray::cast(object);
12984
12985 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012986 // AllocateFixedArray above does not make the heap non-iterable.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012987 ASSERT(heap->IsHeapIterable());
12988 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012989 count = DebugReferencedBy(&heap_iterator2,
12990 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012991 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012992
12993 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012994 Object* result;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012995 MaybeObject* maybe_result = heap->AllocateJSObject(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012996 isolate->context()->native_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012997 if (!maybe_result->ToObject(&result)) return maybe_result;
12998 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012999}
13000
13001
13002// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013003static int DebugConstructedBy(HeapIterator* iterator,
13004 JSFunction* constructor,
13005 int max_references,
13006 FixedArray* instances,
13007 int instances_size) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013008 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013009
13010 // Iterate the heap.
13011 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013012 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013013 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013014 (max_references == 0 || count < max_references)) {
13015 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013016 if (heap_obj->IsJSObject()) {
13017 JSObject* obj = JSObject::cast(heap_obj);
13018 if (obj->map()->constructor() == constructor) {
13019 // Valid reference found add to instance array if supplied an update
13020 // count.
13021 if (instances != NULL && count < instances_size) {
13022 instances->set(count, obj);
13023 }
13024 count++;
13025 }
13026 }
13027 }
13028
13029 // Return the number of referencing objects found.
13030 return count;
13031}
13032
13033
13034// Scan the heap for objects constructed by a specific function.
13035// args[0]: the constructor to find instances of
13036// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013037RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013038 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013039 ASSERT(args.length() == 2);
13040
13041 // First perform a full GC in order to avoid dead objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013042 Heap* heap = isolate->heap();
13043 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013044
13045 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013046 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013047 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
13048 RUNTIME_ASSERT(max_references >= 0);
13049
13050 // Get the number of referencing objects.
13051 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013052 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013053 count = DebugConstructedBy(&heap_iterator,
13054 constructor,
13055 max_references,
13056 NULL,
13057 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013058
13059 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013060 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013061 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013062 if (!maybe_object->ToObject(&object)) return maybe_object;
13063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013064 FixedArray* instances = FixedArray::cast(object);
13065
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000013066 ASSERT(isolate->heap()->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013067 // Fill the referencing objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013068 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013069 count = DebugConstructedBy(&heap_iterator2,
13070 constructor,
13071 max_references,
13072 instances,
13073 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013074
13075 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013076 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013077 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013078 isolate->context()->native_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013079 if (!maybe_result->ToObject(&result)) return maybe_result;
13080 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013081 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013082}
13083
13084
ager@chromium.orgddb913d2009-01-27 10:01:48 +000013085// Find the effective prototype object as returned by __proto__.
13086// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013087RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013088 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013089 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013090 CONVERT_ARG_CHECKED(JSObject, obj, 0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013091 return GetPrototypeSkipHiddenPrototypes(isolate, obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092}
13093
13094
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013095// Patches script source (should be called upon BeforeCompile event).
13096RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
13097 HandleScope scope(isolate);
13098 ASSERT(args.length() == 2);
13099
13100 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013101 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013102
13103 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
13104 Handle<Script> script(Script::cast(script_wrapper->value()));
13105
danno@chromium.orgd3c42102013-08-01 16:58:23 +000013106 int compilation_state = script->compilation_state();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013107 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
13108 script->set_source(*source);
13109
13110 return isolate->heap()->undefined_value();
13111}
13112
13113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013114RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013115 SealHandleScope shs(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000013116 ASSERT(args.length() == 0);
rossberg@chromium.org92597162013-08-23 13:28:00 +000013117 OS::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013118 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013119}
13120
13121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013122RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013123 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013124#ifdef DEBUG
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013125 ASSERT(args.length() == 1);
13126 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013127 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +000013128 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013129 return Failure::Exception();
13130 }
13131 func->code()->PrintLn();
13132#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013133 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013134}
ager@chromium.org9085a012009-05-11 19:22:57 +000013135
13136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013137RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013138 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013139#ifdef DEBUG
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013140 ASSERT(args.length() == 1);
13141 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013142 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org49546742013-12-23 16:17:49 +000013143 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013144 return Failure::Exception();
13145 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +000013146 func->shared()->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013147#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013148 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000013149}
13150
13151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013152RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013153 SealHandleScope shs(isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +000013154 ASSERT(args.length() == 1);
13155
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013156 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000013157 return f->shared()->inferred_name();
13158}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013160
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013161static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
13162 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013163 FixedArray* buffer) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013164 DisallowHeapAllocation no_allocation;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013165 int counter = 0;
13166 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013167 for (HeapObject* obj = iterator->next();
13168 obj != NULL;
13169 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013170 ASSERT(obj != NULL);
13171 if (!obj->IsSharedFunctionInfo()) {
13172 continue;
13173 }
13174 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
13175 if (shared->script() != script) {
13176 continue;
13177 }
13178 if (counter < buffer_size) {
13179 buffer->set(counter, shared);
13180 }
13181 counter++;
13182 }
13183 return counter;
13184}
13185
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013187// For a script finds all SharedFunctionInfo's in the heap that points
13188// to this script. Returns JSArray of SharedFunctionInfo wrapped
13189// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013190RUNTIME_FUNCTION(MaybeObject*,
13191 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013192 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013193 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013194 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013195 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013196
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013197 RUNTIME_ASSERT(script_value->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013198 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
13199
13200 const int kBufferSize = 32;
13201
13202 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013203 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013204 int number;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013205 Heap* heap = isolate->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013206 {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013207 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013208 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013209 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013210 Script* scr = *script;
13211 FixedArray* arr = *array;
13212 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
13213 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013214 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013215 array = isolate->factory()->NewFixedArray(number);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013216 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013217 DisallowHeapAllocation no_allocation;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000013218 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013219 Script* scr = *script;
13220 FixedArray* arr = *array;
13221 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013222 }
13223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013224 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013225 result->set_length(Smi::FromInt(number));
13226
13227 LiveEdit::WrapSharedFunctionInfos(result);
13228
13229 return *result;
13230}
13231
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013232
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013233// For a script calculates compilation information about all its functions.
13234// The script source is explicitly specified by the second argument.
13235// The source of the actual script is not used, however it is important that
13236// all generated code keeps references to this particular instance of script.
13237// Returns a JSArray of compilation infos. The array is ordered so that
13238// each function with all its descendant is always stored in a continues range
13239// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013240RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013241 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013242 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013243 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013244 CONVERT_ARG_CHECKED(JSValue, script, 0);
13245 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013246
13247 RUNTIME_ASSERT(script->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013248 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
13249
13250 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
13251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013252 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013253 return Failure::Exception();
13254 }
13255
13256 return result;
13257}
13258
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013259
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013260// Changes the source of the script to a new_source.
13261// If old_script_name is provided (i.e. is a String), also creates a copy of
13262// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013263RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
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() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013267 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
13268 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013269 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013270
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013271 RUNTIME_ASSERT(original_script_value->value()->IsScript());
13272 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013273
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013274 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
13275 new_source,
13276 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013277
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013278 if (old_script->IsScript()) {
13279 Handle<Script> script_handle(Script::cast(old_script));
13280 return *(GetScriptWrapper(script_handle));
13281 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013282 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013283 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013284}
13285
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013287RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013288 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013289 CHECK(isolate->debugger()->live_edit_enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013290 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013291 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013292 return LiveEdit::FunctionSourceUpdated(shared_info);
13293}
13294
13295
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013296// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013297RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013298 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013299 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013300 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013301 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
13302 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013303
ager@chromium.orgac091b72010-05-05 07:34:42 +000013304 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013305}
13306
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013307
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013308// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013309RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013310 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013311 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013312 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013313 Handle<Object> function_object(args[0], isolate);
13314 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013315
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013316 if (function_object->IsJSValue()) {
13317 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
13318 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013319 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
13320 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013321 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013322 }
13323
13324 LiveEdit::SetFunctionScript(function_wrapper, script_object);
13325 } else {
13326 // Just ignore this. We may not have a SharedFunctionInfo for some functions
13327 // and we check it in this function.
13328 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013330 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013331}
13332
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013333
13334// In a code of a parent function replaces original function as embedded object
13335// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013336RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013337 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013338 CHECK(isolate->debugger()->live_edit_enabled());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013339 ASSERT(args.length() == 3);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013340
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013341 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
13342 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
13343 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013344
13345 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
13346 subst_wrapper);
13347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013348 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000013349}
13350
13351
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013352// Updates positions of a shared function info (first parameter) according
13353// to script source change. Text change is described in second parameter as
13354// array of groups of 3 numbers:
13355// (change_begin, change_end, change_end_new_position).
13356// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013357RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013358 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013359 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013360 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013361 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13362 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013363
ager@chromium.orgac091b72010-05-05 07:34:42 +000013364 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013365}
13366
13367
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013368// For array of SharedFunctionInfo's (each wrapped in JSValue)
13369// checks that none of them have activations on stacks (of any thread).
13370// Returns array of the same length with corresponding results of
13371// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013372RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013373 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013374 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.org357bf652010-04-12 11:30:10 +000013375 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013376 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
13377 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013378
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013379 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013380}
13381
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013382
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013383// Compares 2 strings line-by-line, then token-wise and returns diff in form
13384// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
13385// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013386RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013387 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013388 CHECK(isolate->debugger()->live_edit_enabled());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013389 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013390 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
13391 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013392
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000013393 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013394}
13395
13396
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013397// Restarts a call frame and completely drops all frames above.
13398// Returns true if successful. Otherwise returns undefined or an error message.
13399RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
13400 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013401 CHECK(isolate->debugger()->live_edit_enabled());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013402 ASSERT(args.length() == 2);
13403
13404 // Check arguments.
13405 Object* check;
13406 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
13407 RUNTIME_ARGUMENTS(isolate, args));
13408 if (!maybe_check->ToObject(&check)) return maybe_check;
13409 }
13410 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
13411 Heap* heap = isolate->heap();
13412
13413 // Find the relevant frame with the requested index.
13414 StackFrame::Id id = isolate->debug()->break_frame_id();
13415 if (id == StackFrame::NO_ID) {
13416 // If there are no JavaScript stack frames return undefined.
13417 return heap->undefined_value();
13418 }
13419
13420 int count = 0;
13421 JavaScriptFrameIterator it(isolate, id);
13422 for (; !it.done(); it.Advance()) {
13423 if (index < count + it.frame()->GetInlineCount()) break;
13424 count += it.frame()->GetInlineCount();
13425 }
13426 if (it.done()) return heap->undefined_value();
13427
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013428 const char* error_message = LiveEdit::RestartFrame(it.frame());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013429 if (error_message) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013430 return *(isolate->factory()->InternalizeUtf8String(error_message));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000013431 }
13432 return heap->true_value();
13433}
13434
13435
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013436// A testing entry. Returns statement position which is the closest to
13437// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013438RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013439 HandleScope scope(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013440 CHECK(isolate->debugger()->live_edit_enabled());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013441 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013442 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013443 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
13444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013445 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013446
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013447 if (code->kind() != Code::FUNCTION &&
13448 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013449 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013450 }
13451
13452 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013453 int closest_pc = 0;
13454 int distance = kMaxInt;
13455 while (!it.done()) {
13456 int statement_position = static_cast<int>(it.rinfo()->data());
13457 // Check if this break point is closer that what was previously found.
13458 if (source_position <= statement_position &&
13459 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000013460 closest_pc =
13461 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000013462 distance = statement_position - source_position;
13463 // Check whether we can't get any closer.
13464 if (distance == 0) break;
13465 }
13466 it.next();
13467 }
13468
13469 return Smi::FromInt(closest_pc);
13470}
13471
13472
ager@chromium.org357bf652010-04-12 11:30:10 +000013473// Calls specified function with or without entering the debugger.
13474// This is used in unit tests to run code as if debugger is entered or simply
13475// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013476RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013477 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013478 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013479 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
13480 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000013481
13482 Handle<Object> result;
13483 bool pending_exception;
13484 {
13485 if (without_debugger) {
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013486 result = Execution::Call(isolate,
13487 function,
13488 isolate->global_object(),
13489 0,
13490 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013491 &pending_exception);
13492 } else {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013493 EnterDebugger enter_debugger(isolate);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000013494 result = Execution::Call(isolate,
13495 function,
13496 isolate->global_object(),
13497 0,
13498 NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000013499 &pending_exception);
13500 }
13501 }
13502 if (!pending_exception) {
13503 return *result;
13504 } else {
13505 return Failure::Exception();
13506 }
13507}
13508
13509
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013510// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013511RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013512 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013513 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000013514 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013515 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +000013516 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013517 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013518}
13519
13520
13521// Performs a GC.
13522// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013523RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013524 SealHandleScope shs(isolate);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000013525 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013526 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013527}
13528
13529
13530// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013531RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013532 SealHandleScope shs(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013533 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013534 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013535 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000013536 }
13537 return Smi::FromInt(usage);
13538}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013539
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013540#endif // ENABLE_DEBUGGER_SUPPORT
13541
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013542
danno@chromium.org59400602013-08-13 17:09:37 +000013543#ifdef V8_I18N_SUPPORT
13544RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) {
13545 HandleScope scope(isolate);
13546
13547 ASSERT(args.length() == 1);
13548 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0);
13549
13550 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str));
13551
13552 // Return value which denotes invalid language tag.
13553 const char* const kInvalidTag = "invalid-tag";
13554
13555 UErrorCode error = U_ZERO_ERROR;
13556 char icu_result[ULOC_FULLNAME_CAPACITY];
13557 int icu_length = 0;
13558
13559 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY,
13560 &icu_length, &error);
13561 if (U_FAILURE(error) || icu_length == 0) {
13562 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13563 }
13564
13565 char result[ULOC_FULLNAME_CAPACITY];
13566
13567 // Force strict BCP47 rules.
13568 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error);
13569
13570 if (U_FAILURE(error)) {
13571 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag));
13572 }
13573
13574 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13575}
13576
13577
13578RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) {
13579 HandleScope scope(isolate);
13580
13581 ASSERT(args.length() == 1);
13582 CONVERT_ARG_HANDLE_CHECKED(String, service, 0);
13583
13584 const icu::Locale* available_locales = NULL;
13585 int32_t count = 0;
13586
13587 if (service->IsUtf8EqualTo(CStrVector("collator"))) {
13588 available_locales = icu::Collator::getAvailableLocales(count);
13589 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) {
13590 available_locales = icu::NumberFormat::getAvailableLocales(count);
13591 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) {
13592 available_locales = icu::DateFormat::getAvailableLocales(count);
13593 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) {
13594 available_locales = icu::BreakIterator::getAvailableLocales(count);
13595 }
13596
13597 UErrorCode error = U_ZERO_ERROR;
13598 char result[ULOC_FULLNAME_CAPACITY];
13599 Handle<JSObject> locales =
13600 isolate->factory()->NewJSObject(isolate->object_function());
13601
13602 for (int32_t i = 0; i < count; ++i) {
13603 const char* icu_name = available_locales[i].getName();
13604
13605 error = U_ZERO_ERROR;
13606 // No need to force strict BCP47 rules.
13607 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13608 if (U_FAILURE(error)) {
13609 // This shouldn't happen, but lets not break the user.
13610 continue;
13611 }
13612
13613 RETURN_IF_EMPTY_HANDLE(isolate,
13614 JSObject::SetLocalPropertyIgnoreAttributes(
13615 locales,
13616 isolate->factory()->NewStringFromAscii(CStrVector(result)),
13617 isolate->factory()->NewNumber(i),
13618 NONE));
13619 }
13620
13621 return *locales;
13622}
13623
13624
13625RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) {
13626 SealHandleScope shs(isolate);
13627
13628 ASSERT(args.length() == 0);
13629
13630 icu::Locale default_locale;
13631
13632 // Set the locale
13633 char result[ULOC_FULLNAME_CAPACITY];
13634 UErrorCode status = U_ZERO_ERROR;
13635 uloc_toLanguageTag(
13636 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
13637 if (U_SUCCESS(status)) {
13638 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result));
13639 }
13640
13641 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und"));
13642}
13643
13644
13645RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
13646 HandleScope scope(isolate);
13647
13648 ASSERT(args.length() == 1);
13649
13650 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0);
13651
13652 uint32_t length = static_cast<uint32_t>(input->length()->Number());
13653 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length);
13654 Handle<Name> maximized =
13655 isolate->factory()->NewStringFromAscii(CStrVector("maximized"));
13656 Handle<Name> base =
13657 isolate->factory()->NewStringFromAscii(CStrVector("base"));
13658 for (unsigned int i = 0; i < length; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000013659 MaybeObject* maybe_string = input->GetElement(isolate, i);
danno@chromium.org59400602013-08-13 17:09:37 +000013660 Object* locale_id;
13661 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) {
13662 return isolate->Throw(isolate->heap()->illegal_argument_string());
13663 }
13664
13665 v8::String::Utf8Value utf8_locale_id(
13666 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id))));
13667
13668 UErrorCode error = U_ZERO_ERROR;
13669
13670 // Convert from BCP47 to ICU format.
13671 // de-DE-u-co-phonebk -> de_DE@collation=phonebook
13672 char icu_locale[ULOC_FULLNAME_CAPACITY];
13673 int icu_locale_length = 0;
13674 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY,
13675 &icu_locale_length, &error);
13676 if (U_FAILURE(error) || icu_locale_length == 0) {
13677 return isolate->Throw(isolate->heap()->illegal_argument_string());
13678 }
13679
13680 // Maximize the locale.
13681 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook
13682 char icu_max_locale[ULOC_FULLNAME_CAPACITY];
13683 uloc_addLikelySubtags(
13684 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13685
13686 // Remove extensions from maximized locale.
13687 // de_Latn_DE@collation=phonebook -> de_Latn_DE
13688 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY];
13689 uloc_getBaseName(
13690 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error);
13691
13692 // Get original name without extensions.
13693 // de_DE@collation=phonebook -> de_DE
13694 char icu_base_locale[ULOC_FULLNAME_CAPACITY];
13695 uloc_getBaseName(
13696 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error);
13697
13698 // Convert from ICU locale format to BCP47 format.
13699 // de_Latn_DE -> de-Latn-DE
13700 char base_max_locale[ULOC_FULLNAME_CAPACITY];
13701 uloc_toLanguageTag(icu_base_max_locale, base_max_locale,
13702 ULOC_FULLNAME_CAPACITY, FALSE, &error);
13703
13704 // de_DE -> de-DE
13705 char base_locale[ULOC_FULLNAME_CAPACITY];
13706 uloc_toLanguageTag(
13707 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error);
13708
13709 if (U_FAILURE(error)) {
13710 return isolate->Throw(isolate->heap()->illegal_argument_string());
13711 }
13712
13713 Handle<JSObject> result =
13714 isolate->factory()->NewJSObject(isolate->object_function());
13715 RETURN_IF_EMPTY_HANDLE(isolate,
13716 JSObject::SetLocalPropertyIgnoreAttributes(
13717 result,
13718 maximized,
13719 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)),
13720 NONE));
13721 RETURN_IF_EMPTY_HANDLE(isolate,
13722 JSObject::SetLocalPropertyIgnoreAttributes(
13723 result,
13724 base,
13725 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)),
13726 NONE));
13727 output->set(i, *result);
13728 }
13729
13730 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output);
13731 result->set_length(Smi::FromInt(length));
13732 return *result;
13733}
13734
13735
13736RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
13737 HandleScope scope(isolate);
13738
13739 ASSERT(args.length() == 3);
13740
13741 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13742 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13743 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13744
13745 Handle<ObjectTemplateInfo> date_format_template =
13746 I18N::GetTemplate(isolate);
13747
13748 // Create an empty object wrapper.
13749 bool has_pending_exception = false;
13750 Handle<JSObject> local_object = Execution::InstantiateObject(
13751 date_format_template, &has_pending_exception);
13752 if (has_pending_exception) {
13753 ASSERT(isolate->has_pending_exception());
13754 return Failure::Exception();
13755 }
13756
13757 // Set date time formatter as internal field of the resulting JS object.
13758 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
13759 isolate, locale, options, resolved);
13760
13761 if (!date_format) return isolate->ThrowIllegalOperation();
13762
13763 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
13764
13765 RETURN_IF_EMPTY_HANDLE(isolate,
13766 JSObject::SetLocalPropertyIgnoreAttributes(
13767 local_object,
13768 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
13769 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13770 NONE));
13771
danno@chromium.org59400602013-08-13 17:09:37 +000013772 // Make object handle weak so we can delete the data format once GC kicks in.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013773 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000013774 GlobalHandles::MakeWeak(wrapper.location(),
13775 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013776 DateFormat::DeleteDateFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013777 return *local_object;
13778}
13779
13780
13781RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
13782 HandleScope scope(isolate);
13783
13784 ASSERT(args.length() == 2);
13785
13786 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13787 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
13788
13789 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013790 Handle<Object> value =
13791 Execution::ToNumber(isolate, date, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013792 if (has_pending_exception) {
13793 ASSERT(isolate->has_pending_exception());
13794 return Failure::Exception();
13795 }
13796
13797 icu::SimpleDateFormat* date_format =
13798 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13799 if (!date_format) return isolate->ThrowIllegalOperation();
13800
13801 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013802 date_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013803
13804 return *isolate->factory()->NewStringFromTwoByte(
13805 Vector<const uint16_t>(
13806 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13807 result.length()));
13808}
13809
13810
13811RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
13812 HandleScope scope(isolate);
13813
13814 ASSERT(args.length() == 2);
13815
13816 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
13817 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
13818
13819 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
13820 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
13821 icu::SimpleDateFormat* date_format =
13822 DateFormat::UnpackDateFormat(isolate, date_format_holder);
13823 if (!date_format) return isolate->ThrowIllegalOperation();
13824
13825 UErrorCode status = U_ZERO_ERROR;
13826 UDate date = date_format->parse(u_date, status);
13827 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13828
13829 bool has_pending_exception = false;
13830 Handle<JSDate> result = Handle<JSDate>::cast(
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013831 Execution::NewDate(
13832 isolate, static_cast<double>(date), &has_pending_exception));
danno@chromium.org59400602013-08-13 17:09:37 +000013833 if (has_pending_exception) {
13834 ASSERT(isolate->has_pending_exception());
13835 return Failure::Exception();
13836 }
13837 return *result;
13838}
13839
13840
13841RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) {
13842 HandleScope scope(isolate);
13843
13844 ASSERT(args.length() == 3);
13845
13846 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13847 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13848 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13849
13850 Handle<ObjectTemplateInfo> number_format_template =
13851 I18N::GetTemplate(isolate);
13852
13853 // Create an empty object wrapper.
13854 bool has_pending_exception = false;
13855 Handle<JSObject> local_object = Execution::InstantiateObject(
13856 number_format_template, &has_pending_exception);
13857 if (has_pending_exception) {
13858 ASSERT(isolate->has_pending_exception());
13859 return Failure::Exception();
13860 }
13861
13862 // Set number formatter as internal field of the resulting JS object.
13863 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat(
13864 isolate, locale, options, resolved);
13865
13866 if (!number_format) return isolate->ThrowIllegalOperation();
13867
13868 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format));
13869
13870 RETURN_IF_EMPTY_HANDLE(isolate,
13871 JSObject::SetLocalPropertyIgnoreAttributes(
13872 local_object,
13873 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")),
13874 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13875 NONE));
13876
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013877 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000013878 GlobalHandles::MakeWeak(wrapper.location(),
13879 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013880 NumberFormat::DeleteNumberFormat);
danno@chromium.org59400602013-08-13 17:09:37 +000013881 return *local_object;
13882}
13883
13884
13885RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) {
13886 HandleScope scope(isolate);
13887
13888 ASSERT(args.length() == 2);
13889
13890 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13891 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
13892
13893 bool has_pending_exception = false;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000013894 Handle<Object> value = Execution::ToNumber(
13895 isolate, number, &has_pending_exception);
danno@chromium.org59400602013-08-13 17:09:37 +000013896 if (has_pending_exception) {
13897 ASSERT(isolate->has_pending_exception());
13898 return Failure::Exception();
13899 }
13900
13901 icu::DecimalFormat* number_format =
13902 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13903 if (!number_format) return isolate->ThrowIllegalOperation();
13904
13905 icu::UnicodeString result;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013906 number_format->format(value->Number(), result);
danno@chromium.org59400602013-08-13 17:09:37 +000013907
13908 return *isolate->factory()->NewStringFromTwoByte(
13909 Vector<const uint16_t>(
13910 reinterpret_cast<const uint16_t*>(result.getBuffer()),
13911 result.length()));
13912}
13913
13914
13915RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) {
13916 HandleScope scope(isolate);
13917
13918 ASSERT(args.length() == 2);
13919
13920 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0);
13921 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1);
13922
13923 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string));
13924 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number));
13925 icu::DecimalFormat* number_format =
13926 NumberFormat::UnpackNumberFormat(isolate, number_format_holder);
13927 if (!number_format) return isolate->ThrowIllegalOperation();
13928
13929 UErrorCode status = U_ZERO_ERROR;
13930 icu::Formattable result;
13931 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49
13932 // to be part of Chrome.
13933 // TODO(cira): Include currency parsing code using parseCurrency call.
13934 // We need to check if the formatter parses all currencies or only the
13935 // one it was constructed with (it will impact the API - how to return ISO
13936 // code and the value).
13937 number_format->parse(u_number, result, status);
13938 if (U_FAILURE(status)) return isolate->heap()->undefined_value();
13939
13940 switch (result.getType()) {
13941 case icu::Formattable::kDouble:
13942 return *isolate->factory()->NewNumber(result.getDouble());
13943 case icu::Formattable::kLong:
13944 return *isolate->factory()->NewNumberFromInt(result.getLong());
13945 case icu::Formattable::kInt64:
13946 return *isolate->factory()->NewNumber(
13947 static_cast<double>(result.getInt64()));
13948 default:
13949 return isolate->heap()->undefined_value();
13950 }
13951}
13952
13953
13954RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) {
13955 HandleScope scope(isolate);
13956
13957 ASSERT(args.length() == 3);
13958
13959 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
13960 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
13961 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
13962
13963 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate);
13964
13965 // Create an empty object wrapper.
13966 bool has_pending_exception = false;
13967 Handle<JSObject> local_object = Execution::InstantiateObject(
13968 collator_template, &has_pending_exception);
13969 if (has_pending_exception) {
13970 ASSERT(isolate->has_pending_exception());
13971 return Failure::Exception();
13972 }
13973
13974 // Set collator as internal field of the resulting JS object.
13975 icu::Collator* collator = Collator::InitializeCollator(
13976 isolate, locale, options, resolved);
13977
13978 if (!collator) return isolate->ThrowIllegalOperation();
13979
13980 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator));
13981
13982 RETURN_IF_EMPTY_HANDLE(isolate,
13983 JSObject::SetLocalPropertyIgnoreAttributes(
13984 local_object,
13985 isolate->factory()->NewStringFromAscii(CStrVector("collator")),
13986 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
13987 NONE));
13988
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013989 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000013990 GlobalHandles::MakeWeak(wrapper.location(),
13991 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000013992 Collator::DeleteCollator);
danno@chromium.org59400602013-08-13 17:09:37 +000013993 return *local_object;
13994}
13995
13996
13997RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) {
13998 HandleScope scope(isolate);
13999
14000 ASSERT(args.length() == 3);
14001
14002 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0);
14003 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1);
14004 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2);
14005
14006 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder);
14007 if (!collator) return isolate->ThrowIllegalOperation();
14008
14009 v8::String::Value string_value1(v8::Utils::ToLocal(string1));
14010 v8::String::Value string_value2(v8::Utils::ToLocal(string2));
14011 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1);
14012 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2);
14013 UErrorCode status = U_ZERO_ERROR;
14014 UCollationResult result = collator->compare(u_string1,
14015 string_value1.length(),
14016 u_string2,
14017 string_value2.length(),
14018 status);
14019 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation();
14020
14021 return *isolate->factory()->NewNumberFromInt(result);
14022}
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014023
14024
14025RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) {
14026 HandleScope scope(isolate);
14027
14028 ASSERT(args.length() == 3);
14029
14030 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
14031 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
14032 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
14033
14034 Handle<ObjectTemplateInfo> break_iterator_template =
14035 I18N::GetTemplate2(isolate);
14036
14037 // Create an empty object wrapper.
14038 bool has_pending_exception = false;
14039 Handle<JSObject> local_object = Execution::InstantiateObject(
14040 break_iterator_template, &has_pending_exception);
14041 if (has_pending_exception) {
14042 ASSERT(isolate->has_pending_exception());
14043 return Failure::Exception();
14044 }
14045
14046 // Set break iterator as internal field of the resulting JS object.
14047 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator(
14048 isolate, locale, options, resolved);
14049
14050 if (!break_iterator) return isolate->ThrowIllegalOperation();
14051
14052 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator));
14053 // Make sure that the pointer to adopted text is NULL.
14054 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL));
14055
14056 RETURN_IF_EMPTY_HANDLE(isolate,
14057 JSObject::SetLocalPropertyIgnoreAttributes(
14058 local_object,
14059 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")),
14060 isolate->factory()->NewStringFromAscii(CStrVector("valid")),
14061 NONE));
14062
14063 // Make object handle weak so we can delete the break iterator once GC kicks
14064 // in.
14065 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +000014066 GlobalHandles::MakeWeak(wrapper.location(),
14067 reinterpret_cast<void*>(wrapper.location()),
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000014068 BreakIterator::DeleteBreakIterator);
14069 return *local_object;
14070}
14071
14072
14073RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) {
14074 HandleScope scope(isolate);
14075
14076 ASSERT(args.length() == 2);
14077
14078 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14079 CONVERT_ARG_HANDLE_CHECKED(String, text, 1);
14080
14081 icu::BreakIterator* break_iterator =
14082 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14083 if (!break_iterator) return isolate->ThrowIllegalOperation();
14084
14085 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>(
14086 break_iterator_holder->GetInternalField(1));
14087 delete u_text;
14088
14089 v8::String::Value text_value(v8::Utils::ToLocal(text));
14090 u_text = new icu::UnicodeString(
14091 reinterpret_cast<const UChar*>(*text_value), text_value.length());
14092 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text));
14093
14094 break_iterator->setText(*u_text);
14095
14096 return isolate->heap()->undefined_value();
14097}
14098
14099
14100RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) {
14101 HandleScope scope(isolate);
14102
14103 ASSERT(args.length() == 1);
14104
14105 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14106
14107 icu::BreakIterator* break_iterator =
14108 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14109 if (!break_iterator) return isolate->ThrowIllegalOperation();
14110
14111 return *isolate->factory()->NewNumberFromInt(break_iterator->first());
14112}
14113
14114
14115RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) {
14116 HandleScope scope(isolate);
14117
14118 ASSERT(args.length() == 1);
14119
14120 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14121
14122 icu::BreakIterator* break_iterator =
14123 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14124 if (!break_iterator) return isolate->ThrowIllegalOperation();
14125
14126 return *isolate->factory()->NewNumberFromInt(break_iterator->next());
14127}
14128
14129
14130RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) {
14131 HandleScope scope(isolate);
14132
14133 ASSERT(args.length() == 1);
14134
14135 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14136
14137 icu::BreakIterator* break_iterator =
14138 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14139 if (!break_iterator) return isolate->ThrowIllegalOperation();
14140
14141 return *isolate->factory()->NewNumberFromInt(break_iterator->current());
14142}
14143
14144
14145RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) {
14146 HandleScope scope(isolate);
14147
14148 ASSERT(args.length() == 1);
14149
14150 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0);
14151
14152 icu::BreakIterator* break_iterator =
14153 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder);
14154 if (!break_iterator) return isolate->ThrowIllegalOperation();
14155
14156 // TODO(cira): Remove cast once ICU fixes base BreakIterator class.
14157 icu::RuleBasedBreakIterator* rule_based_iterator =
14158 static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
14159 int32_t status = rule_based_iterator->getRuleStatus();
14160 // Keep return values in sync with JavaScript BreakType enum.
14161 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
14162 return *isolate->factory()->NewStringFromAscii(CStrVector("none"));
14163 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
14164 return *isolate->factory()->NewStringFromAscii(CStrVector("number"));
14165 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
14166 return *isolate->factory()->NewStringFromAscii(CStrVector("letter"));
14167 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
14168 return *isolate->factory()->NewStringFromAscii(CStrVector("kana"));
14169 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
14170 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo"));
14171 } else {
14172 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown"));
14173 }
14174}
danno@chromium.org59400602013-08-13 17:09:37 +000014175#endif // V8_I18N_SUPPORT
14176
14177
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014178// Finds the script object from the script data. NOTE: This operation uses
14179// heap traversal to find the function generated for the source position
14180// for the requested break point. For lazily compiled functions several heap
14181// traversals might be required rendering this operation as a rather slow
14182// operation. However for setting break points which is normally done through
14183// some kind of user interaction the performance is not crucial.
14184static Handle<Object> Runtime_GetScriptFromScriptName(
14185 Handle<String> script_name) {
14186 // Scan the heap for Script objects to find the script with the requested
14187 // script data.
14188 Handle<Script> script;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014189 Factory* factory = script_name->GetIsolate()->factory();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014190 Heap* heap = script_name->GetHeap();
14191 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014192 DisallowHeapAllocation no_allocation_during_heap_iteration;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000014193 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014194 HeapObject* obj = NULL;
14195 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014196 // If a script is found check if it has the script data requested.
14197 if (obj->IsScript()) {
14198 if (Script::cast(obj)->name()->IsString()) {
14199 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
14200 script = Handle<Script>(Script::cast(obj));
14201 }
14202 }
14203 }
14204 }
14205
14206 // If no script with the requested script data is found return undefined.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000014207 if (script.is_null()) return factory->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014208
14209 // Return the script found.
14210 return GetScriptWrapper(script);
14211}
14212
14213
14214// Get the script object from script data. NOTE: Regarding performance
14215// see the NOTE for GetScriptFromScriptData.
14216// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014218 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014219
14220 ASSERT(args.length() == 1);
14221
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014222 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014223
14224 // Find the requested script.
14225 Handle<Object> result =
14226 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
14227 return *result;
14228}
14229
14230
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014231// Collect the raw data for a stack trace. Returns an array of 4
14232// element segments each containing a receiver, function, code and
14233// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014234RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014235 HandleScope scope(isolate);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014236 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014237 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000014238 Handle<Object> caller = args.at<Object>(1);
14239 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014240
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014241 // Optionally capture a more detailed stack trace for the message.
14242 isolate->CaptureAndSetDetailedStackTrace(error_object);
14243 // Capture a simple stack trace for the stack property.
14244 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
14245}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014246
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014247
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014248// Retrieve the stack trace. This is the raw stack trace that yet has to
14249// be formatted. Since we only need this once, clear it afterwards.
14250RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000014251 HandleScope scope(isolate);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000014252 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014253 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
14254 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
14255 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000014256 if (result->IsTheHole()) return isolate->heap()->undefined_value();
14257 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000014258 JSObject::DeleteHiddenProperty(error_object, key);
14259 return *result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014260}
14261
14262
ager@chromium.org3811b432009-10-28 14:53:37 +000014263// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014264RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014265 SealHandleScope shs(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014266 ASSERT_EQ(args.length(), 0);
ager@chromium.org3811b432009-10-28 14:53:37 +000014267
14268 const char* version_string = v8::V8::GetVersion();
14269
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000014270 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014271 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000014272}
14273
14274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014275RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014276 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014277 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000014278 OS::PrintError("abort: %s\n",
14279 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000014280 isolate->PrintStack(stderr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014281 OS::Abort();
14282 UNREACHABLE();
14283 return NULL;
14284}
14285
14286
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014287RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) {
14288 HandleScope scope(isolate);
14289 ASSERT(args.length() == 1);
14290 CONVERT_ARG_HANDLE_CHECKED(String, message, 0);
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +000014291 OS::PrintError("abort: %s\n", message->ToCString().get());
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014292 isolate->PrintStack(stderr);
14293 OS::Abort();
14294 UNREACHABLE();
14295 return NULL;
14296}
14297
14298
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014299RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
14300 HandleScope scope(isolate);
14301 ASSERT(args.length() == 1);
14302 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
14303 FlattenString(str);
14304 return isolate->heap()->undefined_value();
14305}
14306
14307
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +000014308RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) {
14309 HandleScope scope(isolate);
14310 ASSERT(args.length() == 0);
14311 isolate->heap()->NotifyContextDisposed();
14312 return isolate->heap()->undefined_value();
14313}
14314
14315
danno@chromium.org59400602013-08-13 17:09:37 +000014316RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) {
14317 HandleScope scope(isolate);
14318 ASSERT(args.length() == 1);
14319 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
14320 if (!object->IsJSObject()) return Smi::FromInt(0);
14321 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
14322 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
14323 JSObject::MigrateInstance(js_object);
14324 return *object;
14325}
14326
14327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014328RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014329 SealHandleScope shs(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014330 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014331 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014332 Object* key = args[1];
14333
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014334 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014335 Object* o = cache->get(finger_index);
14336 if (o == key) {
14337 // The fastest case: hit the same place again.
14338 return cache->get(finger_index + 1);
14339 }
14340
14341 for (int i = finger_index - 2;
14342 i >= JSFunctionResultCache::kEntriesIndex;
14343 i -= 2) {
14344 o = cache->get(i);
14345 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014346 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014347 return cache->get(i + 1);
14348 }
14349 }
14350
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014351 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014352 ASSERT(size <= cache->length());
14353
14354 for (int i = size - 2; i > finger_index; i -= 2) {
14355 o = cache->get(i);
14356 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014357 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014358 return cache->get(i + 1);
14359 }
14360 }
14361
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014362 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014363 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014364
14365 Handle<JSFunctionResultCache> cache_handle(cache);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014366 Handle<Object> key_handle(key, isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014367 Handle<Object> value;
14368 {
14369 Handle<JSFunction> factory(JSFunction::cast(
14370 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
14371 // TODO(antonm): consider passing a receiver when constructing a cache.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014372 Handle<Object> receiver(isolate->native_context()->global_object(),
14373 isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014374 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014375 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014376 bool pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000014377 value = Execution::Call(isolate,
14378 factory,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014379 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000014380 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014381 argv,
14382 &pending_exception);
14383 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014384 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014385
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014386#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014387 if (FLAG_verify_heap) {
14388 cache_handle->JSFunctionResultCacheVerify();
14389 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014390#endif
14391
14392 // Function invocation may have cleared the cache. Reread all the data.
14393 finger_index = cache_handle->finger_index();
14394 size = cache_handle->size();
14395
14396 // If we have spare room, put new data into it, otherwise evict post finger
14397 // entry which is likely to be the least recently used.
14398 int index = -1;
14399 if (size < cache_handle->length()) {
14400 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
14401 index = size;
14402 } else {
14403 index = finger_index + JSFunctionResultCache::kEntrySize;
14404 if (index == cache_handle->length()) {
14405 index = JSFunctionResultCache::kEntriesIndex;
14406 }
14407 }
14408
14409 ASSERT(index % 2 == 0);
14410 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
14411 ASSERT(index < cache_handle->length());
14412
14413 cache_handle->set(index, *key_handle);
14414 cache_handle->set(index + 1, *value);
14415 cache_handle->set_finger_index(index);
14416
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000014417#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014418 if (FLAG_verify_heap) {
14419 cache_handle->JSFunctionResultCacheVerify();
14420 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000014421#endif
14422
14423 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000014424}
14425
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014427RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014428 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014429 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014430 return Smi::FromInt(message->start_position());
14431}
14432
14433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014434RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014435 SealHandleScope shs(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014436 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000014437 return message->script();
14438}
14439
14440
kasper.lund44510672008-07-25 07:37:58 +000014441#ifdef DEBUG
14442// ListNatives is ONLY used by the fuzz-natives.js in debug mode
14443// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014444RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014445 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014446 ASSERT(args.length() == 0);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014447#define COUNT_ENTRY(Name, argc, ressize) + 1
14448 int entry_count = 0
14449 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
14450 INLINE_FUNCTION_LIST(COUNT_ENTRY)
14451 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
14452#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014453 Factory* factory = isolate->factory();
14454 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014455 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014456 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000014457#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014458 { \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000014459 HandleScope inner(isolate); \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014460 Handle<String> name; \
14461 /* Inline runtime functions have an underscore in front of the name. */ \
14462 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014463 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014464 Vector<const char>("_" #Name, StrLength("_" #Name))); \
14465 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014466 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014467 Vector<const char>(#Name, StrLength(#Name))); \
14468 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014469 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014470 pair_elements->set(0, *name); \
14471 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014472 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014473 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014474 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014475 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014476 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014477 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014478 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000014479 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014480#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000014481 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014482 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014483 return *result;
14484}
kasper.lund44510672008-07-25 07:37:58 +000014485#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014486
14487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014488RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014489 SealHandleScope shs(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014490 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014491 CONVERT_ARG_CHECKED(String, format, 0);
14492 CONVERT_ARG_CHECKED(JSArray, elms, 1);
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014493 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000014494 String::FlatContent format_content = format->GetFlatContent();
14495 RUNTIME_ASSERT(format_content.IsAscii());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014496 Vector<const uint8_t> chars = format_content.ToOneByteVector();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000014497 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014498 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000014499}
14500
14501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014502RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014503 UNREACHABLE(); // implemented as macro in the parser
14504 return NULL;
14505}
14506
14507
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014508#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
14509 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014510 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014511 return isolate->heap()->ToBoolean(obj->Has##Name()); \
14512 }
14513
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014514ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
14515ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
14516ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014517ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014518ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014519ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014520ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014521ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
14522ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
14523ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
14524ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
14525ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
14526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
14527ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
14528ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
14529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
14530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
mmassi@chromium.org7028c052012-06-13 11:51:58 +000014531// Properties test sitting with elements tests - not fooling anyone.
14532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000014533
14534#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
14535
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014536
14537RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014538 SealHandleScope shs(isolate);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014539 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000014540 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
14541 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000014542 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
14543}
14544
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014545
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014546RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) {
14547 SealHandleScope shs(isolate);
14548 ASSERT(args.length() == 1);
14549 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
14550 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded());
14551}
14552
14553
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014554RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014555 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014556 ASSERT(args.length() == 1);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +000014557
14558 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value();
14559 JSReceiver* obj = JSReceiver::cast(args[0]);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014560 if (obj->IsJSGlobalProxy()) {
14561 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014562 if (proto->IsNull()) return isolate->heap()->false_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014563 ASSERT(proto->IsJSGlobalObject());
14564 obj = JSReceiver::cast(proto);
14565 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014566 return isolate->heap()->ToBoolean(obj->map()->is_observed());
14567}
14568
14569
14570RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014571 HandleScope scope(isolate);
danno@chromium.org169691d2013-07-15 08:01:13 +000014572 ASSERT(args.length() == 1);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014573 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014574 if (obj->IsJSGlobalProxy()) {
14575 Object* proto = obj->GetPrototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014576 if (proto->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014577 ASSERT(proto->IsJSGlobalObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014578 obj = handle(JSReceiver::cast(proto));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014579 }
danno@chromium.org59400602013-08-13 17:09:37 +000014580 if (obj->IsJSProxy())
14581 return isolate->heap()->undefined_value();
14582
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014583 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014584 Handle<JSObject>::cast(obj)->HasFastElements()));
danno@chromium.org169691d2013-07-15 08:01:13 +000014585 ASSERT(obj->IsJSObject());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000014586 JSObject::SetObserved(Handle<JSObject>::cast(obj));
14587 return isolate->heap()->undefined_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014588}
14589
14590
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014591RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014592 SealHandleScope shs(isolate);
machenbach@chromium.org9f18d912013-11-28 13:42:41 +000014593 ASSERT(args.length() == 1);
14594 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
14595 bool old_state = isolate->microtask_pending();
14596 isolate->set_microtask_pending(new_state);
14597 return isolate->heap()->ToBoolean(old_state);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014598}
14599
14600
14601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014602 SealHandleScope shs(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014603 ASSERT(args.length() == 0);
14604 return isolate->heap()->observation_state();
14605}
14606
14607
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014608RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014609 HandleScope scope(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014610 ASSERT(args.length() == 0);
14611 // TODO(adamk): Currently this runtime function is only called three times per
14612 // isolate. If it's called more often, the map should be moved into the
14613 // strong root list.
14614 Handle<Map> map =
14615 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
14616 Handle<JSWeakMap> weakmap =
14617 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000014618 return WeakCollectionInitialize(isolate, weakmap);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014619}
14620
14621
14622RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014623 SealHandleScope shs(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014624 ASSERT(args.length() == 1);
14625 Object* object = args[0];
14626 if (object->IsJSGlobalProxy()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000014627 object = object->GetPrototype(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014628 if (object->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000014629 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000014630 return object;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000014631}
14632
14633
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000014634RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) {
14635 HandleScope scope(isolate);
14636 ASSERT(args.length() == 3);
14637 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0);
14638 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1);
14639 ASSERT(object->IsAccessCheckNeeded());
14640 Handle<Object> key = args.at<Object>(2);
14641 SaveContext save(isolate);
14642 isolate->set_context(observer->context());
14643 if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
14644 v8::ACCESS_KEYS)) {
14645 return isolate->heap()->false_value();
14646 }
14647 bool access_allowed = false;
14648 uint32_t index = 0;
14649 if (key->ToArrayIndex(&index) ||
14650 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) {
14651 access_allowed =
14652 isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) &&
14653 isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS);
14654 } else {
14655 access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) &&
14656 isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS);
14657 }
14658 return isolate->heap()->ToBoolean(access_allowed);
14659}
14660
14661
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014662static MaybeObject* ArrayConstructorCommon(Isolate* isolate,
14663 Handle<JSFunction> constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014664 Handle<AllocationSite> site,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014665 Arguments* caller_args) {
14666 bool holey = false;
14667 bool can_use_type_feedback = true;
14668 if (caller_args->length() == 1) {
14669 Object* argument_one = (*caller_args)[0];
14670 if (argument_one->IsSmi()) {
14671 int value = Smi::cast(argument_one)->value();
14672 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
14673 // the array is a dictionary in this case.
14674 can_use_type_feedback = false;
14675 } else if (value != 0) {
14676 holey = true;
14677 }
14678 } else {
14679 // Non-smi length argument produces a dictionary
14680 can_use_type_feedback = false;
14681 }
14682 }
14683
14684 JSArray* array;
14685 MaybeObject* maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014686 if (!site.is_null() && can_use_type_feedback) {
danno@chromium.orgbee51992013-07-10 14:57:15 +000014687 ElementsKind to_kind = site->GetElementsKind();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014688 if (holey && !IsFastHoleyElementsKind(to_kind)) {
14689 to_kind = GetHoleyElementsKind(to_kind);
14690 // Update the allocation site info to reflect the advice alteration.
danno@chromium.orgbee51992013-07-10 14:57:15 +000014691 site->SetElementsKind(to_kind);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014692 }
14693
14694 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite(
danno@chromium.orgbee51992013-07-10 14:57:15 +000014695 *constructor, site);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014696 if (!maybe_array->To(&array)) return maybe_array;
14697 } else {
14698 maybe_array = isolate->heap()->AllocateJSObject(*constructor);
14699 if (!maybe_array->To(&array)) return maybe_array;
14700 // We might need to transition to holey
14701 ElementsKind kind = constructor->initial_map()->elements_kind();
14702 if (holey && !IsFastHoleyElementsKind(kind)) {
14703 kind = GetHoleyElementsKind(kind);
14704 maybe_array = array->TransitionElementsKind(kind);
14705 if (maybe_array->IsFailure()) return maybe_array;
14706 }
14707 }
14708
14709 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0,
14710 DONT_INITIALIZE_ARRAY_ELEMENTS);
14711 if (maybe_array->IsFailure()) return maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014712 ElementsKind old_kind = array->GetElementsKind();
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014713 maybe_array = ArrayConstructInitializeElements(array, caller_args);
14714 if (maybe_array->IsFailure()) return maybe_array;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014715 if (!site.is_null() &&
14716 (old_kind != array->GetElementsKind() ||
14717 !can_use_type_feedback)) {
14718 // The arguments passed in caused a transition. This kind of complexity
14719 // can't be dealt with in the inlined hydrogen array constructor case.
14720 // We must mark the allocationsite as un-inlinable.
14721 site->SetDoNotInlineCall();
14722 }
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014723 return array;
14724}
14725
14726
14727RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
14728 HandleScope scope(isolate);
14729 // If we get 2 arguments then they are the stub parameters (constructor, type
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014730 // info). If we get 4, then the first one is a pointer to the arguments
14731 // passed by the caller, and the last one is the length of the arguments
14732 // passed to the caller (redundant, but useful to check on the deoptimizer
14733 // with an assert).
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014734 Arguments empty_args(0, NULL);
14735 bool no_caller_args = args.length() == 2;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014736 ASSERT(no_caller_args || args.length() == 4);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014737 int parameters_start = no_caller_args ? 0 : 1;
14738 Arguments* caller_args = no_caller_args
14739 ? &empty_args
14740 : reinterpret_cast<Arguments*>(args[0]);
14741 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
14742 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014743#ifdef DEBUG
14744 if (!no_caller_args) {
14745 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
14746 ASSERT(arg_count == caller_args->length());
14747 }
14748#endif
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014749
14750 Handle<AllocationSite> site;
14751 if (!type_info.is_null() &&
14752 *type_info != isolate->heap()->undefined_value() &&
14753 Cell::cast(*type_info)->value()->IsAllocationSite()) {
14754 site = Handle<AllocationSite>(
14755 AllocationSite::cast(Cell::cast(*type_info)->value()), isolate);
14756 ASSERT(!site->SitePointsToLiteral());
14757 }
14758
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014759 return ArrayConstructorCommon(isolate,
14760 constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014761 site,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014762 caller_args);
14763}
14764
14765
14766RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) {
14767 HandleScope scope(isolate);
14768 Arguments empty_args(0, NULL);
14769 bool no_caller_args = args.length() == 1;
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014770 ASSERT(no_caller_args || args.length() == 3);
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014771 int parameters_start = no_caller_args ? 0 : 1;
14772 Arguments* caller_args = no_caller_args
14773 ? &empty_args
14774 : reinterpret_cast<Arguments*>(args[0]);
14775 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000014776#ifdef DEBUG
14777 if (!no_caller_args) {
14778 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
14779 ASSERT(arg_count == caller_args->length());
14780 }
14781#endif
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014782 return ArrayConstructorCommon(isolate,
14783 constructor,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014784 Handle<AllocationSite>::null(),
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000014785 caller_args);
14786}
14787
14788
machenbach@chromium.orgea468882013-11-18 08:53:19 +000014789RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) {
14790 return Smi::FromInt(Smi::kMaxValue);
14791}
14792
14793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014794// ----------------------------------------------------------------------------
14795// Implementation of Runtime
14796
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014797#define F(name, number_of_args, result_size) \
14798 { Runtime::k##name, Runtime::RUNTIME, #name, \
14799 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014800
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014801
14802#define I(name, number_of_args, result_size) \
14803 { Runtime::kInline##name, Runtime::INLINE, \
14804 "_" #name, NULL, number_of_args, result_size },
14805
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014806static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014807 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014808 INLINE_FUNCTION_LIST(I)
14809 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014810};
14811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014813MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
14814 Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014815 ASSERT(dictionary != NULL);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014816 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014817 for (int i = 0; i < kNumFunctions; ++i) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014818 Object* name_string;
14819 { MaybeObject* maybe_name_string =
14820 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
14821 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014822 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000014823 NameDictionary* name_dictionary = NameDictionary::cast(dictionary);
14824 { MaybeObject* maybe_dictionary = name_dictionary->Add(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014825 String::cast(name_string),
lrn@chromium.org303ada72010-10-27 09:33:13 +000014826 Smi::FromInt(i),
danno@chromium.orgf005df62013-04-30 16:36:45 +000014827 PropertyDetails(NONE, NORMAL, Representation::None()));
lrn@chromium.org303ada72010-10-27 09:33:13 +000014828 if (!maybe_dictionary->ToObject(&dictionary)) {
14829 // Non-recoverable failure. Calling code must restart heap
14830 // initialization.
14831 return maybe_dictionary;
14832 }
14833 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014834 }
14835 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014836}
14837
14838
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014839const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014840 Heap* heap = name->GetHeap();
14841 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014842 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014843 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014844 int function_index = Smi::cast(smi_index)->value();
14845 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014846 }
14847 return NULL;
14848}
14849
14850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014851const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000014852 return &(kIntrinsicFunctions[static_cast<int>(id)]);
14853}
14854
14855
machenbach@chromium.org528ce022013-09-23 14:09:36 +000014856void Runtime::PerformGC(Object* result, Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014857 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014858 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014859 if (isolate->heap()->new_space()->AddFreshPage()) {
14860 return;
14861 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000014862
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014863 // Try to do a garbage collection; ignore it if it fails. The C
14864 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014865 isolate->heap()->CollectGarbage(failure->allocation_space(),
14866 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014867 } else {
14868 // Handle last resort GC and make sure to allow future allocations
14869 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000014870 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000014871 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
14872 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000014873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014874}
14875
14876
14877} } // namespace v8::internal