blob: 2215eadcf3cda1c98d15770281688342ecf6d255 [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>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000048#include "jsregexp-inl.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000049#include "json-parser.h"
danno@chromium.org72204d52012-10-31 10:02:10 +000050#include "json-stringifier.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000051#include "liveedit.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000052#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000053#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000055#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057#include "scopeinfo.h"
yangguo@chromium.org304cc332012-07-24 07:59:48 +000058#include "smart-pointers.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000060#include "stub-cache.h"
ulan@chromium.org2e04b582013-02-21 14:06:02 +000061#include "uri.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000062#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000063#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasperl@chromium.org71affb52009-05-26 05:44:31 +000065namespace v8 {
66namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68
ager@chromium.org3e875802009-06-29 08:26:34 +000069#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000070 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071
72// Cast the given object to a value of the specified type and store
73// it in a variable with the given name. If the object is not of the
74// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000077 Type* name = Type::cast(args[index]);
78
79#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
80 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081 Handle<Type> name = args.at<Type>(index);
82
kasper.lundbd3ec4e2008-07-09 11:06:54 +000083// Cast the given object to a boolean and store it in a variable with
84// the given name. If the object is not a boolean call IllegalOperation
85// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000086#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
87 RUNTIME_ASSERT(args[index]->IsBoolean()); \
88 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000089
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090// Cast the given argument to a Smi and store its value in an int variable
91// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093#define CONVERT_SMI_ARG_CHECKED(name, index) \
94 RUNTIME_ASSERT(args[index]->IsSmi()); \
95 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097// Cast the given argument to a double and store it in a variable with
98// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000100#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
101 RUNTIME_ASSERT(args[index]->IsNumber()); \
102 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104// Call the specified converter on the object *comand store the result in
105// a variable of the specified type with the given name. If the
106// object is not a Number call IllegalOperation and return.
107#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
108 RUNTIME_ASSERT(obj->IsNumber()); \
109 type name = NumberTo##Type(obj);
110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000112// Cast the given argument to PropertyDetails and store its value in a
113// variable with the given name. If the argument is not a Smi call
114// IllegalOperation and return.
115#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
116 RUNTIME_ASSERT(args[index]->IsSmi()); \
117 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
118
119
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000120// Assert that the given argument has a valid value for a StrictModeFlag
121// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000122#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
123 RUNTIME_ASSERT(args[index]->IsSmi()); \
124 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
125 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000126 StrictModeFlag name = \
127 static_cast<StrictModeFlag>(args.smi_at(index));
128
129
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000130// Assert that the given argument has a valid value for a LanguageMode
131// and store it in a LanguageMode variable with the given name.
132#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
133 ASSERT(args[index]->IsSmi()); \
134 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
135 args.smi_at(index) == STRICT_MODE || \
136 args.smi_at(index) == EXTENDED_MODE); \
137 LanguageMode name = \
138 static_cast<LanguageMode>(args.smi_at(index));
139
140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000141MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
142 JSObject* boilerplate) {
143 StackLimitCheck check(isolate);
144 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000148 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000149 if (!maybe_result->ToObject(&result)) return maybe_result;
150 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 JSObject* copy = JSObject::cast(result);
152
153 // Deep copy local properties.
154 if (copy->HasFastProperties()) {
155 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 for (int i = 0; i < properties->length(); i++) {
157 Object* value = properties->get(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000166 int nof = copy->map()->inobject_properties();
167 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 Object* value = copy->InObjectPropertyAt(i);
169 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000170 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000171 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000172 if (!maybe_result->ToObject(&result)) return maybe_result;
173 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000175 }
176 }
177 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000179 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000180 if (!maybe_result->ToObject(&result)) return maybe_result;
181 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000182 FixedArray* names = FixedArray::cast(result);
183 copy->GetLocalPropertyNames(names, 0);
184 for (int i = 0; i < names->length(); i++) {
185 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000188 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000189 // Only deep copy fields from the object literal expression.
190 // In particular, don't try to copy the length attribute of
191 // an array.
192 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 Object* value =
194 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000195 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000196 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000197 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000198 if (!maybe_result->ToObject(&result)) return maybe_result;
199 }
200 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000201 // Creating object copy for literals. No strict mode needed.
202 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000203 if (!maybe_result->ToObject(&result)) return maybe_result;
204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 }
206 }
207 }
208
209 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000211 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 switch (copy->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000213 case FAST_SMI_ELEMENTS:
214 case FAST_ELEMENTS:
215 case FAST_HOLEY_SMI_ELEMENTS:
216 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 if (elements->map() == heap->fixed_cow_array_map()) {
219 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000220#ifdef DEBUG
221 for (int i = 0; i < elements->length(); i++) {
222 ASSERT(!elements->get(i)->IsJSObject());
223 }
224#endif
225 } else {
226 for (int i = 0; i < elements->length(); i++) {
227 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000228 ASSERT(value->IsSmi() ||
229 value->IsTheHole() ||
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000230 (IsFastObjectElementsKind(copy->GetElementsKind())));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000231 if (value->IsJSObject()) {
232 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000233 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
234 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000235 if (!maybe_result->ToObject(&result)) return maybe_result;
236 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000237 elements->set(i, result);
238 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000239 }
240 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000242 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000243 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000244 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000245 int capacity = element_dictionary->Capacity();
246 for (int i = 0; i < capacity; i++) {
247 Object* k = element_dictionary->KeyAt(i);
248 if (element_dictionary->IsKey(k)) {
249 Object* value = element_dictionary->ValueAt(i);
250 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000251 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
253 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000254 if (!maybe_result->ToObject(&result)) return maybe_result;
255 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000256 element_dictionary->ValueAtPut(i, result);
257 }
258 }
259 }
260 break;
261 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000262 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000263 UNIMPLEMENTED();
264 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000265 case EXTERNAL_PIXEL_ELEMENTS:
266 case EXTERNAL_BYTE_ELEMENTS:
267 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
268 case EXTERNAL_SHORT_ELEMENTS:
269 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
270 case EXTERNAL_INT_ELEMENTS:
271 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
272 case EXTERNAL_FLOAT_ELEMENTS:
273 case EXTERNAL_DOUBLE_ELEMENTS:
274 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000275 case FAST_HOLEY_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000276 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000277 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000278 }
279 return copy;
280}
281
282
ager@chromium.org236ad962008-09-25 09:45:57 +0000283static Handle<Map> ComputeObjectLiteralMap(
284 Handle<Context> context,
285 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 int properties_length = constant_properties->length();
289 int number_of_properties = properties_length / 2;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000290 // Check that there are only internal strings and array indices among keys.
291 int number_of_string_keys = 0;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000292 for (int p = 0; p != properties_length; p += 2) {
293 Object* key = constant_properties->get(p);
294 uint32_t element_index = 0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000295 if (key->IsInternalizedString()) {
296 number_of_string_keys++;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000297 } else if (key->ToArrayIndex(&element_index)) {
298 // An index key does not require space in the property backing store.
299 number_of_properties--;
300 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000301 // Bail out as a non-internalized-string non-index key makes caching
302 // impossible.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000303 // ASSERT to make sure that the if condition after the loop is false.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000304 ASSERT(number_of_string_keys != number_of_properties);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000305 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000306 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000307 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000308 // If we only have internalized strings and array indices among keys then we
309 // can use the map cache in the native context.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000310 const int kMaxKeys = 10;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000311 if ((number_of_string_keys == number_of_properties) &&
312 (number_of_string_keys < kMaxKeys)) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000313 // Create the fixed array with the key.
314 Handle<FixedArray> keys =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000315 isolate->factory()->NewFixedArray(number_of_string_keys);
316 if (number_of_string_keys > 0) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 int index = 0;
318 for (int p = 0; p < properties_length; p += 2) {
319 Object* key = constant_properties->get(p);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000320 if (key->IsInternalizedString()) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000321 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000322 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000323 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000324 ASSERT(index == number_of_string_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000325 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000326 *is_result_from_cache = true;
327 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000328 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000329 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000331 Handle<Map>(context->object_function()->initial_map()),
332 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000333}
334
335
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000336static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
339 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000340
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000341
342static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000344 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000345 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 bool should_have_fast_elements,
347 bool has_function_literal) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000348 // Get the native context from the literals array. This is the
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000349 // context in which the function was created and we use the object
350 // function from this context to create the object literal. We do
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000351 // not use the object function from the current native context
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000352 // because this might be the object function from another context
353 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000354 Handle<Context> context =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000355 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals));
ager@chromium.org236ad962008-09-25 09:45:57 +0000356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000357 // In case we have function literals, we want the object to be in
358 // slow properties mode for now. We don't go in the map cache because
359 // maps with constant functions can't be shared if the functions are
360 // not the same (which is the common case).
361 bool is_result_from_cache = false;
362 Handle<Map> map = has_function_literal
363 ? Handle<Map>(context->object_function()->initial_map())
364 : ComputeObjectLiteralMap(context,
365 constant_properties,
366 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000369
370 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000371 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000373 // Add the constant properties to the boilerplate.
374 int length = constant_properties->length();
375 bool should_transform =
376 !is_result_from_cache && boilerplate->HasFastProperties();
377 if (should_transform || has_function_literal) {
378 // Normalize the properties of object to avoid n^2 behavior
379 // when extending the object multiple properties. Indicate the number of
380 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000381 JSObject::NormalizeProperties(
382 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383 }
384
385 for (int index = 0; index < length; index +=2) {
386 Handle<Object> key(constant_properties->get(index+0), isolate);
387 Handle<Object> value(constant_properties->get(index+1), isolate);
388 if (value->IsFixedArray()) {
389 // The value contains the constant_properties of a
390 // simple object or array literal.
391 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
392 value = CreateLiteralBoilerplate(isolate, literals, array);
393 if (value.is_null()) return value;
394 }
395 Handle<Object> result;
396 uint32_t element_index = 0;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000397 if (key->IsInternalizedString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
399 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000400 result = JSObject::SetOwnElement(
401 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000403 Handle<String> name(String::cast(*key));
404 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000405 result = JSObject::SetLocalPropertyIgnoreAttributes(
406 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 } else if (key->ToArrayIndex(&element_index)) {
409 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000410 result = JSObject::SetOwnElement(
411 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 } else {
413 // Non-uint32 number.
414 ASSERT(key->IsNumber());
415 double num = key->Number();
416 char arr[100];
417 Vector<char> buffer(arr, ARRAY_SIZE(arr));
418 const char* str = DoubleToCString(num, buffer);
419 Handle<String> name =
420 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000421 result = JSObject::SetLocalPropertyIgnoreAttributes(
422 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000424 // If setting the property on the boilerplate throws an
425 // exception, the exception is converted to an empty handle in
426 // the handle based operations. In that case, we need to
427 // convert back to an exception.
428 if (result.is_null()) return result;
429 }
430
431 // Transform to fast properties if necessary. For object literals with
432 // containing function literals we defer this operation until after all
433 // computed properties have been assigned so that we can generate
434 // constant function properties.
435 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000436 JSObject::TransformToFastProperties(
437 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 }
439
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000441}
442
443
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000444MaybeObject* TransitionElements(Handle<Object> object,
445 ElementsKind to_kind,
446 Isolate* isolate) {
447 HandleScope scope(isolate);
448 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
449 ElementsKind from_kind =
450 Handle<JSObject>::cast(object)->map()->elements_kind();
451 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
452 Handle<Object> result = JSObject::TransitionElementsKind(
453 Handle<JSObject>::cast(object), to_kind);
454 if (result.is_null()) return isolate->ThrowIllegalOperation();
455 return *result;
456 }
457 return isolate->ThrowIllegalOperation();
458}
459
460
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000461static const int kSmiLiteralMinimumLength = 1024;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462
463
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000464Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000465 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466 Handle<FixedArray> literals,
467 Handle<FixedArray> elements) {
468 // Create the JSArray.
469 Handle<JSFunction> constructor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000470 JSFunction::NativeContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471 Handle<JSArray> object =
472 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 ElementsKind constant_elements_kind =
475 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
476 Handle<FixedArrayBase> constant_elements_values(
477 FixedArrayBase::cast(elements->get(1)));
478
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000479 ASSERT(IsFastElementsKind(constant_elements_kind));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000480 Context* native_context = isolate->context()->native_context();
481 Object* maybe_maps_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000482 ASSERT(!maybe_maps_array->IsUndefined());
483 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get(
484 constant_elements_kind);
485 ASSERT(maybe_map->IsMap());
486 object->set_map(Map::cast(maybe_map));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 Handle<FixedArrayBase> copied_elements_values;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000489 if (IsFastDoubleElementsKind(constant_elements_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000490 ASSERT(FLAG_smi_only_arrays);
491 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
492 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000493 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000494 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000495 const bool is_cow =
496 (constant_elements_values->map() ==
497 isolate->heap()->fixed_cow_array_map());
498 if (is_cow) {
499 copied_elements_values = constant_elements_values;
500#if DEBUG
501 Handle<FixedArray> fixed_array_values =
502 Handle<FixedArray>::cast(copied_elements_values);
503 for (int i = 0; i < fixed_array_values->length(); i++) {
504 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
505 }
506#endif
507 } else {
508 Handle<FixedArray> fixed_array_values =
509 Handle<FixedArray>::cast(constant_elements_values);
510 Handle<FixedArray> fixed_array_values_copy =
511 isolate->factory()->CopyFixedArray(fixed_array_values);
512 copied_elements_values = fixed_array_values_copy;
513 for (int i = 0; i < fixed_array_values->length(); i++) {
514 Object* current = fixed_array_values->get(i);
515 if (current->IsFixedArray()) {
516 // The value contains the constant_properties of a
517 // simple object or array literal.
518 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
519 Handle<Object> result =
520 CreateLiteralBoilerplate(isolate, literals, fa);
521 if (result.is_null()) return result;
522 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000523 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000524 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000525 }
526 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000527 object->set_elements(*copied_elements_values);
528 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000529
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000530 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000531 // on or the object is larger than the threshold.
532 if (!FLAG_smi_only_arrays &&
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000533 constant_elements_values->length() < kSmiLiteralMinimumLength) {
534 ElementsKind elements_kind = object->GetElementsKind();
535 if (!IsFastObjectElementsKind(elements_kind)) {
536 if (IsFastHoleyElementsKind(elements_kind)) {
537 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS,
538 isolate)->IsFailure());
539 } else {
540 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
541 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000542 }
543 }
544
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000545 object->ValidateElements();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000546 return object;
547}
548
549
550static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000552 Handle<FixedArray> literals,
553 Handle<FixedArray> array) {
554 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000555 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000557 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 return CreateObjectLiteralBoilerplate(isolate,
559 literals,
560 elements,
561 true,
562 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000563 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 return CreateObjectLiteralBoilerplate(isolate,
565 literals,
566 elements,
567 false,
568 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000569 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000570 return Runtime::CreateArrayLiteralBoilerplate(
571 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000572 default:
573 UNREACHABLE();
574 return Handle<Object>::null();
575 }
576}
577
578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000579RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000582 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000583 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000584 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000585 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
587 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateObjectLiteralBoilerplate(isolate,
593 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 should_have_fast_elements,
596 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000597 if (boilerplate.is_null()) return Failure::Exception();
598 // Update the functions literal and return the boilerplate.
599 literals->set(literals_index, *boilerplate);
600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000608 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000609 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000610 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000611 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
613 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614
615 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 Handle<Object> boilerplate(literals->get(literals_index), isolate);
617 if (*boilerplate == isolate->heap()->undefined_value()) {
618 boilerplate = CreateObjectLiteralBoilerplate(isolate,
619 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000620 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 should_have_fast_elements,
622 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 if (boilerplate.is_null()) return Failure::Exception();
624 // Update the functions literal and return the boilerplate.
625 literals->set(literals_index, *boilerplate);
626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000628}
629
630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000631RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000634 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000635 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000636 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000637
638 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 Handle<Object> boilerplate(literals->get(literals_index), isolate);
640 if (*boilerplate == isolate->heap()->undefined_value()) {
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000641 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000642 boilerplate =
643 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644 if (boilerplate.is_null()) return Failure::Exception();
645 // Update the functions literal and return the boilerplate.
646 literals->set(literals_index, *boilerplate);
647 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000649}
650
651
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000653 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000654 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000655 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000656 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000657 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000658
659 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 Handle<Object> boilerplate(literals->get(literals_index), isolate);
661 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000662 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000663 boilerplate =
664 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000665 if (boilerplate.is_null()) return Failure::Exception();
666 // Update the functions literal and return the boilerplate.
667 literals->set(literals_index, *boilerplate);
668 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000669 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000670 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000671 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000672 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000673
674 JSObject* boilerplate_object = JSObject::cast(*boilerplate);
675 AllocationSiteMode mode = AllocationSiteInfo::GetMode(
676 boilerplate_object->GetElementsKind());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000677 if (mode == TRACK_ALLOCATION_SITE) {
678 return isolate->heap()->CopyJSObjectWithAllocationSite(boilerplate_object);
679 }
680
681 return isolate->heap()->CopyJSObject(boilerplate_object);
682}
683
684
685RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) {
686 NoHandleAllocation ha(isolate);
687 ASSERT(args.length() == 0);
688 return isolate->heap()->AllocateSymbol();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000689}
690
691
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000692RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
693 ASSERT(args.length() == 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000694 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000695 Object* prototype = args[1];
696 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000697 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000698 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
699}
700
701
lrn@chromium.org34e60782011-09-15 07:25:40 +0000702RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
703 ASSERT(args.length() == 4);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000704 CONVERT_ARG_CHECKED(JSReceiver, handler, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000705 Object* call_trap = args[1];
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000706 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy());
707 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708 Object* prototype = args[3];
709 Object* used_prototype =
710 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
711 return isolate->heap()->AllocateJSFunctionProxy(
712 handler, call_trap, construct_trap, used_prototype);
713}
714
715
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000716RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
717 ASSERT(args.length() == 1);
718 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000719 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000720}
721
722
lrn@chromium.org34e60782011-09-15 07:25:40 +0000723RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
724 ASSERT(args.length() == 1);
725 Object* obj = args[0];
726 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
727}
728
729
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000733 return proxy->handler();
734}
735
736
lrn@chromium.org34e60782011-09-15 07:25:40 +0000737RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
738 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000739 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000740 return proxy->call_trap();
741}
742
743
744RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
745 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000746 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000747 return proxy->construct_trap();
748}
749
750
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000751RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
752 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000753 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000754 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000755 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000756}
757
758
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000759RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
760 HandleScope scope(isolate);
761 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000762 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000763 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
764 holder->set_table(*table);
765 return *holder;
766}
767
768
769RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
770 HandleScope scope(isolate);
771 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000772 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000773 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000774 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
775 table = ObjectHashSetAdd(table, key);
776 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000777 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778}
779
780
781RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
782 HandleScope scope(isolate);
783 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000784 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000785 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000786 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
787 return isolate->heap()->ToBoolean(table->Contains(*key));
788}
789
790
791RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
792 HandleScope scope(isolate);
793 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000794 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000795 Handle<Object> key(args[1], isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
797 table = ObjectHashSetRemove(table, key);
798 holder->set_table(*table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000799 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000800}
801
802
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000803RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) {
804 HandleScope scope(isolate);
805 ASSERT(args.length() == 1);
806 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
807 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
808 return Smi::FromInt(table->NumberOfElements());
809}
810
811
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000812RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
813 HandleScope scope(isolate);
814 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000815 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000816 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
817 holder->set_table(*table);
818 return *holder;
819}
820
821
822RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
823 HandleScope scope(isolate);
824 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000825 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000826 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
827 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000828 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000829 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
830}
831
832
833RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) {
834 HandleScope scope(isolate);
835 ASSERT(args.length() == 2);
836 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
837 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
838 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000839 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000840 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
841}
842
843
844RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) {
845 HandleScope scope(isolate);
846 ASSERT(args.length() == 2);
847 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
848 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
849 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000850 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000851 Handle<ObjectHashTable> new_table =
852 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value());
853 holder->set_table(*new_table);
854 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000855}
856
857
858RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
859 HandleScope scope(isolate);
860 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000861 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000862 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
863 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000864 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
865 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
866 holder->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000867 return isolate->heap()->undefined_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000868}
869
870
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) {
872 HandleScope scope(isolate);
873 ASSERT(args.length() == 1);
874 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
875 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
876 return Smi::FromInt(table->NumberOfElements());
877}
878
879
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000880static JSWeakMap* WeakMapInitialize(Isolate* isolate,
881 Handle<JSWeakMap> weakmap) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000882 ASSERT(weakmap->map()->inobject_properties() == 0);
883 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
884 weakmap->set_table(*table);
885 weakmap->set_next(Smi::FromInt(0));
886 return *weakmap;
887}
888
889
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +0000890RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
891 HandleScope scope(isolate);
892 ASSERT(args.length() == 1);
893 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
894 return WeakMapInitialize(isolate, weakmap);
895}
896
897
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000898RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000899 HandleScope scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000900 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000901 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
902 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000903 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000904 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000905 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
906}
907
908
909RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapHas) {
910 HandleScope scope(isolate);
911 ASSERT(args.length() == 2);
912 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
913 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
914 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000915 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000916 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
917}
918
919
920RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapDelete) {
921 HandleScope scope(isolate);
922 ASSERT(args.length() == 2);
923 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
924 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
925 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000926 Handle<Object> lookup(table->Lookup(*key), isolate);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000927 Handle<ObjectHashTable> new_table =
928 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value());
929 weakmap->set_table(*new_table);
930 return isolate->heap()->ToBoolean(!lookup->IsTheHole());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000931}
932
933
934RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
935 HandleScope scope(isolate);
936 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000937 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
938 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000939 Handle<Object> value(args[2], isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000940 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000941 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
942 weakmap->set_table(*new_table);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000943 return isolate->heap()->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000944}
945
946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000947RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000948 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 ASSERT(args.length() == 1);
950 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952 return JSObject::cast(obj)->class_name();
953}
954
ager@chromium.org7c537e22008-10-16 08:43:32 +0000955
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000956RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000957 NoHandleAllocation ha(isolate);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000958 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000959 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000960 Object* obj = input_obj;
961 // We don't expect access checks to be needed on JSProxy objects.
962 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000963 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000964 if (obj->IsAccessCheckNeeded() &&
965 !isolate->MayNamedAccess(JSObject::cast(obj),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000966 isolate->heap()->proto_string(),
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000967 v8::ACCESS_GET)) {
968 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
969 return isolate->heap()->undefined_value();
970 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000971 obj = obj->GetPrototype(isolate);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000972 } while (obj->IsJSObject() &&
973 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000974 return obj;
975}
976
977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000978RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000979 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 ASSERT(args.length() == 2);
981 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
982 Object* O = args[0];
983 Object* V = args[1];
984 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000985 Object* prototype = V->GetPrototype(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 if (prototype->IsNull()) return isolate->heap()->false_value();
987 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 V = prototype;
989 }
990}
991
992
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000993static bool CheckAccessException(Object* callback,
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000994 v8::AccessType access_type) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000995 if (callback->IsAccessorInfo()) {
996 AccessorInfo* info = AccessorInfo::cast(callback);
997 return
998 (access_type == v8::ACCESS_HAS &&
999 (info->all_can_read() || info->all_can_write())) ||
1000 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
1001 (access_type == v8::ACCESS_SET && info->all_can_write());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001002 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001003 return false;
1004}
1005
1006
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001007template<class Key>
1008static bool CheckGenericAccess(
1009 JSObject* receiver,
1010 JSObject* holder,
1011 Key key,
1012 v8::AccessType access_type,
1013 bool (Isolate::*mayAccess)(JSObject*, Key, v8::AccessType)) {
1014 Isolate* isolate = receiver->GetIsolate();
1015 for (JSObject* current = receiver;
1016 true;
1017 current = JSObject::cast(current->GetPrototype())) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001018 if (current->IsAccessCheckNeeded() &&
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001019 !(isolate->*mayAccess)(current, key, access_type)) {
1020 return false;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001021 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001022 if (current == holder) break;
1023 }
1024 return true;
1025}
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001026
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001027
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001028enum AccessCheckResult {
1029 ACCESS_FORBIDDEN,
1030 ACCESS_ALLOWED,
1031 ACCESS_ABSENT
1032};
1033
1034
1035static AccessCheckResult CheckElementAccess(
1036 JSObject* obj,
1037 uint32_t index,
1038 v8::AccessType access_type) {
1039 // TODO(1095): we should traverse hidden prototype hierachy as well.
1040 if (CheckGenericAccess(
1041 obj, obj, index, access_type, &Isolate::MayIndexedAccess)) {
1042 return ACCESS_ALLOWED;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001043 }
1044
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001045 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1046 return ACCESS_FORBIDDEN;
1047}
1048
1049
1050static AccessCheckResult CheckPropertyAccess(
1051 JSObject* obj,
1052 String* name,
1053 v8::AccessType access_type) {
1054 uint32_t index;
1055 if (name->AsArrayIndex(&index)) {
1056 return CheckElementAccess(obj, index, access_type);
1057 }
1058
1059 LookupResult lookup(obj->GetIsolate());
1060 obj->LocalLookup(name, &lookup, true);
1061
1062 if (!lookup.IsProperty()) return ACCESS_ABSENT;
1063 if (CheckGenericAccess<Object*>(
1064 obj, lookup.holder(), name, access_type, &Isolate::MayNamedAccess)) {
1065 return ACCESS_ALLOWED;
1066 }
1067
1068 // Access check callback denied the access, but some properties
1069 // can have a special permissions which override callbacks descision
1070 // (currently see v8::AccessControl).
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001071 // API callbacks can have per callback access exceptions.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001072 switch (lookup.type()) {
1073 case CALLBACKS:
1074 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1075 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001076 }
1077 break;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001078 case INTERCEPTOR:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001079 // If the object has an interceptor, try real named properties.
1080 // Overwrite the result to fetch the correct property later.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001081 lookup.holder()->LookupRealNamedProperty(name, &lookup);
1082 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) {
1083 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) {
1084 return ACCESS_ALLOWED;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001085 }
1086 }
1087 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001088 default:
1089 break;
1090 }
1091
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001092 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type);
1093 return ACCESS_FORBIDDEN;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001094}
1095
1096
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001097// Enumerator used as indices into the array returned from GetOwnProperty
1098enum PropertyDescriptorIndices {
1099 IS_ACCESSOR_INDEX,
1100 VALUE_INDEX,
1101 GETTER_INDEX,
1102 SETTER_INDEX,
1103 WRITABLE_INDEX,
1104 ENUMERABLE_INDEX,
1105 CONFIGURABLE_INDEX,
1106 DESCRIPTOR_SIZE
1107};
1108
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001109
1110static MaybeObject* GetOwnProperty(Isolate* isolate,
1111 Handle<JSObject> obj,
1112 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 Heap* heap = isolate->heap();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001114 // Due to some WebKit tests, we want to make sure that we do not log
1115 // more than one access failure here.
1116 switch (CheckPropertyAccess(*obj, *name, v8::ACCESS_HAS)) {
1117 case ACCESS_FORBIDDEN: return heap->false_value();
1118 case ACCESS_ALLOWED: break;
1119 case ACCESS_ABSENT: return heap->undefined_value();
1120 }
1121
1122 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name);
1123 if (attrs == ABSENT) return heap->undefined_value();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001124 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name);
1125 Handle<AccessorPair> accessors(raw_accessors, isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001127 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001128 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
1129 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001130 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001131
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001132 if (raw_accessors == NULL) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001133 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
1134 // GetProperty does access check.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001135 Handle<Object> value = GetProperty(isolate, obj, name);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001136 if (value.is_null()) return Failure::Exception();
1137 elms->set(VALUE_INDEX, *value);
1138 } else {
1139 // Access checks are performed for both accessors separately.
1140 // When they fail, the respective field is not set in the descriptor.
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001141 Object* getter = accessors->GetComponent(ACCESSOR_GETTER);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001142 Object* setter = accessors->GetComponent(ACCESSOR_SETTER);
1143 if (!getter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_GET)) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001144 elms->set(GETTER_INDEX, getter);
1145 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001146 if (!setter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_SET)) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001147 elms->set(SETTER_INDEX, setter);
1148 }
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +00001149 }
1150
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001151 return *isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001152}
1153
1154
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001155// Returns an array with the property description:
1156// if args[1] is not a property on args[0]
1157// returns undefined
1158// if args[1] is a data property on args[0]
1159// [false, value, Writeable, Enumerable, Configurable]
1160// if args[1] is an accessor on args[0]
1161// [true, GetFunction, SetFunction, Enumerable, Configurable]
1162RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1163 ASSERT(args.length() == 2);
1164 HandleScope scope(isolate);
1165 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1166 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1167 return GetOwnProperty(isolate, obj, name);
1168}
1169
1170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001171RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001172 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001173 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001174 return obj->PreventExtensions();
1175}
1176
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001178RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001179 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001180 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001181 if (obj->IsJSGlobalProxy()) {
1182 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001184 ASSERT(proto->IsJSGlobalObject());
1185 obj = JSObject::cast(proto);
1186 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001187 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001188}
1189
1190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001191RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001194 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1195 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1196 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001197 Handle<Object> result =
1198 RegExpImpl::Compile(re, pattern, flags, isolate->runtime_zone());
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001199 if (result.is_null()) return Failure::Exception();
1200 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001205 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001207 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001208 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209}
1210
1211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001212RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 ASSERT(args.length() == 1);
1214 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001215 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001222 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1223 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001224 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1225 InstanceType type = templ->map()->instance_type();
1226 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1227 type == OBJECT_TEMPLATE_INFO_TYPE);
1228 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001229 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001230 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1231 } else {
1232 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1233 }
1234 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235}
1236
1237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001238RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001239 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001240 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001241 Map* old_map = object->map();
1242 bool needs_access_checks = old_map->is_access_check_needed();
1243 if (needs_access_checks) {
1244 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001245 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001246 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001247 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00001248
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001249 new_map->set_is_access_check_needed(false);
1250 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00001251 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001252 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001253}
1254
1255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001256RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001257 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001258 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001259 Map* old_map = object->map();
1260 if (!old_map->is_access_check_needed()) {
1261 // Copy map so it won't interfere constructor's initial map.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001262 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00001263 MaybeObject* maybe_new_map = old_map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001264 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org32912102009-01-16 10:38:43 +00001265
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001266 new_map->set_is_access_check_needed(true);
1267 object->set_map(new_map);
ager@chromium.org32912102009-01-16 10:38:43 +00001268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001270}
1271
1272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001273static Failure* ThrowRedeclarationError(Isolate* isolate,
1274 const char* type,
1275 Handle<String> name) {
1276 HandleScope scope(isolate);
1277 Handle<Object> type_handle =
1278 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 Handle<Object> args[2] = { type_handle, name };
1280 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1282 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283}
1284
1285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001286RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001287 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 HandleScope scope(isolate);
1289 Handle<GlobalObject> global = Handle<GlobalObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001290 isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291
ager@chromium.org3811b432009-10-28 14:53:37 +00001292 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001293 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001294 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 // Traverse the name/value pairs and set the properties.
1297 int length = pairs->length();
1298 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
1303 // We have to declare a global const property. To capture we only
1304 // assign to it when evaluating the assignment for "const x =
1305 // <expr>" the initial value is the hole.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001306 bool is_var = value->IsUndefined();
1307 bool is_const = value->IsTheHole();
1308 bool is_function = value->IsSharedFunctionInfo();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001309 ASSERT(is_var + is_const + is_function == 1);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001310
1311 if (is_var || is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 // Lookup the property in the global object, and don't set the
1313 // value of the variable if the property is already there.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001314 // Do the lookup locally only, see ES5 erratum.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 LookupResult lookup(isolate);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001316 if (FLAG_es52_globals) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001317 global->LocalLookup(*name, &lookup, true);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001318 } else {
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00001319 global->Lookup(*name, &lookup);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001320 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001321 if (lookup.IsFound()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 // We found an existing property. Unless it was an interceptor
1323 // that claims the property is absent, skip this declaration.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001324 if (!lookup.IsInterceptor()) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001325 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001326 if (attributes != ABSENT) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 // Fall-through and introduce the absent property by using
1328 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001330 } else if (is_function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001332 Handle<SharedFunctionInfo> shared =
1333 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 Handle<JSFunction> function =
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001335 isolate->factory()->NewFunctionFromSharedFunctionInfo(
1336 shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337 value = function;
1338 }
1339
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001340 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001341 global->LocalLookup(*name, &lookup, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001343 // Compute the property attributes. According to ECMA-262,
1344 // the property must be non-configurable except in eval.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001345 int attr = NONE;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001346 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001347 if (!is_eval) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001348 attr |= DONT_DELETE;
1349 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001350 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001351 if (is_const || (is_native && is_function)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 attr |= READ_ONLY;
1353 }
1354
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001355 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1356
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001357 if (!lookup.IsFound() || is_function) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001358 // If the local property exists, check that we can reconfigure it
1359 // as required for function declarations.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001360 if (lookup.IsFound() && lookup.IsDontDelete()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001361 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001362 lookup.IsPropertyCallbacks()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001363 return ThrowRedeclarationError(isolate, "function", name);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001364 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001365 // If the existing property is not configurable, keep its attributes.
1366 attr = lookup.GetAttributes();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001367 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001368 // Define or redefine own property.
1369 RETURN_IF_EMPTY_HANDLE(isolate,
1370 JSObject::SetLocalPropertyIgnoreAttributes(
1371 global, name, value, static_cast<PropertyAttributes>(attr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001373 // Do a [[Put]] on the existing (own) property.
1374 RETURN_IF_EMPTY_HANDLE(isolate,
1375 JSObject::SetProperty(
1376 global, name, value, static_cast<PropertyAttributes>(attr),
1377 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378 }
1379 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001380
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 ASSERT(!isolate->has_pending_exception());
1382 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383}
1384
1385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001386RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001388 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001390 // Declarations are always made in a function or native context. In the
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 // case of eval code, the context passed is the context of the caller,
1392 // which may be some nested context and not the declaration context.
1393 RUNTIME_ASSERT(args[0]->IsContext());
1394 Handle<Context> context(Context::cast(args[0])->declaration_context());
1395
ager@chromium.org7c537e22008-10-16 08:43:32 +00001396 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001397 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001398 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 int index;
1402 PropertyAttributes attributes;
1403 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001404 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001405 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001406 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407
1408 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 // The name was declared before; check for conflicting re-declarations.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001410 // Note: this is actually inconsistent with what happens for globals (where
1411 // we silently ignore such declarations).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1413 // Functions are not read-only.
1414 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1415 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 }
1418
1419 // Initialize it if necessary.
1420 if (*initial_value != NULL) {
1421 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 ASSERT(holder.is_identical_to(context));
1423 if (((attributes & READ_ONLY) == 0) ||
1424 context->get(index)->IsTheHole()) {
1425 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 }
1427 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 // Slow case: The property is in the context extension object of a
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001429 // function context or the global object of a native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001430 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001431 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001433 JSReceiver::SetProperty(object, name, initial_value, mode,
1434 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 }
1436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001439 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 // "declared" in the function context's extension context or as a
1441 // property of the the global object.
1442 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001443 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001445 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 // Context extension objects are allocated lazily.
1447 ASSERT(context->IsFunctionContext());
1448 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001449 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001450 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001451 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001452 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453
ager@chromium.org7c537e22008-10-16 08:43:32 +00001454 // Declare the property by setting it to the initial value if provided,
1455 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1456 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001459 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001460 // Declaring a const context slot is a conflicting declaration if
1461 // there is a callback with that name in a prototype. It is
1462 // allowed to introduce const variables in
1463 // JSContextExtensionObjects. They are treated specially in
1464 // SetProperty and no setters are invoked for those since they are
1465 // not real JSObjects.
1466 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001468 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001469 object->Lookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001470 if (lookup.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001472 }
1473 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001474 if (object->IsJSGlobalObject()) {
1475 // Define own property on the global object.
1476 RETURN_IF_EMPTY_HANDLE(isolate,
1477 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
1478 } else {
1479 RETURN_IF_EMPTY_HANDLE(isolate,
1480 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
1481 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001482 }
1483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485}
1486
1487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001488RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001489 NoHandleAllocation nha(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001490 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001491 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493
1494 // Determine if we need to assign to the variable if it already
1495 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001496 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1497 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001499 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001500 GlobalObject* global = isolate->context()->global_object();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001501 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001502 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1503 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1504 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505
1506 // According to ECMA-262, section 12.2, page 62, the property must
1507 // not be deletable.
1508 PropertyAttributes attributes = DONT_DELETE;
1509
1510 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001511 // there, there is a property with this name in the prototype chain.
1512 // We follow Safari and Firefox behavior and only set the property
1513 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001514 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001515 // Note that objects can have hidden prototypes, so we need to traverse
1516 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001517 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001518 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001519 JSObject::cast(object)->LocalLookup(*name, &lookup, true);
1520 if (lookup.IsInterceptor()) {
1521 HandleScope handle_scope(isolate);
1522 PropertyAttributes intercepted =
1523 lookup.holder()->GetPropertyAttribute(*name);
1524 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1525 // Found an interceptor that's not read only.
1526 if (assign) {
1527 return lookup.holder()->SetProperty(
1528 &lookup, *name, args[2], attributes, strict_mode_flag);
1529 } else {
1530 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001531 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001532 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533 }
1534
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 // Reload global in case the loop above performed a GC.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001536 global = isolate->context()->global_object();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001538 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001540 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541}
1542
1543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001544RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 // All constants are declared with an initial value. The name
1546 // of the constant is the first argument and the initial value
1547 // is the second.
1548 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001549 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 Handle<Object> value = args.at<Object>(1);
1551
1552 // Get the current global object from top.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001553 GlobalObject* global = isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554
1555 // According to ECMA-262, section 12.2, page 62, the property must
1556 // not be deletable. Since it's a const, it must be READ_ONLY too.
1557 PropertyAttributes attributes =
1558 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1559
1560 // Lookup the property locally in the global object. If it isn't
1561 // there, we add the property and take special precautions to always
1562 // add it as a local property even in case of callbacks in the
1563 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001564 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001565 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 global->LocalLookup(*name, &lookup);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001567 if (!lookup.IsFound()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001568 return global->SetLocalPropertyIgnoreAttributes(*name,
1569 *value,
1570 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 }
1572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 HandleScope handle_scope(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001577 Handle<GlobalObject> global(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001579 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // property through an interceptor and only do it if it's
1581 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001582 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001583 RETURN_IF_EMPTY_HANDLE(
1584 isolate,
1585 JSReceiver::SetProperty(global, name, value, attributes,
1586 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 return *value;
1588 }
1589
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001590 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 // constant. For now, we determine this by checking if the
1592 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 // Strict mode handling not needed (const is disallowed in strict mode).
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001594 if (lookup.IsField()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 FixedArray* properties = global->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001596 int index = lookup.GetFieldIndex().field_index();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001597 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 properties->set(index, *value);
1599 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001600 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001601 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1602 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001603 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 }
1605 } else {
1606 // Ignore re-initialization of constants that have already been
1607 // assigned a function value.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001608 ASSERT(lookup.IsReadOnly() && lookup.IsConstantFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609 }
1610
1611 // Use the set value as the result of the operation.
1612 return *value;
1613}
1614
1615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001616RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001617 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 ASSERT(args.length() == 3);
1619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001623 // Initializations are always done in a function or native context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 RUNTIME_ASSERT(args[1]->IsContext());
1625 Handle<Context> context(Context::cast(args[1])->declaration_context());
1626
1627 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
1629 int index;
1630 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001631 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001632 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001633 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001634 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 ASSERT(holder->IsContext());
1638 // Property was found in a context. Perform the assignment if we
1639 // found some non-constant or an uninitialized constant.
1640 Handle<Context> context = Handle<Context>::cast(holder);
1641 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1642 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 }
1644 return *value;
1645 }
1646
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001647 // The property could not be found, we introduce it as a property of the
1648 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001649 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001650 Handle<JSObject> global = Handle<JSObject>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001651 isolate->context()->global_object());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001652 // Strict mode not needed (const disallowed in strict mode).
1653 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001655 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 return *value;
1657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001659 // The property was present in some function's context extension object,
1660 // as a property on the subject of a with, or as a property of the global
1661 // object.
1662 //
1663 // In most situations, eval-introduced consts should still be present in
1664 // the context extension object. However, because declaration and
1665 // initialization are separate, the property might have been deleted
1666 // before we reach the initialization point.
1667 //
1668 // Example:
1669 //
1670 // function f() { eval("delete x; const x;"); }
1671 //
1672 // In that case, the initialization behaves like a normal assignment.
1673 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001675 if (*object == context->extension()) {
1676 // This is the property that was introduced by the const declaration.
1677 // Set it if it hasn't been set before. NOTE: We cannot use
1678 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001679 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001680 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001681 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1683
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001684 if (lookup.IsField()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 FixedArray* properties = object->properties();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00001686 int index = lookup.GetFieldIndex().field_index();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001690 } else if (lookup.IsNormal()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
1699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001702 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001704 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 return *value;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001718 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001721 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001723 }
1724 return *object;
1725}
1726
1727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001737 RUNTIME_ASSERT(index >= 0);
1738 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001740 Handle<Object> result = RegExpImpl::Exec(regexp,
1741 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001742 index,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001743 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001744 if (result.is_null()) return Failure::Exception();
1745 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001746}
1747
1748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001749RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001751 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001752 if (elements_count < 0 ||
1753 elements_count > FixedArray::kMaxLength ||
1754 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001756 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 Object* new_object;
1758 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001760 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1761 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1764 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001765 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1766 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 {
1768 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001770 reinterpret_cast<HeapObject*>(new_object)->
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001771 set_map(isolate->native_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001772 }
1773 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001775 array->set_elements(elements);
1776 array->set_length(Smi::FromInt(elements_count));
1777 // Write in-object properties after the length of the array.
1778 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1779 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1780 return array;
1781}
1782
1783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001784RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785 AssertNoAllocation no_alloc;
1786 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001787 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1788 CONVERT_ARG_CHECKED(String, source, 1);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001789 // If source is the empty string we set it to "(?:)" instead as
1790 // suggested by ECMA-262, 5th, section 15.10.4.1.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001791 if (source->length() == 0) source = isolate->heap()->query_colon_string();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792
1793 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001795
1796 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798
1799 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001800 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001801
1802 Map* map = regexp->map();
1803 Object* constructor = map->constructor();
1804 if (constructor->IsJSFunction() &&
1805 JSFunction::cast(constructor)->initial_map() == map) {
1806 // If we still have the original map, set in-object properties directly.
1807 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001808 // Both true and false are immovable immortal objects so no need for write
1809 // barrier.
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1814 regexp->InObjectPropertyAtPut(
1815 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001816 regexp->InObjectPropertyAtPut(
1817 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001818 return regexp;
1819 }
1820
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001821 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001822 PropertyAttributes final =
1823 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1824 PropertyAttributes writable =
1825 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827 MaybeObject* result;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001828 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_string(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001829 source,
1830 final);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001831 // TODO(jkummerow): Turn these back into ASSERTs when we can be certain
1832 // that it never fires in Release mode in the wild.
1833 CHECK(!result->IsFailure());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001834 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_string(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001835 global,
1836 final);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001837 CHECK(!result->IsFailure());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838 result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001839 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_string(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001840 ignoreCase,
1841 final);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001842 CHECK(!result->IsFailure());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001843 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_string(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001844 multiline,
1845 final);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001846 CHECK(!result->IsFailure());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001847 result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001848 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_string(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001849 Smi::FromInt(0),
1850 writable);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001851 CHECK(!result->IsFailure());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001852 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001853 return regexp;
1854}
1855
1856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001859 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001860 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001861 // This is necessary to enable fast checks for absence of elements
1862 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001863 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001864 return Smi::FromInt(0);
1865}
1866
1867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1869 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001871 Builtins::Name builtin_name) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001872 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1874 Handle<JSFunction> optimized =
1875 isolate->factory()->NewFunction(key,
1876 JS_OBJECT_TYPE,
1877 JSObject::kHeaderSize,
1878 code,
1879 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001880 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001881 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001882 return optimized;
1883}
1884
1885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001886RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001888 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001889 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001890
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001891 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1892 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1893 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1894 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1895 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1896 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1897 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001898
1899 return *holder;
1900}
1901
1902
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001903RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001904 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001905 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001906
1907 if (!callable->IsJSFunction()) {
1908 HandleScope scope(isolate);
1909 bool threw = false;
1910 Handle<Object> delegate =
1911 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1912 if (threw) return Failure::Exception();
1913 callable = JSFunction::cast(*delegate);
1914 }
1915 JSFunction* function = JSFunction::cast(callable);
1916
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001917 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001918 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001919 return isolate->heap()->undefined_value();
1920 }
1921 // Returns undefined for strict or native functions, or
1922 // the associated global receiver for "normal" functions.
1923
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001924 Context* native_context =
1925 function->context()->global_object()->native_context();
1926 return native_context->global_object()->global_receiver();
ager@chromium.org357bf652010-04-12 11:30:10 +00001927}
1928
1929
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001930RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001931 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001933 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001934 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935 Handle<String> pattern = args.at<String>(2);
1936 Handle<String> flags = args.at<String>(3);
1937
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001938 // Get the RegExp function from the context in the literals array.
1939 // This is the RegExp function from the context in which the
1940 // function was created. We do not use the RegExp function from the
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001941 // current native context because this might be the RegExp function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001942 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001943 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001944 Handle<JSFunction>(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001945 JSFunction::NativeContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001946 // Compute the regular expression literal.
1947 bool has_pending_exception;
1948 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001949 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1950 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 return Failure::Exception();
1954 }
1955 literals->set(index, *regexp);
1956 return *regexp;
1957}
1958
1959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001960RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001961 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 ASSERT(args.length() == 1);
1963
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001964 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001965 return f->shared()->name();
1966}
1967
1968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001969RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001970 NoHandleAllocation ha(isolate);
ager@chromium.org236ad962008-09-25 09:45:57 +00001971 ASSERT(args.length() == 2);
1972
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001973 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1974 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001975 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001976 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001977}
1978
1979
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001980RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001981 NoHandleAllocation ha(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001982 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001983 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001984 return isolate->heap()->ToBoolean(
1985 f->shared()->name_should_print_as_anonymous());
1986}
1987
1988
1989RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001990 NoHandleAllocation ha(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001991 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001992 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001993 f->shared()->set_name_should_print_as_anonymous(true);
1994 return isolate->heap()->undefined_value();
1995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001999 NoHandleAllocation ha(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002000 ASSERT(args.length() == 1);
2001
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002002 CONVERT_ARG_CHECKED(JSFunction, f, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002003 f->RemovePrototype();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002004
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002010 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002011 ASSERT(args.length() == 1);
2012
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002013 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002014 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2015 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016
2017 return *GetScriptWrapper(Handle<Script>::cast(script));
2018}
2019
2020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002022 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 ASSERT(args.length() == 1);
2024
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002025 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002026 Handle<SharedFunctionInfo> shared(f->shared());
2027 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002028}
2029
2030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002031RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002032 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033 ASSERT(args.length() == 1);
2034
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002035 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 int pos = fun->shared()->start_position();
2037 return Smi::FromInt(pos);
2038}
2039
2040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002041RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002042 ASSERT(args.length() == 2);
2043
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002044 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2046
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002047 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2048
2049 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002050 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002055 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056 ASSERT(args.length() == 2);
2057
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002058 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2059 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062}
2063
2064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002065RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002066 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 ASSERT(args.length() == 2);
2068
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002069 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2070 CONVERT_SMI_ARG_CHECKED(length, 1);
2071 fun->shared()->set_length(length);
2072 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073}
2074
2075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002076RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002077 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 ASSERT(args.length() == 2);
2079
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002080 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002081 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002082 Object* obj;
2083 { MaybeObject* maybe_obj =
2084 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2085 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087 return args[0]; // return TOS
2088}
2089
2090
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002091RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002092 NoHandleAllocation ha(isolate);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002093 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002094 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002095
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002096 String* name = isolate->heap()->prototype_string();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002097
2098 if (function->HasFastProperties()) {
2099 // Construct a new field descriptor with updated attributes.
2100 DescriptorArray* instance_desc = function->map()->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002101
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002102 int index = instance_desc->SearchWithCache(name, function->map());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002103 ASSERT(index != DescriptorArray::kNotFound);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002104 PropertyDetails details = instance_desc->GetDetails(index);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002105
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002106 CallbacksDescriptor new_desc(name,
2107 instance_desc->GetValue(index),
2108 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002109 details.descriptor_index());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002110
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002111 // Create a new map featuring the new field descriptors array.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002112 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002113 MaybeObject* maybe_map =
2114 function->map()->CopyReplaceDescriptor(
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002115 instance_desc, &new_desc, index, OMIT_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002116 if (!maybe_map->To(&new_map)) return maybe_map;
2117
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002118 function->set_map(new_map);
2119 } else { // Dictionary properties.
2120 // Directly manipulate the property details.
2121 int entry = function->property_dictionary()->FindEntry(name);
2122 ASSERT(entry != StringDictionary::kNotFound);
2123 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2124 PropertyDetails new_details(
2125 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2126 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002127 details.dictionary_index());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002128 function->property_dictionary()->DetailsAtPut(entry, new_details);
2129 }
2130 return function;
2131}
2132
2133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002134RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002135 NoHandleAllocation ha(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002136 ASSERT(args.length() == 1);
2137
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002138 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002139 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002140}
2141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002143RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002144 NoHandleAllocation ha(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002145 ASSERT(args.length() == 1);
2146
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002147 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002148 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002149}
2150
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002152RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002153 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 ASSERT(args.length() == 2);
2155
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002156 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 Handle<Object> code = args.at<Object>(1);
2158
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002159 if (code->IsNull()) return *target;
2160 RUNTIME_ASSERT(code->IsJSFunction());
2161 Handle<JSFunction> source = Handle<JSFunction>::cast(code);
2162 Handle<SharedFunctionInfo> target_shared(target->shared());
2163 Handle<SharedFunctionInfo> source_shared(source->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002165 if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002166 return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 }
2168
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002169 // Set the code, scope info, formal parameter count, and the length
2170 // of the target shared function info. Set the source code of the
2171 // target function to undefined. SetCode is only used for built-in
2172 // constructors like String, Array, and Object, and some web code
2173 // doesn't like seeing source code for constructors.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002174 target_shared->ReplaceCode(source_shared->code());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002175 target_shared->set_scope_info(source_shared->scope_info());
2176 target_shared->set_length(source_shared->length());
2177 target_shared->set_formal_parameter_count(
2178 source_shared->formal_parameter_count());
2179 target_shared->set_script(isolate->heap()->undefined_value());
2180
2181 // Since we don't store the source we should never optimize this.
2182 target_shared->code()->set_optimizable(false);
2183
2184 // Clear the optimization hints related to the compiled code as these
2185 // are no longer valid when the code is overwritten.
2186 target_shared->ClearThisPropertyAssignmentsInfo();
2187
2188 // Set the code of the target function.
2189 target->ReplaceCode(source_shared->code());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002190 ASSERT(target->next_function_link()->IsUndefined());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002191
2192 // Make sure we get a fresh copy of the literal vector to avoid cross
2193 // context contamination.
2194 Handle<Context> context(source->context());
2195 int number_of_literals = source->NumberOfLiterals();
2196 Handle<FixedArray> literals =
2197 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
2198 if (number_of_literals > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002199 literals->set(JSFunction::kLiteralNativeContextIndex,
2200 context->native_context());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 target->set_context(*context);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002203 target->set_literals(*literals);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002204
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002205 if (isolate->logger()->is_logging_code_events() ||
2206 CpuProfiler::is_profiling(isolate)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002207 isolate->logger()->LogExistingFunction(
2208 source_shared, Handle<Code>(source_shared->code()));
2209 }
2210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 return *target;
2212}
2213
2214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002215RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002216 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002217 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002218 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002219 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220 RUNTIME_ASSERT(num >= 0);
2221 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002223}
2224
2225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2227 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002228 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002229 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002230 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002232 }
2233 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235}
2236
2237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002238RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002239 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240 ASSERT(args.length() == 2);
2241
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002242 CONVERT_ARG_CHECKED(String, subject, 0);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002243 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002244
2245 // Flatten the string. If someone wants to get a char at an index
2246 // in a cons string, it is likely that more indices will be
2247 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002248 Object* flat;
2249 { MaybeObject* maybe_flat = subject->TryFlatten();
2250 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2251 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002252 subject = String::cast(flat);
2253
2254 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 }
2257
2258 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002259}
2260
2261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002262RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002263 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002265 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002266}
2267
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268
2269class FixedArrayBuilder {
2270 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002271 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2272 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002273 length_(0),
2274 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002275 // Require a non-zero initial size. Ensures that doubling the size to
2276 // extend the array will work.
2277 ASSERT(initial_capacity > 0);
2278 }
2279
2280 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2281 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002282 length_(0),
2283 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002284 // Require a non-zero initial size. Ensures that doubling the size to
2285 // extend the array will work.
2286 ASSERT(backing_store->length() > 0);
2287 }
2288
2289 bool HasCapacity(int elements) {
2290 int length = array_->length();
2291 int required_length = length_ + elements;
2292 return (length >= required_length);
2293 }
2294
2295 void EnsureCapacity(int elements) {
2296 int length = array_->length();
2297 int required_length = length_ + elements;
2298 if (length < required_length) {
2299 int new_length = length;
2300 do {
2301 new_length *= 2;
2302 } while (new_length < required_length);
2303 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002304 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 array_->CopyTo(0, *extended_array, 0, length_);
2306 array_ = extended_array;
2307 }
2308 }
2309
2310 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002311 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312 ASSERT(length_ < capacity());
2313 array_->set(length_, value);
2314 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002315 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 }
2317
2318 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 ASSERT(length_ < capacity());
2321 array_->set(length_, value);
2322 length_++;
2323 }
2324
2325 Handle<FixedArray> array() {
2326 return array_;
2327 }
2328
2329 int length() {
2330 return length_;
2331 }
2332
2333 int capacity() {
2334 return array_->length();
2335 }
2336
lrn@chromium.org25156de2010-04-06 13:10:27 +00002337 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002338 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339 target_array->set_length(Smi::FromInt(length_));
2340 return target_array;
2341 }
2342
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002343
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 private:
2345 Handle<FixedArray> array_;
2346 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002347 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002348};
2349
2350
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002351// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002352const int kStringBuilderConcatHelperLengthBits = 11;
2353const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002354
2355template <typename schar>
2356static inline void StringBuilderConcatHelper(String*,
2357 schar*,
2358 FixedArray*,
2359 int);
2360
lrn@chromium.org25156de2010-04-06 13:10:27 +00002361typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2362 StringBuilderSubstringLength;
2363typedef BitField<int,
2364 kStringBuilderConcatHelperLengthBits,
2365 kStringBuilderConcatHelperPositionBits>
2366 StringBuilderSubstringPosition;
2367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368
2369class ReplacementStringBuilder {
2370 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002371 ReplacementStringBuilder(Heap* heap,
2372 Handle<String> subject,
2373 int estimated_part_count)
2374 : heap_(heap),
2375 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002376 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 character_count_(0),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002378 is_ascii_(subject->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 // Require a non-zero initial size. Ensures that doubling the size to
2380 // extend the array will work.
2381 ASSERT(estimated_part_count > 0);
2382 }
2383
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2385 int from,
2386 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002387 ASSERT(from >= 0);
2388 int length = to - from;
2389 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390 if (StringBuilderSubstringLength::is_valid(length) &&
2391 StringBuilderSubstringPosition::is_valid(from)) {
2392 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2393 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002394 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002396 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397 builder->Add(Smi::FromInt(-length));
2398 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 }
2401
2402
2403 void EnsureCapacity(int elements) {
2404 array_builder_.EnsureCapacity(elements);
2405 }
2406
2407
2408 void AddSubjectSlice(int from, int to) {
2409 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 }
2412
2413
2414 void AddString(Handle<String> string) {
2415 int length = string->length();
2416 ASSERT(length > 0);
2417 AddElement(*string);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002418 if (!string->IsOneByteRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 is_ascii_ = false;
2420 }
2421 IncrementCharacterCount(length);
2422 }
2423
2424
2425 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002427 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 }
2429
2430 Handle<String> joined_string;
2431 if (is_ascii_) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002432 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 AssertNoAllocation no_alloc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002434 uint8_t* char_buffer = seq->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 StringBuilderConcatHelper(*subject_,
2436 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002437 *array_builder_.array(),
2438 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002439 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 } else {
2441 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002442 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002443 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 uc16* char_buffer = seq->GetChars();
2445 StringBuilderConcatHelper(*subject_,
2446 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002447 *array_builder_.array(),
2448 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002449 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 }
2451 return joined_string;
2452 }
2453
2454
2455 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002456 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 V8::FatalProcessOutOfMemory("String.replace result too large.");
2458 }
2459 character_count_ += by;
2460 }
2461
lrn@chromium.org25156de2010-04-06 13:10:27 +00002462 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002463 Handle<SeqOneByteString> NewRawOneByteString(int length) {
2464 return heap_->isolate()->factory()->NewRawOneByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002465 }
2466
2467
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2469 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471
2472
2473 void AddElement(Object* element) {
2474 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 ASSERT(array_builder_.capacity() > array_builder_.length());
2476 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 }
2478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002479 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 int character_count_;
2483 bool is_ascii_;
2484};
2485
2486
2487class CompiledReplacement {
2488 public:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002489 explicit CompiledReplacement(Zone* zone)
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002490 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002491
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002492 // Return whether the replacement is simple.
2493 bool Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 int capture_count,
2495 int subject_length);
2496
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002497 // Use Apply only if Compile returned false.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 void Apply(ReplacementStringBuilder* builder,
2499 int match_from,
2500 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002501 int32_t* match);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002502
2503 // Number of distinct parts of the replacement pattern.
2504 int parts() {
2505 return parts_.length();
2506 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002507
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002508 Zone* zone() const { return zone_; }
2509
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 private:
2511 enum PartType {
2512 SUBJECT_PREFIX = 1,
2513 SUBJECT_SUFFIX,
2514 SUBJECT_CAPTURE,
2515 REPLACEMENT_SUBSTRING,
2516 REPLACEMENT_STRING,
2517
2518 NUMBER_OF_PART_TYPES
2519 };
2520
2521 struct ReplacementPart {
2522 static inline ReplacementPart SubjectMatch() {
2523 return ReplacementPart(SUBJECT_CAPTURE, 0);
2524 }
2525 static inline ReplacementPart SubjectCapture(int capture_index) {
2526 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2527 }
2528 static inline ReplacementPart SubjectPrefix() {
2529 return ReplacementPart(SUBJECT_PREFIX, 0);
2530 }
2531 static inline ReplacementPart SubjectSuffix(int subject_length) {
2532 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2533 }
2534 static inline ReplacementPart ReplacementString() {
2535 return ReplacementPart(REPLACEMENT_STRING, 0);
2536 }
2537 static inline ReplacementPart ReplacementSubString(int from, int to) {
2538 ASSERT(from >= 0);
2539 ASSERT(to > from);
2540 return ReplacementPart(-from, to);
2541 }
2542
2543 // If tag <= 0 then it is the negation of a start index of a substring of
2544 // the replacement pattern, otherwise it's a value from PartType.
2545 ReplacementPart(int tag, int data)
2546 : tag(tag), data(data) {
2547 // Must be non-positive or a PartType value.
2548 ASSERT(tag < NUMBER_OF_PART_TYPES);
2549 }
2550 // Either a value of PartType or a non-positive number that is
2551 // the negation of an index into the replacement string.
2552 int tag;
2553 // The data value's interpretation depends on the value of tag:
2554 // tag == SUBJECT_PREFIX ||
2555 // tag == SUBJECT_SUFFIX: data is unused.
2556 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2557 // tag == REPLACEMENT_SUBSTRING ||
2558 // tag == REPLACEMENT_STRING: data is index into array of substrings
2559 // of the replacement string.
2560 // tag <= 0: Temporary representation of the substring of the replacement
2561 // string ranging over -tag .. data.
2562 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2563 // substring objects.
2564 int data;
2565 };
2566
2567 template<typename Char>
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002568 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2569 Vector<Char> characters,
2570 int capture_count,
2571 int subject_length,
2572 Zone* zone) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002573 int length = characters.length();
2574 int last = 0;
2575 for (int i = 0; i < length; i++) {
2576 Char c = characters[i];
2577 if (c == '$') {
2578 int next_index = i + 1;
2579 if (next_index == length) { // No next character!
2580 break;
2581 }
2582 Char c2 = characters[next_index];
2583 switch (c2) {
2584 case '$':
2585 if (i > last) {
2586 // There is a substring before. Include the first "$".
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002587 parts->Add(ReplacementPart::ReplacementSubString(last, next_index),
2588 zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002589 last = next_index + 1; // Continue after the second "$".
2590 } else {
2591 // Let the next substring start with the second "$".
2592 last = next_index;
2593 }
2594 i = next_index;
2595 break;
2596 case '`':
2597 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002598 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002599 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002600 parts->Add(ReplacementPart::SubjectPrefix(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002601 i = next_index;
2602 last = i + 1;
2603 break;
2604 case '\'':
2605 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002606 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002607 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002608 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002609 i = next_index;
2610 last = i + 1;
2611 break;
2612 case '&':
2613 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002614 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002615 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002616 parts->Add(ReplacementPart::SubjectMatch(), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002617 i = next_index;
2618 last = i + 1;
2619 break;
2620 case '0':
2621 case '1':
2622 case '2':
2623 case '3':
2624 case '4':
2625 case '5':
2626 case '6':
2627 case '7':
2628 case '8':
2629 case '9': {
2630 int capture_ref = c2 - '0';
2631 if (capture_ref > capture_count) {
2632 i = next_index;
2633 continue;
2634 }
2635 int second_digit_index = next_index + 1;
2636 if (second_digit_index < length) {
2637 // Peek ahead to see if we have two digits.
2638 Char c3 = characters[second_digit_index];
2639 if ('0' <= c3 && c3 <= '9') { // Double digits.
2640 int double_digit_ref = capture_ref * 10 + c3 - '0';
2641 if (double_digit_ref <= capture_count) {
2642 next_index = second_digit_index;
2643 capture_ref = double_digit_ref;
2644 }
2645 }
2646 }
2647 if (capture_ref > 0) {
2648 if (i > last) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002649 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002650 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002651 ASSERT(capture_ref <= capture_count);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002652 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653 last = next_index + 1;
2654 }
2655 i = next_index;
2656 break;
2657 }
2658 default:
2659 i = next_index;
2660 break;
2661 }
2662 }
2663 }
2664 if (length > last) {
2665 if (last == 0) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002666 // Replacement is simple. Do not use Apply to do the replacement.
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002667 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002669 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 }
2671 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002672 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002673 }
2674
2675 ZoneList<ReplacementPart> parts_;
2676 ZoneList<Handle<String> > replacement_substrings_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002677 Zone* zone_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002678};
2679
2680
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002681bool CompiledReplacement::Compile(Handle<String> replacement,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 int capture_count,
2683 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002684 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002685 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002686 String::FlatContent content = replacement->GetFlatContent();
2687 ASSERT(content.IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002688 bool simple = false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002689 if (content.IsAscii()) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002690 simple = ParseReplacementPattern(&parts_,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002691 content.ToOneByteVector(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002692 capture_count,
2693 subject_length,
2694 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 } else {
2696 ASSERT(content.IsTwoByte());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002697 simple = ParseReplacementPattern(&parts_,
2698 content.ToUC16Vector(),
2699 capture_count,
2700 subject_length,
2701 zone());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002702 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002703 if (simple) return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002707 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 int substring_index = 0;
2709 for (int i = 0, n = parts_.length(); i < n; i++) {
2710 int tag = parts_[i].tag;
2711 if (tag <= 0) { // A replacement string slice.
2712 int from = -tag;
2713 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002714 replacement_substrings_.Add(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002715 isolate->factory()->NewSubString(replacement, from, to), zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 parts_[i].tag = REPLACEMENT_SUBSTRING;
2717 parts_[i].data = substring_index;
2718 substring_index++;
2719 } else if (tag == REPLACEMENT_STRING) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002720 replacement_substrings_.Add(replacement, zone());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721 parts_[i].data = substring_index;
2722 substring_index++;
2723 }
2724 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002725 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002726}
2727
2728
2729void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2730 int match_from,
2731 int match_to,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002732 int32_t* match) {
2733 ASSERT_LT(0, parts_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 for (int i = 0, n = parts_.length(); i < n; i++) {
2735 ReplacementPart part = parts_[i];
2736 switch (part.tag) {
2737 case SUBJECT_PREFIX:
2738 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2739 break;
2740 case SUBJECT_SUFFIX: {
2741 int subject_length = part.data;
2742 if (match_to < subject_length) {
2743 builder->AddSubjectSlice(match_to, subject_length);
2744 }
2745 break;
2746 }
2747 case SUBJECT_CAPTURE: {
2748 int capture = part.data;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002749 int from = match[capture * 2];
2750 int to = match[capture * 2 + 1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002751 if (from >= 0 && to > from) {
2752 builder->AddSubjectSlice(from, to);
2753 }
2754 break;
2755 }
2756 case REPLACEMENT_SUBSTRING:
2757 case REPLACEMENT_STRING:
2758 builder->AddString(replacement_substrings_[part.data]);
2759 break;
2760 default:
2761 UNREACHABLE();
2762 }
2763 }
2764}
2765
2766
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002767void FindAsciiStringIndices(Vector<const uint8_t> subject,
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002768 char pattern,
2769 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002770 unsigned int limit,
2771 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002772 ASSERT(limit > 0);
2773 // Collect indices of pattern in subject using memchr.
2774 // Stop after finding at most limit values.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002775 const uint8_t* subject_start = subject.start();
2776 const uint8_t* subject_end = subject_start + subject.length();
2777 const uint8_t* pos = subject_start;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002778 while (limit > 0) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002779 pos = reinterpret_cast<const uint8_t*>(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002780 memchr(pos, pattern, subject_end - pos));
2781 if (pos == NULL) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002782 indices->Add(static_cast<int>(pos - subject_start), zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002783 pos++;
2784 limit--;
2785 }
2786}
2787
2788
mmassi@chromium.org49a44672012-12-04 13:52:03 +00002789void FindTwoByteStringIndices(const Vector<const uc16> subject,
2790 uc16 pattern,
2791 ZoneList<int>* indices,
2792 unsigned int limit,
2793 Zone* zone) {
2794 ASSERT(limit > 0);
2795 const uc16* subject_start = subject.start();
2796 const uc16* subject_end = subject_start + subject.length();
2797 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) {
2798 if (*pos == pattern) {
2799 indices->Add(static_cast<int>(pos - subject_start), zone);
2800 limit--;
2801 }
2802 }
2803}
2804
2805
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002806template <typename SubjectChar, typename PatternChar>
2807void FindStringIndices(Isolate* isolate,
2808 Vector<const SubjectChar> subject,
2809 Vector<const PatternChar> pattern,
2810 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002811 unsigned int limit,
2812 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002813 ASSERT(limit > 0);
2814 // Collect indices of pattern in subject.
2815 // Stop after finding at most limit values.
2816 int pattern_length = pattern.length();
2817 int index = 0;
2818 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2819 while (limit > 0) {
2820 index = search.Search(subject, index);
2821 if (index < 0) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002822 indices->Add(index, zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002823 index += pattern_length;
2824 limit--;
2825 }
2826}
2827
2828
2829void FindStringIndicesDispatch(Isolate* isolate,
2830 String* subject,
2831 String* pattern,
2832 ZoneList<int>* indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002833 unsigned int limit,
2834 Zone* zone) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002835 {
2836 AssertNoAllocation no_gc;
2837 String::FlatContent subject_content = subject->GetFlatContent();
2838 String::FlatContent pattern_content = pattern->GetFlatContent();
2839 ASSERT(subject_content.IsFlat());
2840 ASSERT(pattern_content.IsFlat());
2841 if (subject_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002842 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002843 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002844 Vector<const uint8_t> pattern_vector =
2845 pattern_content.ToOneByteVector();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002846 if (pattern_vector.length() == 1) {
2847 FindAsciiStringIndices(subject_vector,
2848 pattern_vector[0],
2849 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002850 limit,
2851 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002852 } else {
2853 FindStringIndices(isolate,
2854 subject_vector,
2855 pattern_vector,
2856 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002857 limit,
2858 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002859 }
2860 } else {
2861 FindStringIndices(isolate,
2862 subject_vector,
2863 pattern_content.ToUC16Vector(),
2864 indices,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002865 limit,
2866 zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002867 }
2868 } else {
2869 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002870 if (pattern_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002871 Vector<const uint8_t> pattern_vector =
2872 pattern_content.ToOneByteVector();
mmassi@chromium.org49a44672012-12-04 13:52:03 +00002873 if (pattern_vector.length() == 1) {
2874 FindTwoByteStringIndices(subject_vector,
2875 pattern_vector[0],
2876 indices,
2877 limit,
2878 zone);
2879 } else {
2880 FindStringIndices(isolate,
2881 subject_vector,
2882 pattern_vector,
2883 indices,
2884 limit,
2885 zone);
2886 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002887 } else {
mmassi@chromium.org49a44672012-12-04 13:52:03 +00002888 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector();
2889 if (pattern_vector.length() == 1) {
2890 FindTwoByteStringIndices(subject_vector,
2891 pattern_vector[0],
2892 indices,
2893 limit,
2894 zone);
2895 } else {
2896 FindStringIndices(isolate,
2897 subject_vector,
2898 pattern_vector,
2899 indices,
2900 limit,
2901 zone);
2902 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002903 }
2904 }
2905 }
2906}
2907
2908
2909template<typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002910MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002911 Isolate* isolate,
2912 Handle<String> subject,
2913 Handle<JSRegExp> pattern_regexp,
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00002914 Handle<String> replacement,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002915 Handle<JSArray> last_match_info) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002916 ASSERT(subject->IsFlat());
2917 ASSERT(replacement->IsFlat());
2918
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002919 Zone* zone = isolate->runtime_zone();
2920 ZoneScope zone_space(zone, DELETE_ON_EXIT);
2921 ZoneList<int> indices(8, zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002922 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2923 String* pattern =
2924 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2925 int subject_len = subject->length();
2926 int pattern_len = pattern->length();
2927 int replacement_len = replacement->length();
2928
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002929 FindStringIndicesDispatch(
2930 isolate, *subject, pattern, &indices, 0xffffffff, zone);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002931
2932 int matches = indices.length();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002933 if (matches == 0) return *subject;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002934
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002935 // Detect integer overflow.
2936 int64_t result_len_64 =
2937 (static_cast<int64_t>(replacement_len) -
2938 static_cast<int64_t>(pattern_len)) *
2939 static_cast<int64_t>(matches) +
2940 static_cast<int64_t>(subject_len);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002941 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002942 int result_len = static_cast<int>(result_len_64);
2943
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002944 int subject_pos = 0;
2945 int result_pos = 0;
2946
2947 Handle<ResultSeqString> result;
2948 if (ResultSeqString::kHasAsciiEncoding) {
2949 result = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002950 isolate->factory()->NewRawOneByteString(result_len));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002951 } else {
2952 result = Handle<ResultSeqString>::cast(
2953 isolate->factory()->NewRawTwoByteString(result_len));
2954 }
2955
2956 for (int i = 0; i < matches; i++) {
2957 // Copy non-matched subject content.
2958 if (subject_pos < indices.at(i)) {
2959 String::WriteToFlat(*subject,
2960 result->GetChars() + result_pos,
2961 subject_pos,
2962 indices.at(i));
2963 result_pos += indices.at(i) - subject_pos;
2964 }
2965
2966 // Replace match.
2967 if (replacement_len > 0) {
2968 String::WriteToFlat(*replacement,
2969 result->GetChars() + result_pos,
2970 0,
2971 replacement_len);
2972 result_pos += replacement_len;
2973 }
2974
2975 subject_pos = indices.at(i) + pattern_len;
2976 }
2977 // Add remaining subject content at the end.
2978 if (subject_pos < subject_len) {
2979 String::WriteToFlat(*subject,
2980 result->GetChars() + result_pos,
2981 subject_pos,
2982 subject_len);
2983 }
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00002984
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002985 int32_t match_indices[] = { indices.at(matches - 1),
2986 indices.at(matches - 1) + pattern_len };
2987 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00002988
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002989 return *result;
2990}
2991
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002992
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002993MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002995 Handle<String> subject,
2996 Handle<JSRegExp> regexp,
2997 Handle<String> replacement,
2998 Handle<JSArray> last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 ASSERT(subject->IsFlat());
3000 ASSERT(replacement->IsFlat());
3001
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003002 int capture_count = regexp->CaptureCount();
3003 int subject_length = subject->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 // CompiledReplacement uses zone allocation.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003006 Zone* zone = isolate->runtime_zone();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003007 ZoneScope zonescope(zone, DELETE_ON_EXIT);
3008 CompiledReplacement compiled_replacement(zone);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003009 bool simple_replace = compiled_replacement.Compile(replacement,
3010 capture_count,
3011 subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003012
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003013 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003014 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003015 if (subject->IsOneByteConvertible() &&
3016 replacement->IsOneByteConvertible()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003017 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003018 isolate, subject, regexp, replacement, last_match_info);
3019 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003020 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003021 isolate, subject, regexp, replacement, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003022 }
3023 }
3024
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003025 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003026 if (global_cache.HasException()) return Failure::Exception();
3027
3028 int32_t* current_match = global_cache.FetchNext();
3029 if (current_match == NULL) {
3030 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003031 return *subject;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003032 }
3033
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034 // Guessing the number of parts that the final result string is built
3035 // from. Global regexps can match any number of times, so we guess
3036 // conservatively.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003037 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003038 ReplacementStringBuilder builder(isolate->heap(),
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003039 subject,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003040 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003041
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003042 // Number of parts added by compiled replacement plus preceeding
3043 // string and possibly suffix after last match. It is possible for
3044 // all components to use two elements when encoded as two smis.
3045 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003046
3047 int prev = 0;
3048
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003049 do {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003050 builder.EnsureCapacity(parts_added_per_loop);
3051
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003052 int start = current_match[0];
3053 int end = current_match[1];
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003054
3055 if (prev < start) {
3056 builder.AddSubjectSlice(prev, start);
3057 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00003058
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003059 if (simple_replace) {
3060 builder.AddString(replacement);
3061 } else {
3062 compiled_replacement.Apply(&builder,
3063 start,
3064 end,
3065 current_match);
3066 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003067 prev = end;
3068
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003069 current_match = global_cache.FetchNext();
3070 } while (current_match != NULL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003071
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003072 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003073
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003074 if (prev < subject_length) {
3075 builder.EnsureCapacity(2);
3076 builder.AddSubjectSlice(prev, subject_length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003077 }
3078
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003079 RegExpImpl::SetLastMatchInfo(last_match_info,
3080 subject,
3081 capture_count,
3082 global_cache.LastSuccessfulMatch());
3083
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003084 return *(builder.ToString());
3085}
3086
3087
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088template <typename ResultSeqString>
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003089MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 Isolate* isolate,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003091 Handle<String> subject,
3092 Handle<JSRegExp> regexp,
3093 Handle<JSArray> last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003094 ASSERT(subject->IsFlat());
3095
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003096 // Shortcut for simple non-regexp global replacements
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003097 if (regexp->TypeTag() == JSRegExp::ATOM) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003098 Handle<String> empty_string = isolate->factory()->empty_string();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003099 if (subject->IsOneByteRepresentation()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003100 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>(
3101 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003102 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003103 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>(
3104 isolate, subject, regexp, empty_string, last_match_info);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003105 }
3106 }
3107
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003108 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003109 if (global_cache.HasException()) return Failure::Exception();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003110
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003111 int32_t* current_match = global_cache.FetchNext();
3112 if (current_match == NULL) {
3113 if (global_cache.HasException()) return Failure::Exception();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003114 return *subject;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003115 }
3116
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003117 int start = current_match[0];
3118 int end = current_match[1];
3119 int capture_count = regexp->CaptureCount();
3120 int subject_length = subject->length();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003121
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003122 int new_length = subject_length - (end - start);
3123 if (new_length == 0) return isolate->heap()->empty_string();
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003124
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003125 Handle<ResultSeqString> answer;
3126 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 answer = Handle<ResultSeqString>::cast(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003128 isolate->factory()->NewRawOneByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003130 answer = Handle<ResultSeqString>::cast(
3131 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003132 }
3133
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003134 int prev = 0;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003135 int position = 0;
3136
3137 do {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003138 start = current_match[0];
3139 end = current_match[1];
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 if (prev < start) {
3141 // Add substring subject[prev;start] to answer string.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003142 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003143 position += start - prev;
3144 }
3145 prev = end;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003146
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003147 current_match = global_cache.FetchNext();
3148 } while (current_match != NULL);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003149
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003150 if (global_cache.HasException()) return Failure::Exception();
3151
3152 RegExpImpl::SetLastMatchInfo(last_match_info,
3153 subject,
3154 capture_count,
3155 global_cache.LastSuccessfulMatch());
3156
3157 if (prev < subject_length) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003158 // Add substring subject[prev;length] to answer string.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003159 String::WriteToFlat(
3160 *subject, answer->GetChars() + position, prev, subject_length);
3161 position += subject_length - prev;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003162 }
3163
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003164 if (position == 0) return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003165
3166 // Shorten string and fill
3167 int string_size = ResultSeqString::SizeFor(position);
3168 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3169 int delta = allocated_string_size - string_size;
3170
3171 answer->set_length(position);
3172 if (delta == 0) return *answer;
3173
3174 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003175 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003176 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003177 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003178 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003179
3180 return *answer;
3181}
3182
3183
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003184RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003185 ASSERT(args.length() == 4);
3186
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003187 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003188
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003189 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3190 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2);
3191 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3192 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003193
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003194 ASSERT(regexp->GetFlags().is_global());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003195
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003196 if (!subject->IsFlat()) subject = FlattenGetString(subject);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003197
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003198 if (replacement->length() == 0) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003199 if (subject->IsOneByteConvertible()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003200 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003201 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003202 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003203 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003204 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003205 }
3206 }
3207
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003208 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement);
3209
3210 return StringReplaceGlobalRegExpWithString(
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003211 isolate, subject, regexp, replacement, last_match_info);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003212}
3213
3214
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003215Handle<String> StringReplaceOneCharWithString(Isolate* isolate,
3216 Handle<String> subject,
3217 Handle<String> search,
3218 Handle<String> replace,
3219 bool* found,
3220 int recursion_limit) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003221 if (recursion_limit == 0) return Handle<String>::null();
3222 if (subject->IsConsString()) {
3223 ConsString* cons = ConsString::cast(*subject);
3224 Handle<String> first = Handle<String>(cons->first());
3225 Handle<String> second = Handle<String>(cons->second());
3226 Handle<String> new_first =
3227 StringReplaceOneCharWithString(isolate,
3228 first,
3229 search,
3230 replace,
3231 found,
3232 recursion_limit - 1);
3233 if (*found) return isolate->factory()->NewConsString(new_first, second);
3234 if (new_first.is_null()) return new_first;
3235
3236 Handle<String> new_second =
3237 StringReplaceOneCharWithString(isolate,
3238 second,
3239 search,
3240 replace,
3241 found,
3242 recursion_limit - 1);
3243 if (*found) return isolate->factory()->NewConsString(first, new_second);
3244 if (new_second.is_null()) return new_second;
3245
3246 return subject;
3247 } else {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003248 int index = Runtime::StringMatch(isolate, subject, search, 0);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003249 if (index == -1) return subject;
3250 *found = true;
3251 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3252 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3253 Handle<String> second =
3254 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3255 return isolate->factory()->NewConsString(cons1, second);
3256 }
3257}
3258
3259
3260RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3261 ASSERT(args.length() == 3);
3262 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003263 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3264 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3265 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003266
3267 // If the cons string tree is too deep, we simply abort the recursion and
3268 // retry with a flattened subject string.
3269 const int kRecursionLimit = 0x1000;
3270 bool found = false;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003271 Handle<String> result = StringReplaceOneCharWithString(isolate,
3272 subject,
3273 search,
3274 replace,
3275 &found,
3276 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003277 if (!result.is_null()) return *result;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003278 return *StringReplaceOneCharWithString(isolate,
3279 FlattenGetString(subject),
3280 search,
3281 replace,
3282 &found,
3283 kRecursionLimit);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003284}
3285
3286
ager@chromium.org7c537e22008-10-16 08:43:32 +00003287// Perform string match of pattern on subject, starting at start index.
3288// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003289// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290int Runtime::StringMatch(Isolate* isolate,
3291 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003292 Handle<String> pat,
3293 int start_index) {
3294 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003295 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003297 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003298 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003300 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301 if (start_index + pattern_length > subject_length) return -1;
3302
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003303 if (!sub->IsFlat()) FlattenString(sub);
3304 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003305
ager@chromium.org7c537e22008-10-16 08:43:32 +00003306 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003307 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003308 String::FlatContent seq_sub = sub->GetFlatContent();
3309 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003310
ager@chromium.org7c537e22008-10-16 08:43:32 +00003311 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003312 if (seq_pat.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003313 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003314 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003315 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003316 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003317 pat_vector,
3318 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003319 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003320 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003321 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322 pat_vector,
3323 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003324 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003325 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3326 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003327 return SearchString(isolate,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003328 seq_sub.ToOneByteVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 pat_vector,
3330 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003332 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003333 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003334 pat_vector,
3335 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003336}
3337
3338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003339RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003340 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003341 ASSERT(args.length() == 3);
3342
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003343 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3344 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003346 Object* index = args[2];
3347 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003348 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003349
ager@chromium.org870a0b62008-11-04 11:43:05 +00003350 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003351 int position =
3352 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003353 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354}
3355
3356
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003357template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003358static int StringMatchBackwards(Vector<const schar> subject,
3359 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003360 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003361 int pattern_length = pattern.length();
3362 ASSERT(pattern_length >= 1);
3363 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364
3365 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003366 for (int i = 0; i < pattern_length; i++) {
3367 uc16 c = pattern[i];
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003368 if (c > String::kMaxOneByteCharCode) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369 return -1;
3370 }
3371 }
3372 }
3373
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003374 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003376 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003377 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003378 while (j < pattern_length) {
3379 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003380 break;
3381 }
3382 j++;
3383 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003384 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003385 return i;
3386 }
3387 }
3388 return -1;
3389}
3390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003391RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 ASSERT(args.length() == 3);
3394
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003395 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3396 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003397
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003400 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003402 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003403 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003405 if (start_index + pat_length > sub_length) {
3406 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409 if (pat_length == 0) {
3410 return Smi::FromInt(start_index);
3411 }
3412
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003413 if (!sub->IsFlat()) FlattenString(sub);
3414 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003415
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003416 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3418
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003419 String::FlatContent sub_content = sub->GetFlatContent();
3420 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003422 if (pat_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003423 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003424 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003425 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 pat_vector,
3427 start_index);
3428 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003429 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 pat_vector,
3431 start_index);
3432 }
3433 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003434 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3435 if (sub_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003436 position = StringMatchBackwards(sub_content.ToOneByteVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 pat_vector,
3438 start_index);
3439 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003440 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 pat_vector,
3442 start_index);
3443 }
3444 }
3445
3446 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003447}
3448
3449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003450RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003451 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 ASSERT(args.length() == 2);
3453
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003454 CONVERT_ARG_CHECKED(String, str1, 0);
3455 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456
3457 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003458 int str1_length = str1->length();
3459 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460
3461 // Decide trivial cases without flattening.
3462 if (str1_length == 0) {
3463 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3464 return Smi::FromInt(-str2_length);
3465 } else {
3466 if (str2_length == 0) return Smi::FromInt(str1_length);
3467 }
3468
3469 int end = str1_length < str2_length ? str1_length : str2_length;
3470
3471 // No need to flatten if we are going to find the answer on the first
3472 // character. At this point we know there is at least one character
3473 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003474 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003475 if (d != 0) return Smi::FromInt(d);
3476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003477 str1->TryFlatten();
3478 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003480 ConsStringIteratorOp* op1 =
3481 isolate->runtime_state()->string_locale_compare_it1();
3482 ConsStringIteratorOp* op2 =
3483 isolate->runtime_state()->string_locale_compare_it2();
3484 // TODO(dcarney) Can do array compares here more efficiently.
3485 StringCharacterStream stream1(str1, op1);
3486 StringCharacterStream stream2(str2, op2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003487
3488 for (int i = 0; i < end; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003489 uint16_t char1 = stream1.GetNext();
3490 uint16_t char2 = stream2.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491 if (char1 != char2) return Smi::FromInt(char1 - char2);
3492 }
3493
3494 return Smi::FromInt(str1_length - str2_length);
3495}
3496
3497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003498RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003499 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500 ASSERT(args.length() == 3);
3501
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003502 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003503 int start, end;
3504 // We have a fast integer-only case here to avoid a conversion to double in
3505 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003506 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3507 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3508 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3509 start = from_number;
3510 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003511 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003512 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3513 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003514 start = FastD2IChecked(from_number);
3515 end = FastD2IChecked(to_number);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003517 RUNTIME_ASSERT(end >= start);
3518 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003519 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003520 isolate->counters()->sub_string_runtime()->Increment();
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003521 if (end - start == 1) {
3522 return isolate->heap()->LookupSingleCharacterStringFromCode(
3523 value->Get(start));
3524 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003525 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526}
3527
3528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003529RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003530 ASSERT_EQ(3, args.length());
3531
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003532 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3533 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3534 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003535 HandleScope handles(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00003536
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003537 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3538 if (global_cache.HasException()) return Failure::Exception();
ager@chromium.org41826e72009-03-30 13:30:57 +00003539
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003540 int capture_count = regexp->CaptureCount();
ager@chromium.org41826e72009-03-30 13:30:57 +00003541
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003542 Zone* zone = isolate->runtime_zone();
3543 ZoneScope zone_space(zone, DELETE_ON_EXIT);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003544 ZoneList<int> offsets(8, zone);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003545
3546 while (true) {
3547 int32_t* match = global_cache.FetchNext();
3548 if (match == NULL) break;
3549 offsets.Add(match[0], zone); // start
3550 offsets.Add(match[1], zone); // end
3551 }
3552
3553 if (global_cache.HasException()) return Failure::Exception();
3554
3555 if (offsets.length() == 0) {
3556 // Not a single match.
3557 return isolate->heap()->null_value();
3558 }
3559
3560 RegExpImpl::SetLastMatchInfo(regexp_info,
3561 subject,
3562 capture_count,
3563 global_cache.LastSuccessfulMatch());
3564
ager@chromium.org41826e72009-03-30 13:30:57 +00003565 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003567 Handle<String> substring =
3568 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1));
ager@chromium.org04921a82011-06-27 13:21:41 +00003569 elements->set(0, *substring);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003570 for (int i = 1; i < matches; i++) {
3571 HandleScope temp_scope(isolate);
ager@chromium.org41826e72009-03-30 13:30:57 +00003572 int from = offsets.at(i * 2);
3573 int to = offsets.at(i * 2 + 1);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003574 Handle<String> substring =
3575 isolate->factory()->NewProperSubString(subject, from, to);
ager@chromium.org04921a82011-06-27 13:21:41 +00003576 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 result->set_length(Smi::FromInt(matches));
3580 return *result;
3581}
3582
3583
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003584// Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
3585// separate last match info. See comment on that function.
3586template<bool has_capture>
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003587static MaybeObject* SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003588 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589 Handle<String> subject,
3590 Handle<JSRegExp> regexp,
3591 Handle<JSArray> last_match_array,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003592 Handle<JSArray> result_array) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003593 ASSERT(subject->IsFlat());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003594 ASSERT_NE(has_capture, regexp->CaptureCount() == 0);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003595
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003596 int capture_count = regexp->CaptureCount();
3597 int subject_length = subject->length();
3598
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003599 static const int kMinLengthToCache = 0x1000;
3600
3601 if (subject_length > kMinLengthToCache) {
3602 Handle<Object> cached_answer(RegExpResultsCache::Lookup(
3603 isolate->heap(),
3604 *subject,
3605 regexp->data(),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003606 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003607 if (*cached_answer != Smi::FromInt(0)) {
3608 Handle<FixedArray> cached_fixed_array =
3609 Handle<FixedArray>(FixedArray::cast(*cached_answer));
3610 // The cache FixedArray is a COW-array and can therefore be reused.
3611 isolate->factory()->SetContent(result_array, cached_fixed_array);
3612 // The actual length of the result array is stored in the last element of
3613 // the backing store (the backing FixedArray may have a larger capacity).
3614 Object* cached_fixed_array_last_element =
3615 cached_fixed_array->get(cached_fixed_array->length() - 1);
3616 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element);
3617 result_array->set_length(js_array_length);
3618 RegExpImpl::SetLastMatchInfo(
3619 last_match_array, subject, capture_count, NULL);
3620 return *result_array;
3621 }
3622 }
3623
3624 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate);
3625 if (global_cache.HasException()) return Failure::Exception();
3626
3627 Handle<FixedArray> result_elements;
3628 if (result_array->HasFastObjectElements()) {
3629 result_elements =
3630 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3631 }
3632 if (result_elements.is_null() || result_elements->length() < 16) {
3633 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
3634 }
3635
3636 FixedArrayBuilder builder(result_elements);
3637
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003638 // Position to search from.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003639 int match_start = -1;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003640 int match_end = 0;
3641 bool first = true;
3642
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003643 // Two smis before and after the match, for very long strings.
3644 static const int kMaxBuilderEntriesPerRegExpMatch = 5;
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003645
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003646 while (true) {
3647 int32_t* current_match = global_cache.FetchNext();
3648 if (current_match == NULL) break;
3649 match_start = current_match[0];
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003650 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003651 if (match_end < match_start) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003652 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003653 match_end,
3654 match_start);
3655 }
3656 match_end = current_match[1];
3657 {
3658 // Avoid accumulating new handles inside loop.
3659 HandleScope temp_scope(isolate);
3660 Handle<String> match;
3661 if (!first) {
3662 match = isolate->factory()->NewProperSubString(subject,
3663 match_start,
3664 match_end);
3665 } else {
3666 match = isolate->factory()->NewSubString(subject,
3667 match_start,
3668 match_end);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003669 first = false;
3670 }
3671
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003672 if (has_capture) {
3673 // Arguments array to replace function is match, captures, index and
3674 // subject, i.e., 3 + capture count in total.
3675 Handle<FixedArray> elements =
3676 isolate->factory()->NewFixedArray(3 + capture_count);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003677
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003678 elements->set(0, *match);
3679 for (int i = 1; i <= capture_count; i++) {
3680 int start = current_match[i * 2];
3681 if (start >= 0) {
3682 int end = current_match[i * 2 + 1];
3683 ASSERT(start <= end);
3684 Handle<String> substring =
3685 isolate->factory()->NewSubString(subject, start, end);
3686 elements->set(i, *substring);
3687 } else {
3688 ASSERT(current_match[i * 2 + 1] < 0);
3689 elements->set(i, isolate->heap()->undefined_value());
3690 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003691 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003692 elements->set(capture_count + 1, Smi::FromInt(match_start));
3693 elements->set(capture_count + 2, *subject);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003694 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003695 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003696 builder.Add(*match);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003697 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003698 }
3699 }
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003700
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003701 if (global_cache.HasException()) return Failure::Exception();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003702
3703 if (match_start >= 0) {
3704 // Finished matching, with at least one match.
3705 if (match_end < subject_length) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003706 ReplacementStringBuilder::AddSubjectSlice(&builder,
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003707 match_end,
3708 subject_length);
3709 }
3710
3711 RegExpImpl::SetLastMatchInfo(
3712 last_match_array, subject, capture_count, NULL);
3713
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003714 if (subject_length > kMinLengthToCache) {
3715 // Store the length of the result array into the last element of the
3716 // backing FixedArray.
3717 builder.EnsureCapacity(1);
3718 Handle<FixedArray> fixed_array = builder.array();
3719 fixed_array->set(fixed_array->length() - 1,
3720 Smi::FromInt(builder.length()));
3721 // Cache the result and turn the FixedArray into a COW array.
3722 RegExpResultsCache::Enter(isolate->heap(),
3723 *subject,
3724 regexp->data(),
3725 *fixed_array,
3726 RegExpResultsCache::REGEXP_MULTIPLE_INDICES);
3727 }
3728 return *builder.ToJSArray(result_array);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003729 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003730 return isolate->heap()->null_value(); // No matches at all.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00003731 }
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003732}
3733
3734
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00003735// This is only called for StringReplaceGlobalRegExpWithFunction. This sets
3736// lastMatchInfoOverride to maintain the last match info, so we don't need to
3737// set any other last match array info.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003738RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003741
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003742 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003743 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003744 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3745 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3746 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003747
lrn@chromium.org25156de2010-04-06 13:10:27 +00003748 ASSERT(regexp->GetFlags().is_global());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003749
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003750 if (regexp->CaptureCount() == 0) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003751 return SearchRegExpMultiple<false>(
3752 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003753 } else {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003754 return SearchRegExpMultiple<true>(
3755 isolate, subject, regexp, last_match_info, result_array);
yangguo@chromium.org08eb1962012-08-21 11:19:20 +00003756 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003757}
3758
3759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003760RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003761 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003763 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003764 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003766 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003767 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003768 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003769 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003770 // Character array used for conversion.
3771 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return isolate->heap()->
3773 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003774 }
3775 }
3776
3777 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003778 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779 if (isnan(value)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003780 return *isolate->factory()->nan_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 }
3782 if (isinf(value)) {
3783 if (value < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003784 return *isolate->factory()->minus_infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003786 return *isolate->factory()->infinity_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003789 MaybeObject* result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003790 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 DeleteArray(str);
3792 return result;
3793}
3794
3795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003797 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 ASSERT(args.length() == 2);
3799
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003800 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003801 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003802 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 RUNTIME_ASSERT(f >= 0);
3804 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003805 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003806 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809}
3810
3811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003812RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003813 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 ASSERT(args.length() == 2);
3815
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003816 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003817 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003818 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 RUNTIME_ASSERT(f >= -1 && f <= 20);
3820 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003821 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003822 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003824 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003825}
3826
3827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003828RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003829 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 ASSERT(args.length() == 2);
3831
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003832 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003833 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003834 int f = FastD2IChecked(f_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835 RUNTIME_ASSERT(f >= 1 && f <= 21);
3836 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 MaybeObject* res =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003838 isolate->heap()->AllocateStringFromOneByte(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003839 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841}
3842
3843
3844// Returns a single character string where first character equals
3845// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003846static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003847 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003848 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003849 return LookupSingleCharacterStringFromCode(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003850 string->GetIsolate(),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003851 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003852 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003853 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003854}
3855
3856
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003857MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3858 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003859 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003860 // Handle [] indexing on Strings
3861 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003862 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3863 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003864 }
3865
3866 // Handle [] indexing on String objects
3867 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003868 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3869 Handle<Object> result =
3870 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3871 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003872 }
3873
3874 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003875 return object->GetPrototype(isolate)->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 }
3877
3878 return object->GetElement(index);
3879}
3880
3881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3883 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003884 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003888 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 isolate->factory()->NewTypeError("non_object_property_load",
3891 HandleVector(args, 2));
3892 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003893 }
3894
3895 // Check if the given key is an array index.
3896 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003897 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 }
3900
3901 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003902 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003903 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003904 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003905 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 bool has_pending_exception = false;
3907 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003908 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003910 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 }
3912
ager@chromium.org32912102009-01-16 10:38:43 +00003913 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 // the element if so.
3915 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003917 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003918 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 }
3920}
3921
3922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003923RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003924 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003925 ASSERT(args.length() == 2);
3926
3927 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003928 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003931}
3932
3933
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003934// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003935RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003936 NoHandleAllocation ha(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003937 ASSERT(args.length() == 2);
3938
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003939 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003940 // itself.
3941 //
3942 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003943 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003944 // global proxy object never has properties. This is the case
3945 // because the global proxy object forwards everything to its hidden
3946 // prototype including local lookups.
3947 //
3948 // Additionally, we need to make sure that we do not cache results
3949 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003950 if (args[0]->IsJSObject()) {
3951 if (!args[0]->IsJSGlobalProxy() &&
3952 !args[0]->IsAccessCheckNeeded() &&
3953 args[1]->IsString()) {
3954 JSObject* receiver = JSObject::cast(args[0]);
3955 String* key = String::cast(args[1]);
3956 if (receiver->HasFastProperties()) {
3957 // Attempt to use lookup cache.
3958 Map* receiver_map = receiver->map();
3959 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3960 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
3961 if (offset != -1) {
3962 Object* value = receiver->FastPropertyAt(offset);
3963 return value->IsTheHole()
3964 ? isolate->heap()->undefined_value()
3965 : value;
3966 }
3967 // Lookup cache miss. Perform lookup and update the cache if
3968 // appropriate.
3969 LookupResult result(isolate);
3970 receiver->LocalLookup(key, &result);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003971 if (result.IsField()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003972 int offset = result.GetFieldIndex().field_index();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003973 keyed_lookup_cache->Update(receiver_map, key, offset);
3974 return receiver->FastPropertyAt(offset);
3975 }
3976 } else {
3977 // Attempt dictionary lookup.
3978 StringDictionary* dictionary = receiver->property_dictionary();
3979 int entry = dictionary->FindEntry(key);
3980 if ((entry != StringDictionary::kNotFound) &&
3981 (dictionary->DetailsAt(entry).type() == NORMAL)) {
3982 Object* value = dictionary->ValueAt(entry);
3983 if (!receiver->IsGlobalObject()) return value;
3984 value = JSGlobalPropertyCell::cast(value)->value();
3985 if (!value->IsTheHole()) return value;
3986 // If value is the hole do the general lookup.
3987 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003988 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003989 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
3990 // JSObject without a string key. If the key is a Smi, check for a
3991 // definite out-of-bounds access to elements, which is a strong indicator
3992 // that subsequent accesses will also call the runtime. Proactively
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003993 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003994 // doubles for those future calls in the case that the elements would
3995 // become FAST_DOUBLE_ELEMENTS.
3996 Handle<JSObject> js_object(args.at<JSObject>(0));
3997 ElementsKind elements_kind = js_object->GetElementsKind();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003998 if (IsFastDoubleElementsKind(elements_kind)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003999 FixedArrayBase* elements = js_object->elements();
4000 if (args.at<Smi>(1)->value() >= elements->length()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004001 if (IsFastHoleyElementsKind(elements_kind)) {
4002 elements_kind = FAST_HOLEY_ELEMENTS;
4003 } else {
4004 elements_kind = FAST_ELEMENTS;
4005 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004006 MaybeObject* maybe_object = TransitionElements(js_object,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004007 elements_kind,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004008 isolate);
4009 if (maybe_object->IsFailure()) return maybe_object;
4010 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004011 } else {
4012 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) ||
4013 !IsFastElementsKind(elements_kind));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004014 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004015 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004016 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4017 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004018 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004019 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004020 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004021 if (index >= 0 && index < str->length()) {
4022 Handle<Object> result = GetCharAt(str, index);
4023 return *result;
4024 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004025 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004026
4027 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004028 return Runtime::GetObjectProperty(isolate,
4029 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004030 args.at<Object>(1));
4031}
4032
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004033
4034static bool IsValidAccessor(Handle<Object> obj) {
4035 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4036}
4037
4038
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004039// Implements part of 8.12.9 DefineOwnProperty.
4040// There are 3 cases that lead here:
4041// Step 4b - define a new accessor property.
4042// Steps 9c & 12 - replace an existing data property with an accessor property.
4043// Step 12 - update an existing accessor property with an accessor or generic
4044// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004045RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004046 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004048 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004049 RUNTIME_ASSERT(!obj->IsNull());
4050 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4051 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4052 RUNTIME_ASSERT(IsValidAccessor(getter));
4053 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4054 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004055 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004056 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004057 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004058
danno@chromium.org88aa0582012-03-23 15:11:57 +00004059 bool fast = obj->HasFastProperties();
4060 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4061 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004062 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004063}
4064
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004065// Implements part of 8.12.9 DefineOwnProperty.
4066// There are 3 cases that lead here:
4067// Step 4a - define a new data property.
4068// Steps 9b & 12 - replace an existing accessor property with a data property.
4069// Step 12 - update an existing data property with a data or generic
4070// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004071RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004072 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004073 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004074 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4075 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004076 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004077 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004078 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004079 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4080
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004081 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004082 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004083
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004084 // Special case for callback properties.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004085 if (result.IsPropertyCallbacks()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004086 Object* callback = result.GetCallbackObject();
4087 // To be compatible with Safari we do not change the value on API objects
4088 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4089 // the value.
4090 if (callback->IsAccessorInfo()) {
4091 return isolate->heap()->undefined_value();
4092 }
4093 // Avoid redefining foreign callback as data property, just use the stored
4094 // setter to update the value instead.
4095 // TODO(mstarzinger): So far this only works if property attributes don't
4096 // change, this should be fixed once we cleanup the underlying code.
4097 if (callback->IsForeign() && result.GetAttributes() == attr) {
4098 return js_object->SetPropertyWithCallback(callback,
4099 *name,
4100 *obj_value,
4101 result.holder(),
4102 kStrictMode);
4103 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004104 }
4105
ager@chromium.org5c838252010-02-19 08:53:10 +00004106 // Take special care when attributes are different and there is already
4107 // a property. For simplicity we normalize the property which enables us
4108 // to not worry about changing the instance_descriptor and creating a new
4109 // map. The current version of SetObjectProperty does not handle attributes
4110 // correctly in the case where a property is a field and is reset with
4111 // new attributes.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004112 if (result.IsFound() &&
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004113 (attr != result.GetAttributes() || result.IsPropertyCallbacks())) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004114 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004115 if (js_object->IsJSGlobalProxy()) {
4116 // Since the result is a property, the prototype will exist so
4117 // we don't have to check for null.
4118 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004119 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004120 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004121 // Use IgnoreAttributes version since a readonly property may be
4122 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004123 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4124 *obj_value,
4125 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004126 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128 return Runtime::ForceSetObjectProperty(isolate,
4129 js_object,
4130 name,
4131 obj_value,
4132 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004133}
4134
4135
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004136// Return property without being observable by accessors or interceptors.
4137RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
4138 ASSERT(args.length() == 2);
4139 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
4140 CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
4141 LookupResult lookup(isolate);
4142 object->LookupRealNamedProperty(*key, &lookup);
4143 if (!lookup.IsFound()) return isolate->heap()->undefined_value();
4144 switch (lookup.type()) {
4145 case NORMAL:
4146 return lookup.holder()->GetNormalizedProperty(&lookup);
4147 case FIELD:
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004148 return lookup.holder()->FastPropertyAt(
4149 lookup.GetFieldIndex().field_index());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004150 case CONSTANT_FUNCTION:
4151 return lookup.GetConstantFunction();
4152 case CALLBACKS:
4153 case HANDLER:
4154 case INTERCEPTOR:
4155 case TRANSITION:
4156 return isolate->heap()->undefined_value();
4157 case NONEXISTENT:
4158 UNREACHABLE();
4159 }
4160 return isolate->heap()->undefined_value();
4161}
4162
4163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004164MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4165 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004166 Handle<Object> key,
4167 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004168 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004169 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004170 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004171 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004174 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 isolate->factory()->NewTypeError("non_object_property_store",
4177 HandleVector(args, 2));
4178 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 }
4180
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004181 if (object->IsJSProxy()) {
4182 bool has_pending_exception = false;
4183 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4184 if (has_pending_exception) return Failure::Exception();
4185 return JSProxy::cast(*object)->SetProperty(
4186 String::cast(*name), *value, attr, strict_mode);
4187 }
4188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 // If the object isn't a JavaScript object, we ignore the store.
4190 if (!object->IsJSObject()) return *value;
4191
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004192 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 // Check if the given key is an array index.
4195 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004196 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4198 // of a string using [] notation. We need to support this too in
4199 // JavaScript.
4200 // In the case of a String object we just need to redirect the assignment to
4201 // the underlying string if the index is in range. Since the underlying
4202 // string does nothing with the assignment then we can ignore such
4203 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004204 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004208 js_object->ValidateElements();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004209 Handle<Object> result = JSObject::SetElement(
4210 js_object, index, value, attr, strict_mode, set_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004211 js_object->ValidateElements();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004212 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213 return *value;
4214 }
4215
4216 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004217 Handle<Object> result;
4218 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004219 result = JSObject::SetElement(
4220 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004222 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004223 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004224 result = JSReceiver::SetProperty(
4225 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004227 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228 return *value;
4229 }
4230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 bool has_pending_exception = false;
4233 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4234 if (has_pending_exception) return Failure::Exception();
4235 Handle<String> name = Handle<String>::cast(converted);
4236
4237 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004238 return js_object->SetElement(
4239 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004241 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 }
4243}
4244
4245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004246MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4247 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004248 Handle<Object> key,
4249 Handle<Object> value,
4250 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004251 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004252
4253 // Check if the given key is an array index.
4254 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004255 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004256 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4257 // of a string using [] notation. We need to support this too in
4258 // JavaScript.
4259 // In the case of a String object we just need to redirect the assignment to
4260 // the underlying string if the index is in range. Since the underlying
4261 // string does nothing with the assignment then we can ignore such
4262 // assignments.
4263 if (js_object->IsStringObjectWithCharacterAt(index)) {
4264 return *value;
4265 }
4266
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004267 return js_object->SetElement(
4268 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004269 }
4270
4271 if (key->IsString()) {
4272 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004273 return js_object->SetElement(
4274 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004275 } else {
4276 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004277 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004278 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4279 *value,
4280 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004281 }
4282 }
4283
4284 // Call-back into JavaScript to convert the key to a string.
4285 bool has_pending_exception = false;
4286 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4287 if (has_pending_exception) return Failure::Exception();
4288 Handle<String> name = Handle<String>::cast(converted);
4289
4290 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004291 return js_object->SetElement(
4292 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004293 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004294 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004295 }
4296}
4297
4298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004300 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004301 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004302 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004303
4304 // Check if the given key is an array index.
4305 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004306 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004307 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4308 // characters of a string using [] notation. In the case of a
4309 // String object we just need to redirect the deletion to the
4310 // underlying string if the index is in range. Since the
4311 // underlying string does nothing with the deletion, we can ignore
4312 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004313 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004315 }
4316
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004317 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004318 }
4319
4320 Handle<String> key_string;
4321 if (key->IsString()) {
4322 key_string = Handle<String>::cast(key);
4323 } else {
4324 // Call-back into JavaScript to convert the key to a string.
4325 bool has_pending_exception = false;
4326 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4327 if (has_pending_exception) return Failure::Exception();
4328 key_string = Handle<String>::cast(converted);
4329 }
4330
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004331 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004332 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004333}
4334
4335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004336RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004337 NoHandleAllocation ha(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004338 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339
4340 Handle<Object> object = args.at<Object>(0);
4341 Handle<Object> key = args.at<Object>(1);
4342 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004343 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004344 RUNTIME_ASSERT(
4345 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004347 PropertyAttributes attributes =
4348 static_cast<PropertyAttributes>(unchecked_attributes);
4349
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004350 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004351 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004352 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004353 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004354 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 return Runtime::SetObjectProperty(isolate,
4357 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004358 key,
4359 value,
4360 attributes,
4361 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362}
4363
4364
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) {
4366 HandleScope scope(isolate);
4367 RUNTIME_ASSERT(args.length() == 2);
4368 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
4369 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
4370 JSObject::TransitionElementsKind(array, map->elements_kind());
4371 return *array;
4372}
4373
4374
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004375RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004376 NoHandleAllocation ha(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004377 RUNTIME_ASSERT(args.length() == 1);
4378 Handle<Object> object = args.at<Object>(0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004379 if (object->IsJSObject()) {
4380 Handle<JSObject> js_object(Handle<JSObject>::cast(object));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004381 ASSERT(!js_object->map()->is_observed());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004382 ElementsKind new_kind = js_object->HasFastHoleyElements()
4383 ? FAST_HOLEY_DOUBLE_ELEMENTS
4384 : FAST_DOUBLE_ELEMENTS;
4385 return TransitionElements(object, new_kind, isolate);
4386 } else {
4387 return *object;
4388 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004389}
4390
4391
4392RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004393 NoHandleAllocation ha(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 RUNTIME_ASSERT(args.length() == 1);
4395 Handle<Object> object = args.at<Object>(0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004396 if (object->IsJSObject()) {
4397 Handle<JSObject> js_object(Handle<JSObject>::cast(object));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004398 ASSERT(!js_object->map()->is_observed());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004399 ElementsKind new_kind = js_object->HasFastHoleyElements()
4400 ? FAST_HOLEY_ELEMENTS
4401 : FAST_ELEMENTS;
4402 return TransitionElements(object, new_kind, isolate);
4403 } else {
4404 return *object;
4405 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004406}
4407
4408
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004409// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004410// This is used to decide if we should transform null and undefined
4411// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004412RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004413 NoHandleAllocation ha(isolate);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004414 RUNTIME_ASSERT(args.length() == 1);
4415
4416 Handle<Object> object = args.at<Object>(0);
4417
4418 if (object->IsJSFunction()) {
4419 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004420 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004421 }
4422 return isolate->heap()->undefined_value();
4423}
4424
4425
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004426RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4427 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004428 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004429 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4430 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004431 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004432 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00004433 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004434
4435 Object* raw_boilerplate_object = literals->get(literal_index);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004436 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004437 ElementsKind elements_kind = object->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004438 ASSERT(IsFastElementsKind(elements_kind));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004439 // Smis should never trigger transitions.
4440 ASSERT(!value->IsSmi());
4441
4442 if (value->IsNumber()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004443 ASSERT(IsFastSmiElementsKind(elements_kind));
4444 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
4445 ? FAST_HOLEY_DOUBLE_ELEMENTS
4446 : FAST_DOUBLE_ELEMENTS;
4447 if (IsMoreGeneralElementsKindTransition(
4448 boilerplate_object->GetElementsKind(),
4449 transitioned_kind)) {
4450 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004451 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004452 JSObject::TransitionElementsKind(object, transitioned_kind);
4453 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind()));
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004454 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004455 HeapNumber* number = HeapNumber::cast(*value);
4456 double_array->set(store_index, number->Number());
4457 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004458 ASSERT(IsFastSmiElementsKind(elements_kind) ||
4459 IsFastDoubleElementsKind(elements_kind));
4460 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind)
4461 ? FAST_HOLEY_ELEMENTS
4462 : FAST_ELEMENTS;
4463 JSObject::TransitionElementsKind(object, transitioned_kind);
4464 if (IsMoreGeneralElementsKindTransition(
4465 boilerplate_object->GetElementsKind(),
4466 transitioned_kind)) {
4467 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004468 }
4469 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004470 object_array->set(store_index, *value);
4471 }
4472 return *object;
4473}
4474
4475
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004476// Check whether debugger and is about to step into the callback that is passed
4477// to a built-in function such as Array.forEach.
4478RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004479#ifdef ENABLE_DEBUGGER_SUPPORT
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004480 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
4481 return isolate->heap()->false_value();
4482 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004483 CONVERT_ARG_CHECKED(Object, callback, 0);
4484 // We do not step into the callback if it's a builtin or not even a function.
4485 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
4486 return isolate->heap()->false_value();
4487 }
4488 return isolate->heap()->true_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004489#else
4490 return isolate->heap()->false_value();
4491#endif // ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004492}
4493
4494
4495// Set one shot breakpoints for the callback function that is passed to a
4496// built-in function such as Array.forEach to enable stepping into the callback.
4497RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004498#ifdef ENABLE_DEBUGGER_SUPPORT
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004499 Debug* debug = isolate->debug();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004500 if (!debug->IsStepping()) return isolate->heap()->undefined_value();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004501 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004502 HandleScope scope(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004503 // When leaving the callback, step out has been activated, but not performed
4504 // if we do not leave the builtin. To be able to step into the callback
4505 // again, we need to clear the step out at this point.
4506 debug->ClearStepOut();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00004507 debug->FloodWithOneShot(callback);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004508#endif // ENABLE_DEBUGGER_SUPPORT
4509 return isolate->heap()->undefined_value();
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004510}
4511
4512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513// Set a local property, even if it is READ_ONLY. If the property does not
4514// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004515RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004516 NoHandleAllocation ha(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004517 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004518 CONVERT_ARG_CHECKED(JSObject, object, 0);
4519 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004520 // Compute attributes.
4521 PropertyAttributes attributes = NONE;
4522 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004523 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004524 // Only attribute bits should be set.
4525 RUNTIME_ASSERT(
4526 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4527 attributes = static_cast<PropertyAttributes>(unchecked_value);
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004530 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004531 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004536 NoHandleAllocation ha(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004537 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004538
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004539 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4540 CONVERT_ARG_CHECKED(String, key, 1);
4541 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004542 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004543 ? JSReceiver::STRICT_DELETION
4544 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545}
4546
4547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548static Object* HasLocalPropertyImplementation(Isolate* isolate,
4549 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004550 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004551 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004552 // Handle hidden prototypes. If there's a hidden prototype above this thing
4553 // then we have to check it for properties, because they are supposed to
4554 // look like they are on this object.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004555 Handle<Object> proto(object->GetPrototype(), isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +00004556 if (proto->IsJSObject() &&
4557 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 return HasLocalPropertyImplementation(isolate,
4559 Handle<JSObject>::cast(proto),
4560 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004562 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004563}
4564
4565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004566RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004567 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004569 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004571 uint32_t index;
4572 const bool key_is_array_index = key->AsArrayIndex(&index);
4573
ager@chromium.org9085a012009-05-11 19:22:57 +00004574 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004576 if (obj->IsJSObject()) {
4577 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004578 // Fast case: either the key is a real named property or it is not
4579 // an array index and there are no interceptors or hidden
4580 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004582 Map* map = object->map();
4583 if (!key_is_array_index &&
4584 !map->has_named_interceptor() &&
4585 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4586 return isolate->heap()->false_value();
4587 }
4588 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004589 HandleScope scope(isolate);
4590 return HasLocalPropertyImplementation(isolate,
4591 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004592 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004593 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004595 String* string = String::cast(obj);
4596 if (index < static_cast<uint32_t>(string->length())) {
4597 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601}
4602
4603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004604RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004605 NoHandleAllocation na(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004607 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4608 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004610 bool result = receiver->HasProperty(key);
4611 if (isolate->has_pending_exception()) return Failure::Exception();
4612 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613}
4614
4615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004616RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004617 NoHandleAllocation na(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004619 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4620 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004622 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004623 if (isolate->has_pending_exception()) return Failure::Exception();
4624 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625}
4626
4627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004628RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004629 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630 ASSERT(args.length() == 2);
4631
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004632 CONVERT_ARG_CHECKED(JSObject, object, 0);
4633 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634
ager@chromium.org870a0b62008-11-04 11:43:05 +00004635 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004637}
4638
4639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004640RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004641 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004643 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004644 bool threw = false;
4645 Handle<JSArray> result = GetKeysFor(object, &threw);
4646 if (threw) return Failure::Exception();
4647 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648}
4649
4650
4651// Returns either a FixedArray as Runtime_GetPropertyNames,
4652// or, if the given object has an enum cache that contains
4653// all enumerable properties of the object and its prototypes
4654// have none, the map of the object. This is used to speed up
4655// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004656RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 ASSERT(args.length() == 1);
4658
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004659 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660
4661 if (raw_object->IsSimpleEnum()) return raw_object->map();
4662
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004664 Handle<JSReceiver> object(raw_object);
4665 bool threw = false;
4666 Handle<FixedArray> content =
4667 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4668 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669
4670 // Test again, since cache may have been built by preceding call.
4671 if (object->IsSimpleEnum()) return object->map();
4672
4673 return *content;
4674}
4675
4676
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004677// Find the length of the prototype chain that is to to handled as one. If a
4678// prototype object is hidden it is to be viewed as part of the the object it
4679// is prototype for.
4680static int LocalPrototypeChainLength(JSObject* obj) {
4681 int count = 1;
4682 Object* proto = obj->GetPrototype();
4683 while (proto->IsJSObject() &&
4684 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4685 count++;
4686 proto = JSObject::cast(proto)->GetPrototype();
4687 }
4688 return count;
4689}
4690
4691
4692// Return the names of the local named properties.
4693// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004694RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004695 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004696 ASSERT(args.length() == 1);
4697 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004698 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004699 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004700 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004701
4702 // Skip the global proxy as it has no properties and always delegates to the
4703 // real global object.
4704 if (obj->IsJSGlobalProxy()) {
4705 // Only collect names if access is permitted.
4706 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 !isolate->MayNamedAccess(*obj,
4708 isolate->heap()->undefined_value(),
4709 v8::ACCESS_KEYS)) {
4710 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4711 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004712 }
4713 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4714 }
4715
4716 // Find the number of objects making up this.
4717 int length = LocalPrototypeChainLength(*obj);
4718
4719 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004720 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004721 int total_property_count = 0;
4722 Handle<JSObject> jsproto = obj;
4723 for (int i = 0; i < length; i++) {
4724 // Only collect names if access is permitted.
4725 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 !isolate->MayNamedAccess(*jsproto,
4727 isolate->heap()->undefined_value(),
4728 v8::ACCESS_KEYS)) {
4729 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4730 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004731 }
4732 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004733 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004734 local_property_count[i] = n;
4735 total_property_count += n;
4736 if (i < length - 1) {
4737 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4738 }
4739 }
4740
4741 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004742 Handle<FixedArray> names =
4743 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004744
4745 // Get the property names.
4746 jsproto = obj;
4747 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004748 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004749 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004750 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4751 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004752 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004753 proto_with_hidden_properties++;
4754 }
4755 if (i < length - 1) {
4756 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4757 }
4758 }
4759
4760 // Filter out name of hidden propeties object.
4761 if (proto_with_hidden_properties > 0) {
4762 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004763 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004764 names->length() - proto_with_hidden_properties);
4765 int dest_pos = 0;
4766 for (int i = 0; i < total_property_count; i++) {
4767 Object* name = old_names->get(i);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004768 if (name == isolate->heap()->hidden_string()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004769 continue;
4770 }
4771 names->set(dest_pos++, name);
4772 }
4773 }
4774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004776}
4777
4778
4779// Return the names of the local indexed properties.
4780// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004781RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004782 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004783 ASSERT(args.length() == 1);
4784 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004785 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004786 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004787 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004788
4789 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004791 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004792 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004793}
4794
4795
4796// Return information on whether an object has a named or indexed interceptor.
4797// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004798RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004800 ASSERT(args.length() == 1);
4801 if (!args[0]->IsJSObject()) {
4802 return Smi::FromInt(0);
4803 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004804 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004805
4806 int result = 0;
4807 if (obj->HasNamedInterceptor()) result |= 2;
4808 if (obj->HasIndexedInterceptor()) result |= 1;
4809
4810 return Smi::FromInt(result);
4811}
4812
4813
4814// Return property names from named interceptor.
4815// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004816RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004817 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004818 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004819 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004820
4821 if (obj->HasNamedInterceptor()) {
4822 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4823 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4824 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004826}
4827
4828
4829// Return element names from indexed interceptor.
4830// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004833 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004834 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004835
4836 if (obj->HasIndexedInterceptor()) {
4837 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4838 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4839 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004840 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004841}
4842
4843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004844RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004845 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004846 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004848 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004849
4850 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004851 // Do access checks before going to the global object.
4852 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004854 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004855 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4856 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004857 }
4858
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004859 Handle<Object> proto(object->GetPrototype(), isolate);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004860 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004862 object = Handle<JSObject>::cast(proto);
4863 }
4864
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004865 bool threw = false;
4866 Handle<FixedArray> contents =
4867 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
4868 if (threw) return Failure::Exception();
4869
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004870 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4871 // property array and since the result is mutable we have to create
4872 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004873 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004874 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004875 for (int i = 0; i < length; i++) {
4876 Object* entry = contents->get(i);
4877 if (entry->IsString()) {
4878 copy->set(i, entry);
4879 } else {
4880 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004881 HandleScope scope(isolate);
4882 Handle<Object> entry_handle(entry, isolate);
4883 Handle<Object> entry_str =
4884 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004885 copy->set(i, *entry_str);
4886 }
4887 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004888 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004889}
4890
4891
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004893 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004894 ASSERT(args.length() == 1);
4895
4896 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004897 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898 it.AdvanceToArgumentsFrame();
4899 JavaScriptFrame* frame = it.frame();
4900
4901 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004902 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903
4904 // Try to convert the key to an index. If successful and within
4905 // index return the the argument from the frame.
4906 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004907 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 return frame->GetParameter(index);
4909 }
4910
4911 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913 bool exception = false;
4914 Handle<Object> converted =
4915 Execution::ToString(args.at<Object>(0), &exception);
4916 if (exception) return Failure::Exception();
4917 Handle<String> key = Handle<String>::cast(converted);
4918
4919 // Try to convert the string key into an array index.
4920 if (key->AsArrayIndex(&index)) {
4921 if (index < n) {
4922 return frame->GetParameter(index);
4923 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004924 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004925 }
4926 }
4927
4928 // Handle special arguments properties.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004929 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n);
4930 if (key->Equals(isolate->heap()->callee_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 Object* function = frame->function();
4932 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004933 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004934 return isolate->Throw(*isolate->factory()->NewTypeError(
4935 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4936 }
4937 return function;
4938 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939
4940 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942}
4943
4944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004945RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004946 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004947 Object* object = args[0];
4948 return (object->IsJSObject() && !object->IsGlobalObject())
4949 ? JSObject::cast(object)->TransformToFastProperties(0)
4950 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004951}
4952
4953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004954RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004955 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956 ASSERT(args.length() == 1);
4957
4958 return args[0]->ToBoolean();
4959}
4960
4961
4962// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4963// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004964RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004965 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004966
4967 Object* obj = args[0];
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004968 if (obj->IsNumber()) return isolate->heap()->number_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969 HeapObject* heap_obj = HeapObject::cast(obj);
4970
4971 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 if (heap_obj->map()->is_undetectable()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004973 return isolate->heap()->undefined_string();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004975
4976 InstanceType instance_type = heap_obj->map()->instance_type();
4977 if (instance_type < FIRST_NONSTRING_TYPE) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004978 return isolate->heap()->string_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 }
4980
4981 switch (instance_type) {
4982 case ODDBALL_TYPE:
4983 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004984 return isolate->heap()->boolean_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 }
4986 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004987 return FLAG_harmony_typeof
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004988 ? isolate->heap()->null_string()
4989 : isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 }
4991 ASSERT(heap_obj->IsUndefined());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004992 return isolate->heap()->undefined_string();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004993 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00004994 case JS_FUNCTION_PROXY_TYPE:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004995 return isolate->heap()->function_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004996 default:
4997 // For any kind of object not handled above, the spec rule for
4998 // host objects gives that it is okay to return "object"
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004999 return isolate->heap()->object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005000 }
5001}
5002
5003
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005004static bool AreDigits(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00005005 for (int i = from; i < to; i++) {
5006 if (s[i] < '0' || s[i] > '9') return false;
5007 }
5008
5009 return true;
5010}
5011
5012
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005013static int ParseDecimalInteger(const uint8_t*s, int from, int to) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00005014 ASSERT(to - from < 10); // Overflow is not possible.
5015 ASSERT(from < to);
5016 int d = s[from] - '0';
5017
5018 for (int i = from + 1; i < to; i++) {
5019 d = 10 * d + (s[i] - '0');
5020 }
5021
5022 return d;
5023}
5024
5025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005026RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005027 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005028 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005029 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005030 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005031
5032 // Fast case: short integer or some sorts of junk values.
5033 int len = subject->length();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005034 if (subject->IsSeqOneByteString()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00005035 if (len == 0) return Smi::FromInt(0);
5036
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005037 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005038 bool minus = (data[0] == '-');
5039 int start_pos = (minus ? 1 : 0);
5040
5041 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005043 } else if (data[start_pos] > '9') {
5044 // Fast check for a junk value. A valid string may start from a
5045 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5046 // the 'I' character ('Infinity'). All of that have codes not greater than
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005047 // '9' except 'I' and &nbsp;.
5048 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005050 }
5051 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5052 // The maximal/minimal smi has 10 digits. If the string has less digits we
5053 // know it will fit into the smi-data type.
5054 int d = ParseDecimalInteger(data, start_pos, len);
5055 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005057 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005058 } else if (!subject->HasHashCode() &&
5059 len <= String::kMaxArrayIndexSize &&
5060 (len == 1 || data[0] != '0')) {
5061 // String hash is not calculated yet but all the data are present.
5062 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005063 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005064#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005065 subject->Hash(); // Force hash calculation.
5066 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5067 static_cast<int>(hash));
5068#endif
5069 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005070 }
5071 return Smi::FromInt(d);
5072 }
5073 }
5074
5075 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005076 return isolate->heap()->NumberFromDouble(
5077 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078}
5079
5080
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00005081RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) {
5082 CONVERT_SMI_ARG_CHECKED(length, 0);
5083 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1);
5084 if (length == 0) return isolate->heap()->empty_string();
5085 if (is_one_byte) {
5086 return isolate->heap()->AllocateRawOneByteString(length);
5087 } else {
5088 return isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00005090}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00005093RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) {
5094 CONVERT_ARG_CHECKED(SeqString, string, 0);
5095 CONVERT_SMI_ARG_CHECKED(new_length, 1);
5096 return string->Truncate(new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097}
5098
5099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005100RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005101 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005102 HandleScope scope(isolate);
5103 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
5104 Handle<String> string = FlattenGetString(source);
5105 String::FlatContent content = string->GetFlatContent();
5106 ASSERT(content.IsFlat());
5107 Handle<String> result =
5108 content.IsAscii() ? URIEscape::Escape<uint8_t>(isolate, source)
5109 : URIEscape::Escape<uc16>(isolate, source);
5110 if (result.is_null()) return Failure::OutOfMemoryException(0x12);
5111 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005112}
5113
5114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005115RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116 ASSERT(args.length() == 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005117 HandleScope scope(isolate);
5118 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
5119 Handle<String> string = FlattenGetString(source);
5120 String::FlatContent content = string->GetFlatContent();
5121 ASSERT(content.IsFlat());
5122 return content.IsAscii() ? *URIUnescape::Unescape<uint8_t>(isolate, source)
5123 : *URIUnescape::Unescape<uc16>(isolate, source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124}
5125
5126
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127static const unsigned int kQuoteTableLength = 128u;
5128
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005129static const int kJsonQuotesCharactersPerEntry = 8;
5130static const char* const JsonQuotes =
5131 "\\u0000 \\u0001 \\u0002 \\u0003 "
5132 "\\u0004 \\u0005 \\u0006 \\u0007 "
5133 "\\b \\t \\n \\u000b "
5134 "\\f \\r \\u000e \\u000f "
5135 "\\u0010 \\u0011 \\u0012 \\u0013 "
5136 "\\u0014 \\u0015 \\u0016 \\u0017 "
5137 "\\u0018 \\u0019 \\u001a \\u001b "
5138 "\\u001c \\u001d \\u001e \\u001f "
5139 " ! \\\" # "
5140 "$ % & ' "
5141 "( ) * + "
5142 ", - . / "
5143 "0 1 2 3 "
5144 "4 5 6 7 "
5145 "8 9 : ; "
5146 "< = > ? "
5147 "@ A B C "
5148 "D E F G "
5149 "H I J K "
5150 "L M N O "
5151 "P Q R S "
5152 "T U V W "
5153 "X Y Z [ "
5154 "\\\\ ] ^ _ "
5155 "` a b c "
5156 "d e f g "
5157 "h i j k "
5158 "l m n o "
5159 "p q r s "
5160 "t u v w "
5161 "x y z { "
5162 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005163
5164
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005165// For a string that is less than 32k characters it should always be
5166// possible to allocate it in new space.
5167static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5168
5169
5170// Doing JSON quoting cannot make the string more than this many times larger.
5171static const int kJsonQuoteWorstCaseBlowup = 6;
5172
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005173static const int kSpaceForQuotesAndComma = 3;
5174static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005175
5176// Covers the entire ASCII range (all other characters are unchanged by JSON
5177// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005178static const byte JsonQuoteLengths[kQuoteTableLength] = {
5179 6, 6, 6, 6, 6, 6, 6, 6,
5180 2, 2, 2, 6, 2, 2, 6, 6,
5181 6, 6, 6, 6, 6, 6, 6, 6,
5182 6, 6, 6, 6, 6, 6, 6, 6,
5183 1, 1, 2, 1, 1, 1, 1, 1,
5184 1, 1, 1, 1, 1, 1, 1, 1,
5185 1, 1, 1, 1, 1, 1, 1, 1,
5186 1, 1, 1, 1, 1, 1, 1, 1,
5187 1, 1, 1, 1, 1, 1, 1, 1,
5188 1, 1, 1, 1, 1, 1, 1, 1,
5189 1, 1, 1, 1, 1, 1, 1, 1,
5190 1, 1, 1, 1, 2, 1, 1, 1,
5191 1, 1, 1, 1, 1, 1, 1, 1,
5192 1, 1, 1, 1, 1, 1, 1, 1,
5193 1, 1, 1, 1, 1, 1, 1, 1,
5194 1, 1, 1, 1, 1, 1, 1, 1,
5195};
5196
5197
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005198template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005200
5201
5202template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5204 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005205}
5206
5207
5208template <>
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005209MaybeObject* AllocateRawString<SeqOneByteString>(Isolate* isolate, int length) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005210 return isolate->heap()->AllocateRawOneByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005211}
5212
5213
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005214template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5216 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005217 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005218 const Char* read_cursor = characters.start();
5219 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005220 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 int quoted_length = kSpaceForQuotes;
5222 while (read_cursor < end) {
5223 Char c = *(read_cursor++);
mstarzinger@chromium.org6fc882a2013-02-26 17:45:41 +00005224 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005225 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005227 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005228 }
5229 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005230 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5231 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005232 Object* new_object;
5233 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005234 return new_alloc;
5235 }
5236 StringType* new_string = StringType::cast(new_object);
5237
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005238 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005239 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005240 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005241 *(write_cursor++) = '"';
5242
5243 read_cursor = characters.start();
5244 while (read_cursor < end) {
5245 Char c = *(read_cursor++);
mstarzinger@chromium.org6fc882a2013-02-26 17:45:41 +00005246 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005247 *(write_cursor++) = c;
5248 } else {
5249 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5250 const char* replacement = JsonQuotes +
5251 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5252 for (int i = 0; i < len; i++) {
5253 *write_cursor++ = *replacement++;
5254 }
5255 }
5256 }
5257 *(write_cursor++) = '"';
5258 return new_string;
5259}
5260
5261
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005262template <typename SinkChar, typename SourceChar>
5263static inline SinkChar* WriteQuoteJsonString(
5264 Isolate* isolate,
5265 SinkChar* write_cursor,
5266 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005267 // SinkChar is only char if SourceChar is guaranteed to be char.
5268 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005269 const SourceChar* read_cursor = characters.start();
5270 const SourceChar* end = read_cursor + characters.length();
5271 *(write_cursor++) = '"';
5272 while (read_cursor < end) {
5273 SourceChar c = *(read_cursor++);
mstarzinger@chromium.org6fc882a2013-02-26 17:45:41 +00005274 if (static_cast<unsigned>(c) >= kQuoteTableLength) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005275 *(write_cursor++) = static_cast<SinkChar>(c);
5276 } else {
5277 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5278 const char* replacement = JsonQuotes +
5279 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5280 write_cursor[0] = replacement[0];
5281 if (len > 1) {
5282 write_cursor[1] = replacement[1];
5283 if (len > 2) {
5284 ASSERT(len == 6);
5285 write_cursor[2] = replacement[2];
5286 write_cursor[3] = replacement[3];
5287 write_cursor[4] = replacement[4];
5288 write_cursor[5] = replacement[5];
5289 }
5290 }
5291 write_cursor += len;
5292 }
5293 }
5294 *(write_cursor++) = '"';
5295 return write_cursor;
5296}
5297
5298
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005299template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005300static MaybeObject* QuoteJsonString(Isolate* isolate,
5301 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005302 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005303 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005304 int worst_case_length =
5305 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005306 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005307 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005308 }
5309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5311 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005312 Object* new_object;
5313 if (!new_alloc->ToObject(&new_object)) {
5314 return new_alloc;
5315 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005316 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005317 // Even if our string is small enough to fit in new space we still have to
5318 // handle it being allocated in old space as may happen in the third
5319 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5320 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005321 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005322 }
5323 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005324 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005325
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005326 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005327 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005328 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005329 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5330 write_cursor,
5331 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005332 int final_length = static_cast<int>(
5333 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005334 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005335 isolate->heap()->new_space()->
5336 template ShrinkStringAtAllocationBoundary<StringType>(
5337 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005338 return new_string;
5339}
5340
5341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005342RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005343 NoHandleAllocation ha(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005344 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005345 if (!str->IsFlat()) {
5346 MaybeObject* try_flatten = str->TryFlatten();
5347 Object* flat;
5348 if (!try_flatten->ToObject(&flat)) {
5349 return try_flatten;
5350 }
5351 str = String::cast(flat);
5352 ASSERT(str->IsFlat());
5353 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005354 String::FlatContent flat = str->GetFlatContent();
5355 ASSERT(flat.IsFlat());
5356 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005357 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005358 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005359 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005360 return QuoteJsonString<uint8_t, SeqOneByteString, false>(
5361 isolate,
5362 flat.ToOneByteVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005363 }
5364}
5365
5366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005367RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005368 NoHandleAllocation ha(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005369 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005370 if (!str->IsFlat()) {
5371 MaybeObject* try_flatten = str->TryFlatten();
5372 Object* flat;
5373 if (!try_flatten->ToObject(&flat)) {
5374 return try_flatten;
5375 }
5376 str = String::cast(flat);
5377 ASSERT(str->IsFlat());
5378 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005379 String::FlatContent flat = str->GetFlatContent();
5380 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005381 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005382 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005383 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005384 return QuoteJsonString<uint8_t, SeqOneByteString, true>(
5385 isolate,
5386 flat.ToOneByteVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005387 }
5388}
5389
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005390
5391template <typename Char, typename StringType>
5392static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5393 FixedArray* array,
5394 int worst_case_length) {
5395 int length = array->length();
5396
5397 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5398 worst_case_length);
5399 Object* new_object;
5400 if (!new_alloc->ToObject(&new_object)) {
5401 return new_alloc;
5402 }
5403 if (!isolate->heap()->new_space()->Contains(new_object)) {
5404 // Even if our string is small enough to fit in new space we still have to
5405 // handle it being allocated in old space as may happen in the third
5406 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5407 // CEntryStub::GenerateCore.
5408 return isolate->heap()->undefined_value();
5409 }
5410 AssertNoAllocation no_gc;
5411 StringType* new_string = StringType::cast(new_object);
5412 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5413
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005414 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005415 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005416 *(write_cursor++) = '[';
5417 for (int i = 0; i < length; i++) {
5418 if (i != 0) *(write_cursor++) = ',';
5419 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005420 String::FlatContent content = str->GetFlatContent();
5421 ASSERT(content.IsFlat());
5422 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005423 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5424 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005425 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005426 } else {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005427 write_cursor =
5428 WriteQuoteJsonString<Char, uint8_t>(isolate,
5429 write_cursor,
5430 content.ToOneByteVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005431 }
5432 }
5433 *(write_cursor++) = ']';
5434
5435 int final_length = static_cast<int>(
5436 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005437 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005438 isolate->heap()->new_space()->
5439 template ShrinkStringAtAllocationBoundary<StringType>(
5440 new_string, final_length);
5441 return new_string;
5442}
5443
5444
5445RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005446 NoHandleAllocation ha(isolate);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005447 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005448 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005449
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005450 if (!array->HasFastObjectElements()) {
5451 return isolate->heap()->undefined_value();
5452 }
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005453 FixedArray* elements = FixedArray::cast(array->elements());
5454 int n = elements->length();
5455 bool ascii = true;
5456 int total_length = 0;
5457
5458 for (int i = 0; i < n; i++) {
5459 Object* elt = elements->get(i);
5460 if (!elt->IsString()) return isolate->heap()->undefined_value();
5461 String* element = String::cast(elt);
5462 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5463 total_length += element->length();
5464 if (ascii && element->IsTwoByteRepresentation()) {
5465 ascii = false;
5466 }
5467 }
5468
5469 int worst_case_length =
5470 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5471 + total_length * kJsonQuoteWorstCaseBlowup;
5472
5473 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5474 return isolate->heap()->undefined_value();
5475 }
5476
5477 if (ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005478 return QuoteJsonStringArray<char, SeqOneByteString>(isolate,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005479 elements,
5480 worst_case_length);
5481 } else {
5482 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5483 elements,
5484 worst_case_length);
5485 }
5486}
5487
5488
danno@chromium.org72204d52012-10-31 10:02:10 +00005489RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) {
5490 ASSERT(args.length() == 1);
5491 HandleScope scope(isolate);
5492 BasicJsonStringifier stringifier(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005493 return stringifier.Stringify(Handle<Object>(args[0], isolate));
danno@chromium.org72204d52012-10-31 10:02:10 +00005494}
5495
5496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005498 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005500 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005501 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005503 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504
lrn@chromium.org25156de2010-04-06 13:10:27 +00005505 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005506 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005507 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508}
5509
5510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005511RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005512 NoHandleAllocation ha(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005513 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514
5515 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005516 double value = StringToDouble(isolate->unicode_cache(),
5517 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518
5519 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005520 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521}
5522
5523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005525MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005527 String* s,
5528 int length,
5529 int input_string_length,
5530 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005531 // We try this twice, once with the assumption that the result is no longer
5532 // than the input and, if that assumption breaks, again with the exact
5533 // length. This may not be pretty, but it is nicer than what was here before
5534 // and I hereby claim my vaffel-is.
5535 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536 // Allocate the resulting string.
5537 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005538 // NOTE: This assumes that the upper/lower case of an ASCII
5539 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 // might break in the future if we implement more context and locale
5541 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005542 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005543 { MaybeObject* maybe_o = s->IsOneByteRepresentation()
5544 ? isolate->heap()->AllocateRawOneByteString(length)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005545 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005546 if (!maybe_o->ToObject(&o)) return maybe_o;
5547 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548 String* result = String::cast(o);
5549 bool has_changed_character = false;
5550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 // Convert all characters to upper case, assuming that they will fit
5552 // in the buffer
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00005553 Access<ConsStringIteratorOp> op(
5554 isolate->runtime_state()->string_iterator());
5555 StringCharacterStream stream(s, op.value());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005556 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557 // We can assume that the string is not empty
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00005558 uc32 current = stream.GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005559 for (int i = 0; i < length;) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00005560 bool has_next = stream.HasMore();
5561 uc32 next = has_next ? stream.GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 int char_length = mapping->get(current, next, chars);
5563 if (char_length == 0) {
5564 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005565 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 i++;
5567 } else if (char_length == 1) {
5568 // Common case: converting the letter resulted in one character.
5569 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005570 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005571 has_changed_character = true;
5572 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005573 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574 // We've assumed that the result would be as long as the
5575 // input but here is a character that converts to several
5576 // characters. No matter, we calculate the exact length
5577 // of the result and try the whole thing again.
5578 //
5579 // Note that this leaves room for optimization. We could just
5580 // memcpy what we already have to the result string. Also,
5581 // the result string is the last object allocated we could
5582 // "realloc" it and probably, in the vast majority of cases,
5583 // extend the existing string to be able to hold the full
5584 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005585 int next_length = 0;
5586 if (has_next) {
5587 next_length = mapping->get(next, 0, chars);
5588 if (next_length == 0) next_length = 1;
5589 }
5590 int current_length = i + char_length + next_length;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00005591 while (stream.HasMore()) {
5592 current = stream.GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005593 // NOTE: we use 0 as the next character here because, while
5594 // the next character may affect what a character converts to,
5595 // it does not in any case affect the length of what it convert
5596 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 int char_length = mapping->get(current, 0, chars);
5598 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005599 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005600 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005602 return Failure::OutOfMemoryException(0x13);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005605 // Try again with the real length.
5606 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 } else {
5608 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005609 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610 i++;
5611 }
5612 has_changed_character = true;
5613 }
5614 current = next;
5615 }
5616 if (has_changed_character) {
5617 return result;
5618 } else {
5619 // If we didn't actually change anything in doing the conversion
5620 // we simple return the result and let the converted string
5621 // become garbage; there is no reason to keep two identical strings
5622 // alive.
5623 return s;
5624 }
5625}
5626
5627
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005628namespace {
5629
lrn@chromium.org303ada72010-10-27 09:33:13 +00005630static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005631#ifdef ENABLE_LATIN_1
5632static const uintptr_t kAsciiMask = kOneInEveryByte << 7;
5633#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005634
5635// Given a word and two range boundaries returns a word with high bit
5636// set in every byte iff the corresponding input byte was strictly in
5637// the range (m, n). All the other bits in the result are cleared.
5638// This function is only useful when it can be inlined and the
5639// boundaries are statically known.
5640// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005641// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005643 // Use strict inequalities since in edge cases the function could be
5644 // further simplified.
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005645 ASSERT(0 < m && m < n);
5646#ifndef ENABLE_LATIN_1
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00005647 // Every byte in an ASCII string is less than or equal to 0x7F.
5648 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005649 ASSERT(n < 0x7F);
5650#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005651 // Has high bit set in every w byte less than n.
5652 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5653 // Has high bit set in every w byte greater than m.
5654 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5655 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5656}
5657
5658
5659enum AsciiCaseConversion {
5660 ASCII_TO_LOWER,
5661 ASCII_TO_UPPER
5662};
5663
5664
5665template <AsciiCaseConversion dir>
5666struct FastAsciiConverter {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005667#ifdef ENABLE_LATIN_1
5668 static bool Convert(char* dst, char* src, int length, bool* changed_out) {
5669#else
lrn@chromium.org303ada72010-10-27 09:33:13 +00005670 static bool Convert(char* dst, char* src, int length) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005671#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005672#ifdef DEBUG
5673 char* saved_dst = dst;
5674 char* saved_src = src;
5675#endif
5676 // We rely on the distance between upper and lower case letters
5677 // being a known power of 2.
5678 ASSERT('a' - 'A' == (1 << 5));
5679 // Boundaries for the range of input characters than require conversion.
5680 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5681 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5682 bool changed = false;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005683#ifdef ENABLE_LATIN_1
5684 uintptr_t or_acc = 0;
5685#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686 char* const limit = src + length;
5687#ifdef V8_HOST_CAN_READ_UNALIGNED
5688 // Process the prefix of the input that requires no conversion one
5689 // (machine) word at a time.
5690 while (src <= limit - sizeof(uintptr_t)) {
5691 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005692#ifdef ENABLE_LATIN_1
5693 or_acc |= w;
5694#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695 if (AsciiRangeMask(w, lo, hi) != 0) {
5696 changed = true;
5697 break;
5698 }
5699 *reinterpret_cast<uintptr_t*>(dst) = w;
5700 src += sizeof(uintptr_t);
5701 dst += sizeof(uintptr_t);
5702 }
5703 // Process the remainder of the input performing conversion when
5704 // required one word at a time.
5705 while (src <= limit - sizeof(uintptr_t)) {
5706 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005707#ifdef ENABLE_LATIN_1
5708 or_acc |= w;
5709#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005710 uintptr_t m = AsciiRangeMask(w, lo, hi);
5711 // The mask has high (7th) bit set in every byte that needs
5712 // conversion and we know that the distance between cases is
5713 // 1 << 5.
5714 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5715 src += sizeof(uintptr_t);
5716 dst += sizeof(uintptr_t);
5717 }
5718#endif
5719 // Process the last few bytes of the input (or the whole input if
5720 // unaligned access is not supported).
5721 while (src < limit) {
5722 char c = *src;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005723#ifdef ENABLE_LATIN_1
5724 or_acc |= c;
5725#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005726 if (lo < c && c < hi) {
5727 c ^= (1 << 5);
5728 changed = true;
5729 }
5730 *dst = c;
5731 ++src;
5732 ++dst;
5733 }
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005734#ifdef ENABLE_LATIN_1
5735 if ((or_acc & kAsciiMask) != 0) {
5736 return false;
5737 }
5738#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005739#ifdef DEBUG
5740 CheckConvert(saved_dst, saved_src, length, changed);
5741#endif
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005742#ifdef ENABLE_LATIN_1
5743 *changed_out = changed;
5744 return true;
5745#else
lrn@chromium.org303ada72010-10-27 09:33:13 +00005746 return changed;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005747#endif
lrn@chromium.org303ada72010-10-27 09:33:13 +00005748 }
5749
5750#ifdef DEBUG
5751 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5752 bool expected_changed = false;
5753 for (int i = 0; i < length; i++) {
5754 if (dst[i] == src[i]) continue;
5755 expected_changed = true;
5756 if (dir == ASCII_TO_LOWER) {
5757 ASSERT('A' <= src[i] && src[i] <= 'Z');
5758 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5759 } else {
5760 ASSERT(dir == ASCII_TO_UPPER);
5761 ASSERT('a' <= src[i] && src[i] <= 'z');
5762 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5763 }
5764 }
5765 ASSERT(expected_changed == changed);
5766 }
5767#endif
5768};
5769
5770
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005771struct ToLowerTraits {
5772 typedef unibrow::ToLowercase UnibrowConverter;
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005775};
5776
5777
5778struct ToUpperTraits {
5779 typedef unibrow::ToUppercase UnibrowConverter;
5780
lrn@chromium.org303ada72010-10-27 09:33:13 +00005781 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005782};
5783
5784} // namespace
5785
5786
5787template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005788MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005789 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005791 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005792 NoHandleAllocation ha(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005793 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005794 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005796 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005797 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 if (length == 0) return s;
5799
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005800 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005802 // NOTE: This assumes that the upper/lower case of an ASCII
5803 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005804 // might break in the future if we implement more context and locale
5805 // dependent upper/lower conversions.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005806 if (s->IsSeqOneByteString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005807 Object* o;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005808 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005809 if (!maybe_o->ToObject(&o)) return maybe_o;
5810 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005811 SeqOneByteString* result = SeqOneByteString::cast(o);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005812#ifndef ENABLE_LATIN_1
lrn@chromium.org303ada72010-10-27 09:33:13 +00005813 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005814 reinterpret_cast<char*>(result->GetChars()),
5815 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
5816 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005817 return has_changed_character ? result : s;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005818#else
5819 bool has_changed_character;
5820 bool is_ascii = ConvertTraits::AsciiConverter::Convert(
5821 reinterpret_cast<char*>(result->GetChars()),
5822 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()),
5823 length,
5824 &has_changed_character);
5825 // If not ASCII, we discard the result and take the 2 byte path.
5826 if (is_ascii) {
5827 return has_changed_character ? result : s;
5828 }
yangguo@chromium.orge19986e2013-01-16 09:48:20 +00005829#endif
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005830 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005831
lrn@chromium.org303ada72010-10-27 09:33:13 +00005832 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005833 { MaybeObject* maybe_answer =
5834 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005835 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5836 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005837 if (answer->IsSmi()) {
5838 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005839 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005840 ConvertCaseHelper(isolate,
5841 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005842 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5843 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005844 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005845 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846}
5847
5848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005849RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 return ConvertCase<ToLowerTraits>(
5851 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005852}
5853
5854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005855RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005856 return ConvertCase<ToUpperTraits>(
5857 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858}
5859
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005861static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00005862 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005863}
5864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005866RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005867 NoHandleAllocation ha(isolate);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005868 ASSERT(args.length() == 3);
5869
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005870 CONVERT_ARG_CHECKED(String, s, 0);
5871 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
5872 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005873
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005874 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005875 int length = s->length();
5876
5877 int left = 0;
5878 if (trimLeft) {
5879 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5880 left++;
5881 }
5882 }
5883
5884 int right = length;
5885 if (trimRight) {
5886 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5887 right--;
5888 }
5889 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005890 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005891}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005895 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005896 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005897 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
5898 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005899 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5900
5901 int subject_length = subject->length();
5902 int pattern_length = pattern->length();
5903 RUNTIME_ASSERT(pattern_length > 0);
5904
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005905 if (limit == 0xffffffffu) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005906 Handle<Object> cached_answer(
5907 RegExpResultsCache::Lookup(isolate->heap(),
5908 *subject,
5909 *pattern,
5910 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS),
5911 isolate);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005912 if (*cached_answer != Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005913 // The cache FixedArray is a COW-array and can therefore be reused.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005914 Handle<JSArray> result =
5915 isolate->factory()->NewJSArrayWithElements(
5916 Handle<FixedArray>::cast(cached_answer));
5917 return *result;
5918 }
5919 }
5920
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005921 // The limit can be very large (0xffffffffu), but since the pattern
5922 // isn't empty, we can never create more parts than ~half the length
5923 // of the subject.
5924
5925 if (!subject->IsFlat()) FlattenString(subject);
5926
5927 static const int kMaxInitialListCapacity = 16;
5928
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00005929 Zone* zone = isolate->runtime_zone();
5930 ZoneScope scope(zone, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005931
5932 // Find (up to limit) indices of separator and end-of-string in subject
5933 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005934 ZoneList<int> indices(initial_capacity, zone);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005935 if (!pattern->IsFlat()) FlattenString(pattern);
5936
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005937 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit, zone);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005938
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005939 if (static_cast<uint32_t>(indices.length()) < limit) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005940 indices.Add(subject_length, zone);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005941 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005942
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005943 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005944
5945 // Create JSArray of substrings separated by separator.
5946 int part_count = indices.length();
5947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005948 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005949 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005950 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005951 result->set_length(Smi::FromInt(part_count));
5952
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005953 ASSERT(result->HasFastObjectElements());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005954
5955 if (part_count == 1 && indices.at(0) == subject_length) {
5956 FixedArray::cast(result->elements())->set(0, *subject);
5957 return *result;
5958 }
5959
5960 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5961 int part_start = 0;
5962 for (int i = 0; i < part_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00005963 HandleScope local_loop_handle(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005964 int part_end = indices.at(i);
5965 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005966 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005967 elements->set(i, *substring);
5968 part_start = part_end + pattern_length;
5969 }
5970
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005971 if (limit == 0xffffffffu) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005972 if (result->HasFastObjectElements()) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005973 RegExpResultsCache::Enter(isolate->heap(),
5974 *subject,
5975 *pattern,
5976 *elements,
5977 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00005978 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005979 }
5980
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005981 return *result;
5982}
5983
5984
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005985// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005986// one-char strings in the cache. Gives up on the first char that is
5987// not in the cache and fills the remainder with smi zeros. Returns
5988// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005989static int CopyCachedAsciiCharsToArray(Heap* heap,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005990 const uint8_t* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005991 FixedArray* elements,
5992 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005993 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994 FixedArray* ascii_cache = heap->single_character_string_cache();
5995 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005996 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005997 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005998 for (i = 0; i < length; ++i) {
5999 Object* value = ascii_cache->get(chars[i]);
6000 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006001 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006002 }
6003 if (i < length) {
6004 ASSERT(Smi::FromInt(0) == 0);
6005 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6006 }
6007#ifdef DEBUG
6008 for (int j = 0; j < length; ++j) {
6009 Object* element = elements->get(j);
6010 ASSERT(element == Smi::FromInt(0) ||
6011 (element->IsString() && String::cast(element)->LooksValid()));
6012 }
6013#endif
6014 return i;
6015}
6016
6017
6018// Converts a String to JSArray.
6019// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006020RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006022 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006023 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006024 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006025
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006026 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006027 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006028
6029 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006030 int position = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006031 if (s->IsFlat() && s->IsOneByteRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006032 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006033 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 { MaybeObject* maybe_obj =
6035 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006036 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6037 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006038 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006039 String::FlatContent content = s->GetFlatContent();
6040 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006041 Vector<const uint8_t> chars = content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006042 // Note, this will initialize all elements (not only the prefix)
6043 // to prevent GC from seeing partially initialized array.
6044 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6045 chars.start(),
6046 *elements,
6047 length);
6048 } else {
6049 MemsetPointer(elements->data_start(),
6050 isolate->heap()->undefined_value(),
6051 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 }
6053 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006055 }
6056 for (int i = position; i < length; ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006057 Handle<Object> str =
6058 LookupSingleCharacterStringFromCode(isolate, s->Get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006059 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006060 }
6061
6062#ifdef DEBUG
6063 for (int i = 0; i < length; ++i) {
6064 ASSERT(String::cast(elements->get(i))->length() == 1);
6065 }
6066#endif
6067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006068 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006069}
6070
6071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006072RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006073 NoHandleAllocation ha(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006074 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006075 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006076 return value->ToObject();
6077}
6078
6079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006080bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006081 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006082 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006083 return char_length == 0;
6084}
6085
6086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006088 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006089 ASSERT(args.length() == 1);
6090
6091 Object* number = args[0];
6092 RUNTIME_ASSERT(number->IsNumber());
6093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006095}
6096
6097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006098RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006099 NoHandleAllocation ha(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +00006100 ASSERT(args.length() == 1);
6101
6102 Object* number = args[0];
6103 RUNTIME_ASSERT(number->IsNumber());
6104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006106}
6107
6108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006110 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006111 ASSERT(args.length() == 1);
6112
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006113 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006114
6115 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6116 if (number > 0 && number <= Smi::kMaxValue) {
6117 return Smi::FromInt(static_cast<int>(number));
6118 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006119 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006120}
6121
6122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006123RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006124 NoHandleAllocation ha(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006125 ASSERT(args.length() == 1);
6126
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006127 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006128
6129 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6130 if (number > 0 && number <= Smi::kMaxValue) {
6131 return Smi::FromInt(static_cast<int>(number));
6132 }
6133
6134 double double_value = DoubleToInteger(number);
6135 // Map both -0 and +0 to +0.
6136 if (double_value == 0) double_value = 0;
6137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006138 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006139}
6140
6141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006142RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006143 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144 ASSERT(args.length() == 1);
6145
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006146 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006147 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006148}
6149
6150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006151RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006152 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 ASSERT(args.length() == 1);
6154
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006155 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156
6157 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6158 if (number > 0 && number <= Smi::kMaxValue) {
6159 return Smi::FromInt(static_cast<int>(number));
6160 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006162}
6163
6164
ager@chromium.org870a0b62008-11-04 11:43:05 +00006165// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6166// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006167RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006168 NoHandleAllocation ha(isolate);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006169 ASSERT(args.length() == 1);
6170
6171 Object* obj = args[0];
6172 if (obj->IsSmi()) {
6173 return obj;
6174 }
6175 if (obj->IsHeapNumber()) {
6176 double value = HeapNumber::cast(obj)->value();
6177 int int_value = FastD2I(value);
6178 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6179 return Smi::FromInt(int_value);
6180 }
6181 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006183}
6184
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006186RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006187 NoHandleAllocation ha(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006188 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006190}
6191
6192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006193RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006194 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195 ASSERT(args.length() == 2);
6196
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006197 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6198 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006199 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
6202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006203RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006204 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205 ASSERT(args.length() == 2);
6206
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006207 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6208 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006209 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006213RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006214 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006215 ASSERT(args.length() == 2);
6216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006217 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6218 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006224 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225 ASSERT(args.length() == 1);
6226
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006227 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006233 NoHandleAllocation ha(isolate);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006234 ASSERT(args.length() == 0);
6235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006237}
6238
6239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006241 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242 ASSERT(args.length() == 2);
6243
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006244 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6245 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006246 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247}
6248
6249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006250RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006251 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 ASSERT(args.length() == 2);
6253
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006254 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6255 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006256
ager@chromium.org3811b432009-10-28 14:53:37 +00006257 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006258 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260}
6261
6262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006263RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006264 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006265 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006266 CONVERT_ARG_CHECKED(String, str1, 0);
6267 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 isolate->counters()->string_add_runtime()->Increment();
6269 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270}
6271
6272
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006273template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006274static inline void StringBuilderConcatHelper(String* special,
6275 sinkchar* sink,
6276 FixedArray* fixed_array,
6277 int array_length) {
6278 int position = 0;
6279 for (int i = 0; i < array_length; i++) {
6280 Object* element = fixed_array->get(i);
6281 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006282 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006283 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006284 int pos;
6285 int len;
6286 if (encoded_slice > 0) {
6287 // Position and length encoded in one smi.
6288 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6289 len = StringBuilderSubstringLength::decode(encoded_slice);
6290 } else {
6291 // Position and length encoded in two smis.
6292 Object* obj = fixed_array->get(++i);
6293 ASSERT(obj->IsSmi());
6294 pos = Smi::cast(obj)->value();
6295 len = -encoded_slice;
6296 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006297 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006298 sink + position,
6299 pos,
6300 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006301 position += len;
6302 } else {
6303 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006304 int element_length = string->length();
6305 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006306 position += element_length;
6307 }
6308 }
6309}
6310
6311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006313 NoHandleAllocation ha(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006314 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006315 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006316 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006317 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006318 return Failure::OutOfMemoryException(0x14);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006319 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006320 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006321 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006322
6323 // This assumption is used by the slice encoding in one or two smis.
6324 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6325
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006326 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006327 if (maybe_result->IsFailure()) return maybe_result;
6328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006329 int special_length = special->length();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006330 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006331 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332 }
6333 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006334 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006335 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337
6338 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006339 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006340 } else if (array_length == 1) {
6341 Object* first = fixed_array->get(0);
6342 if (first->IsString()) return first;
6343 }
6344
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006345 bool one_byte = special->IsOneByteConvertible();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346 int position = 0;
6347 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006348 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006349 Object* elt = fixed_array->get(i);
6350 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006351 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006352 int smi_value = Smi::cast(elt)->value();
6353 int pos;
6354 int len;
6355 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006356 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006357 pos = StringBuilderSubstringPosition::decode(smi_value);
6358 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006359 } else {
6360 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006361 len = -smi_value;
6362 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006363 i++;
6364 if (i >= array_length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006365 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006366 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006367 Object* next_smi = fixed_array->get(i);
6368 if (!next_smi->IsSmi()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006369 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006370 }
6371 pos = Smi::cast(next_smi)->value();
6372 if (pos < 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006373 return isolate->Throw(isolate->heap()->illegal_argument_string());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006374 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006376 ASSERT(pos >= 0);
6377 ASSERT(len >= 0);
6378 if (pos > special_length || len > special_length - pos) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006379 return isolate->Throw(isolate->heap()->illegal_argument_string());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006380 }
6381 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 } else if (elt->IsString()) {
6383 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006384 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006385 increment = element_length;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006386 if (one_byte && !element->IsOneByteConvertible()) {
6387 one_byte = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006390 ASSERT(!elt->IsTheHole());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006391 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006392 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006393 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006395 return Failure::OutOfMemoryException(0x15);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006396 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006397 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 }
6399
6400 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006401 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006402
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006403 if (one_byte) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 { MaybeObject* maybe_object =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006405 isolate->heap()->AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006406 if (!maybe_object->ToObject(&object)) return maybe_object;
6407 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006408 SeqOneByteString* answer = SeqOneByteString::cast(object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006409 StringBuilderConcatHelper(special,
6410 answer->GetChars(),
6411 fixed_array,
6412 array_length);
6413 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006415 { MaybeObject* maybe_object =
6416 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006417 if (!maybe_object->ToObject(&object)) return maybe_object;
6418 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006419 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6420 StringBuilderConcatHelper(special,
6421 answer->GetChars(),
6422 fixed_array,
6423 array_length);
6424 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426}
6427
6428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006429RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006430 NoHandleAllocation ha(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006431 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006432 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006433 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006434 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006435 return Failure::OutOfMemoryException(0x16);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006436 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006437 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006438 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006439
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006440 if (!array->HasFastObjectElements()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006441 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006442 }
6443 FixedArray* fixed_array = FixedArray::cast(array->elements());
6444 if (fixed_array->length() < array_length) {
6445 array_length = fixed_array->length();
6446 }
6447
6448 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006450 } else if (array_length == 1) {
6451 Object* first = fixed_array->get(0);
6452 if (first->IsString()) return first;
6453 }
6454
6455 int separator_length = separator->length();
6456 int max_nof_separators =
6457 (String::kMaxLength + separator_length - 1) / separator_length;
6458 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006460 return Failure::OutOfMemoryException(0x17);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006461 }
6462 int length = (array_length - 1) * separator_length;
6463 for (int i = 0; i < array_length; i++) {
6464 Object* element_obj = fixed_array->get(i);
6465 if (!element_obj->IsString()) {
6466 // TODO(1161): handle this case.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006467 return isolate->Throw(isolate->heap()->illegal_argument_string());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006468 }
6469 String* element = String::cast(element_obj);
6470 int increment = element->length();
6471 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472 isolate->context()->mark_out_of_memory();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006473 return Failure::OutOfMemoryException(0x18);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006474 }
6475 length += increment;
6476 }
6477
6478 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 { MaybeObject* maybe_object =
6480 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006481 if (!maybe_object->ToObject(&object)) return maybe_object;
6482 }
6483 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6484
6485 uc16* sink = answer->GetChars();
6486#ifdef DEBUG
6487 uc16* end = sink + length;
6488#endif
6489
6490 String* first = String::cast(fixed_array->get(0));
6491 int first_length = first->length();
6492 String::WriteToFlat(first, sink, 0, first_length);
6493 sink += first_length;
6494
6495 for (int i = 1; i < array_length; i++) {
6496 ASSERT(sink + separator_length <= end);
6497 String::WriteToFlat(separator, sink, 0, separator_length);
6498 sink += separator_length;
6499
6500 String* element = String::cast(fixed_array->get(i));
6501 int element_length = element->length();
6502 ASSERT(sink + element_length <= end);
6503 String::WriteToFlat(element, sink, 0, element_length);
6504 sink += element_length;
6505 }
6506 ASSERT(sink == end);
6507
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006508 // Use %_FastAsciiArrayJoin instead.
6509 ASSERT(!answer->IsOneByteRepresentation());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006510 return answer;
6511}
6512
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006513template <typename Char>
6514static void JoinSparseArrayWithSeparator(FixedArray* elements,
6515 int elements_length,
6516 uint32_t array_length,
6517 String* separator,
6518 Vector<Char> buffer) {
6519 int previous_separator_position = 0;
6520 int separator_length = separator->length();
6521 int cursor = 0;
6522 for (int i = 0; i < elements_length; i += 2) {
6523 int position = NumberToInt32(elements->get(i));
6524 String* string = String::cast(elements->get(i + 1));
6525 int string_length = string->length();
6526 if (string->length() > 0) {
6527 while (previous_separator_position < position) {
6528 String::WriteToFlat<Char>(separator, &buffer[cursor],
6529 0, separator_length);
6530 cursor += separator_length;
6531 previous_separator_position++;
6532 }
6533 String::WriteToFlat<Char>(string, &buffer[cursor],
6534 0, string_length);
6535 cursor += string->length();
6536 }
6537 }
6538 if (separator_length > 0) {
6539 // Array length must be representable as a signed 32-bit number,
6540 // otherwise the total string length would have been too large.
6541 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6542 int last_array_index = static_cast<int>(array_length - 1);
6543 while (previous_separator_position < last_array_index) {
6544 String::WriteToFlat<Char>(separator, &buffer[cursor],
6545 0, separator_length);
6546 cursor += separator_length;
6547 previous_separator_position++;
6548 }
6549 }
6550 ASSERT(cursor <= buffer.length());
6551}
6552
6553
6554RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006555 NoHandleAllocation ha(isolate);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006556 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006557 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006558 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006559 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006560 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006561 // elements_array is fast-mode JSarray of alternating positions
6562 // (increasing order) and strings.
6563 // array_length is length of original array (used to add separators);
6564 // separator is string to put between elements. Assumed to be non-empty.
6565
6566 // Find total length of join result.
6567 int string_length = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006568 bool is_ascii = separator->IsOneByteRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006569 int max_string_length;
6570 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006571 max_string_length = SeqOneByteString::kMaxLength;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006572 } else {
6573 max_string_length = SeqTwoByteString::kMaxLength;
6574 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006575 bool overflow = false;
6576 CONVERT_NUMBER_CHECKED(int, elements_length,
6577 Int32, elements_array->length());
6578 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6579 FixedArray* elements = FixedArray::cast(elements_array->elements());
6580 for (int i = 0; i < elements_length; i += 2) {
6581 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006582 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6583 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006584 int length = string->length();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006585 if (is_ascii && !string->IsOneByteRepresentation()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006586 is_ascii = false;
6587 max_string_length = SeqTwoByteString::kMaxLength;
6588 }
6589 if (length > max_string_length ||
6590 max_string_length - length < string_length) {
6591 overflow = true;
6592 break;
6593 }
6594 string_length += length;
6595 }
6596 int separator_length = separator->length();
6597 if (!overflow && separator_length > 0) {
6598 if (array_length <= 0x7fffffffu) {
6599 int separator_count = static_cast<int>(array_length) - 1;
6600 int remaining_length = max_string_length - string_length;
6601 if ((remaining_length / separator_length) >= separator_count) {
6602 string_length += separator_length * (array_length - 1);
6603 } else {
6604 // Not room for the separators within the maximal string length.
6605 overflow = true;
6606 }
6607 } else {
6608 // Nonempty separator and at least 2^31-1 separators necessary
6609 // means that the string is too large to create.
6610 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6611 overflow = true;
6612 }
6613 }
6614 if (overflow) {
6615 // Throw OutOfMemory exception for creating too large a string.
6616 V8::FatalProcessOutOfMemory("Array join result too large.");
6617 }
6618
6619 if (is_ascii) {
6620 MaybeObject* result_allocation =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006621 isolate->heap()->AllocateRawOneByteString(string_length);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006622 if (result_allocation->IsFailure()) return result_allocation;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006623 SeqOneByteString* result_string =
6624 SeqOneByteString::cast(result_allocation->ToObjectUnchecked());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006625 JoinSparseArrayWithSeparator<uint8_t>(elements,
6626 elements_length,
6627 array_length,
6628 separator,
6629 Vector<uint8_t>(
6630 result_string->GetChars(),
6631 string_length));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006632 return result_string;
6633 } else {
6634 MaybeObject* result_allocation =
6635 isolate->heap()->AllocateRawTwoByteString(string_length);
6636 if (result_allocation->IsFailure()) return result_allocation;
6637 SeqTwoByteString* result_string =
6638 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6639 JoinSparseArrayWithSeparator<uc16>(elements,
6640 elements_length,
6641 array_length,
6642 separator,
6643 Vector<uc16>(result_string->GetChars(),
6644 string_length));
6645 return result_string;
6646 }
6647}
6648
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006650RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006651 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 ASSERT(args.length() == 2);
6653
6654 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6655 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657}
6658
6659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006661 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662 ASSERT(args.length() == 2);
6663
6664 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6665 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006666 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667}
6668
6669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006670RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006671 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 ASSERT(args.length() == 2);
6673
6674 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6675 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677}
6678
6679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006680RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006681 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682 ASSERT(args.length() == 1);
6683
6684 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006685 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686}
6687
6688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006689RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006690 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691 ASSERT(args.length() == 2);
6692
6693 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6694 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696}
6697
6698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006699RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006700 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 ASSERT(args.length() == 2);
6702
6703 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6704 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006706}
6707
6708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006709RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006710 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 ASSERT(args.length() == 2);
6712
6713 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6714 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006715 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716}
6717
6718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006719RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006720 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 ASSERT(args.length() == 2);
6722
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006723 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6724 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006725 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6726 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6727 if (x == y) return Smi::FromInt(EQUAL);
6728 Object* result;
6729 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6730 result = Smi::FromInt(EQUAL);
6731 } else {
6732 result = Smi::FromInt(NOT_EQUAL);
6733 }
6734 return result;
6735}
6736
6737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006738RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006739 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 ASSERT(args.length() == 2);
6741
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006742 CONVERT_ARG_CHECKED(String, x, 0);
6743 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006745 bool not_equal = !x->Equals(y);
6746 // This is slightly convoluted because the value that signifies
6747 // equality is 0 and inequality is 1 so we have to negate the result
6748 // from String::Equals.
6749 ASSERT(not_equal == 0 || not_equal == 1);
6750 STATIC_CHECK(EQUAL == 0);
6751 STATIC_CHECK(NOT_EQUAL == 1);
6752 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753}
6754
6755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006756RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006757 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 ASSERT(args.length() == 3);
6759
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006760 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6761 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 if (isnan(x) || isnan(y)) return args[2];
6763 if (x == y) return Smi::FromInt(EQUAL);
6764 if (isless(x, y)) return Smi::FromInt(LESS);
6765 return Smi::FromInt(GREATER);
6766}
6767
6768
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006769// Compare two Smis as if they were converted to strings and then
6770// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006771RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006772 NoHandleAllocation ha(isolate);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006773 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006774 CONVERT_SMI_ARG_CHECKED(x_value, 0);
6775 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006776
6777 // If the integers are equal so are the string representations.
6778 if (x_value == y_value) return Smi::FromInt(EQUAL);
6779
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006780 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006781 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006782 if (x_value == 0 || y_value == 0)
6783 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006784
ager@chromium.org32912102009-01-16 10:38:43 +00006785 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006786 // smallest because the char code of '-' is less than the char code
6787 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006788
6789 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6790 // architectures using 32-bit Smis.
6791 uint32_t x_scaled = x_value;
6792 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006793 if (x_value < 0 || y_value < 0) {
6794 if (y_value >= 0) return Smi::FromInt(LESS);
6795 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006796 x_scaled = -x_value;
6797 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006798 }
6799
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006800 static const uint32_t kPowersOf10[] = {
6801 1, 10, 100, 1000, 10*1000, 100*1000,
6802 1000*1000, 10*1000*1000, 100*1000*1000,
6803 1000*1000*1000
6804 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006805
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006806 // If the integers have the same number of decimal digits they can be
6807 // compared directly as the numeric order is the same as the
6808 // lexicographic order. If one integer has fewer digits, it is scaled
6809 // by some power of 10 to have the same number of digits as the longer
6810 // integer. If the scaled integers are equal it means the shorter
6811 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006813 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6814 int x_log2 = IntegerLog2(x_scaled);
6815 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6816 x_log10 -= x_scaled < kPowersOf10[x_log10];
6817
6818 int y_log2 = IntegerLog2(y_scaled);
6819 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6820 y_log10 -= y_scaled < kPowersOf10[y_log10];
6821
6822 int tie = EQUAL;
6823
6824 if (x_log10 < y_log10) {
6825 // X has fewer digits. We would like to simply scale up X but that
6826 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6827 // be scaled up to 9_000_000_000. So we scale up by the next
6828 // smallest power and scale down Y to drop one digit. It is OK to
6829 // drop one digit from the longer integer since the final digit is
6830 // past the length of the shorter integer.
6831 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6832 y_scaled /= 10;
6833 tie = LESS;
6834 } else if (y_log10 < x_log10) {
6835 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6836 x_scaled /= 10;
6837 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006838 }
6839
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006840 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6841 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6842 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006843}
6844
6845
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006846static Object* StringCharacterStreamCompare(RuntimeState* state,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006847 String* x,
6848 String* y) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006849 StringCharacterStream stream_x(x, state->string_iterator_compare_x());
6850 StringCharacterStream stream_y(y, state->string_iterator_compare_y());
6851 while (stream_x.HasMore() && stream_y.HasMore()) {
6852 int d = stream_x.GetNext() - stream_y.GetNext();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006853 if (d < 0) return Smi::FromInt(LESS);
6854 else if (d > 0) return Smi::FromInt(GREATER);
6855 }
6856
6857 // x is (non-trivial) prefix of y:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006858 if (stream_y.HasMore()) return Smi::FromInt(LESS);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006859 // y is prefix of x:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006860 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006861}
6862
6863
6864static Object* FlatStringCompare(String* x, String* y) {
6865 ASSERT(x->IsFlat());
6866 ASSERT(y->IsFlat());
6867 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6868 int prefix_length = x->length();
6869 if (y->length() < prefix_length) {
6870 prefix_length = y->length();
6871 equal_prefix_result = Smi::FromInt(GREATER);
6872 } else if (y->length() > prefix_length) {
6873 equal_prefix_result = Smi::FromInt(LESS);
6874 }
6875 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006876 String::FlatContent x_content = x->GetFlatContent();
6877 String::FlatContent y_content = y->GetFlatContent();
6878 if (x_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006879 Vector<const uint8_t> x_chars = x_content.ToOneByteVector();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006880 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006881 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006882 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006883 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006884 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006885 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6886 }
6887 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006888 Vector<const uc16> x_chars = x_content.ToUC16Vector();
6889 if (y_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00006890 Vector<const uint8_t> y_chars = y_content.ToOneByteVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006891 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6892 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006893 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006894 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6895 }
6896 }
6897 Object* result;
6898 if (r == 0) {
6899 result = equal_prefix_result;
6900 } else {
6901 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6902 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006903 ASSERT(result ==
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006904 StringCharacterStreamCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006905 return result;
6906}
6907
6908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006909RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006910 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911 ASSERT(args.length() == 2);
6912
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006913 CONVERT_ARG_CHECKED(String, x, 0);
6914 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006918 // A few fast case tests before we flatten.
6919 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006920 if (y->length() == 0) {
6921 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006922 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006923 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924 return Smi::FromInt(LESS);
6925 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006926
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006927 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006928 if (d < 0) return Smi::FromInt(LESS);
6929 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006930
lrn@chromium.org303ada72010-10-27 09:33:13 +00006931 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006933 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6934 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006935 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006936 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006939 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00006940 : StringCharacterStreamCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006941}
6942
6943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006944RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006945 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006947 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006948
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006949 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006950 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951}
6952
6953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006954RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006955 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006959 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961}
6962
6963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006964RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006965 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006967 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006969 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006970 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006971}
6972
6973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006974static const double kPiDividedBy4 = 0.78539816339744830962;
6975
6976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006977RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00006978 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006980 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006982 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6983 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984 double result;
6985 if (isinf(x) && isinf(y)) {
6986 // Make sure that the result in case of two infinite arguments
6987 // is a multiple of Pi / 4. The sign of the result is determined
6988 // by the first argument (x) and the sign of the second argument
6989 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990 int multiplier = (x < 0) ? -1 : 1;
6991 if (y < 0) multiplier *= 3;
6992 result = multiplier * kPiDividedBy4;
6993 } else {
6994 result = atan2(x, y);
6995 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006996 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997}
6998
6999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007001 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007005 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007006 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007}
7008
7009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007010RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007011 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007012 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007013 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007015 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017}
7018
7019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007020RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007021 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007023 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007025 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00007026 lazily_initialize_fast_exp();
7027 return isolate->heap()->NumberFromDouble(fast_exp(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028}
7029
7030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007032 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007034 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007036 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038}
7039
7040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007041RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007042 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007046 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048}
7049
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007050// Slow version of Math.pow. We check for fast paths for special cases.
7051// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007052RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007053 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007057 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007058
7059 // If the second argument is a smi, it is much faster to call the
7060 // custom powi() function than the generic pow().
7061 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007062 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007064 }
7065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007066 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00007067 double result = power_helper(x, y);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007068 if (isnan(result)) return isolate->heap()->nan_value();
7069 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070}
7071
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007072// 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 +00007073// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007074RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007075 NoHandleAllocation ha(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007076 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007077 isolate->counters()->math_pow()->Increment();
7078
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007079 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7080 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007081 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007082 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007083 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007084 double result = power_double_double(x, y);
7085 if (isnan(result)) return isolate->heap()->nan_value();
7086 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007087 }
7088}
7089
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007091RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007092 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007094 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007096 if (!args[0]->IsHeapNumber()) {
7097 // Must be smi. Return the argument unchanged for all the other types
7098 // to make fuzz-natives test happy.
7099 return args[0];
7100 }
7101
7102 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7103
7104 double value = number->value();
7105 int exponent = number->get_exponent();
7106 int sign = number->get_sign();
7107
danno@chromium.org160a7b02011-04-18 15:51:38 +00007108 if (exponent < -1) {
7109 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7110 if (sign) return isolate->heap()->minus_zero_value();
7111 return Smi::FromInt(0);
7112 }
7113
7114 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7115 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007116 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007117 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007118 return Smi::FromInt(static_cast<int>(value + 0.5));
7119 }
7120
7121 // If the magnitude is big enough, there's no place for fraction part. If we
7122 // try to add 0.5 to this number, 1.0 will be added instead.
7123 if (exponent >= 52) {
7124 return number;
7125 }
7126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007127 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007128
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007129 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007130 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007131}
7132
7133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007134RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007135 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007136 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007137 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007139 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007140 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007141}
7142
7143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007144RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007145 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007146 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007147 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007148
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007149 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007150 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007151}
7152
7153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007154RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007155 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007156 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007157 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007159 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007160 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007161}
7162
7163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007164RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007165 NoHandleAllocation ha(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007166 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007167
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007168 CONVERT_SMI_ARG_CHECKED(year, 0);
7169 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007170
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007171 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007172}
7173
7174
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007175RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7176 HandleScope scope(isolate);
7177 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007178
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007179 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7180 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7181 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007182
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007183 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007184
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007185 Object* value = NULL;
7186 bool is_value_nan = false;
7187 if (isnan(time)) {
7188 value = isolate->heap()->nan_value();
7189 is_value_nan = true;
7190 } else if (!is_utc &&
7191 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7192 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7193 value = isolate->heap()->nan_value();
7194 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007195 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007196 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7197 if (time < -DateCache::kMaxTimeInMs ||
7198 time > DateCache::kMaxTimeInMs) {
7199 value = isolate->heap()->nan_value();
7200 is_value_nan = true;
7201 } else {
7202 MaybeObject* maybe_result =
7203 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7204 if (!maybe_result->ToObject(&value)) return maybe_result;
7205 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007206 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007207 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007208 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007209}
7210
7211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007212RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007213 HandleScope scope(isolate);
7214 ASSERT(args.length() == 3);
7215
7216 Handle<JSFunction> callee = args.at<JSFunction>(0);
7217 Object** parameters = reinterpret_cast<Object**>(args[1]);
7218 const int argument_count = Smi::cast(args[2])->value();
7219
7220 Handle<JSObject> result =
7221 isolate->factory()->NewArgumentsObject(callee, argument_count);
7222 // Allocate the elements if needed.
7223 int parameter_count = callee->shared()->formal_parameter_count();
7224 if (argument_count > 0) {
7225 if (parameter_count > 0) {
7226 int mapped_count = Min(argument_count, parameter_count);
7227 Handle<FixedArray> parameter_map =
7228 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7229 parameter_map->set_map(
7230 isolate->heap()->non_strict_arguments_elements_map());
7231
7232 Handle<Map> old_map(result->map());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007233 Handle<Map> new_map = isolate->factory()->CopyMap(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007234 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007235
7236 result->set_map(*new_map);
7237 result->set_elements(*parameter_map);
7238
7239 // Store the context and the arguments array at the beginning of the
7240 // parameter map.
7241 Handle<Context> context(isolate->context());
7242 Handle<FixedArray> arguments =
7243 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7244 parameter_map->set(0, *context);
7245 parameter_map->set(1, *arguments);
7246
7247 // Loop over the actual parameters backwards.
7248 int index = argument_count - 1;
7249 while (index >= mapped_count) {
7250 // These go directly in the arguments array and have no
7251 // corresponding slot in the parameter map.
7252 arguments->set(index, *(parameters - index - 1));
7253 --index;
7254 }
7255
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007256 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007257 while (index >= 0) {
7258 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007259 Handle<String> name(scope_info->ParameterName(index));
7260 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007261 bool duplicate = false;
7262 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007263 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007264 duplicate = true;
7265 break;
7266 }
7267 }
7268
7269 if (duplicate) {
7270 // This goes directly in the arguments array with a hole in the
7271 // parameter map.
7272 arguments->set(index, *(parameters - index - 1));
7273 parameter_map->set_the_hole(index + 2);
7274 } else {
7275 // The context index goes in the parameter map with a hole in the
7276 // arguments array.
7277 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007278 for (int j = 0; j < context_local_count; ++j) {
7279 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007280 context_index = j;
7281 break;
7282 }
7283 }
7284 ASSERT(context_index >= 0);
7285 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007286 parameter_map->set(index + 2, Smi::FromInt(
7287 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007288 }
7289
7290 --index;
7291 }
7292 } else {
7293 // If there is no aliasing, the arguments object elements are not
7294 // special in any way.
7295 Handle<FixedArray> elements =
7296 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7297 result->set_elements(*elements);
7298 for (int i = 0; i < argument_count; ++i) {
7299 elements->set(i, *(parameters - i - 1));
7300 }
7301 }
7302 }
7303 return *result;
7304}
7305
7306
7307RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007308 NoHandleAllocation ha(isolate);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007309 ASSERT(args.length() == 3);
7310
7311 JSFunction* callee = JSFunction::cast(args[0]);
7312 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007313 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007314
lrn@chromium.org303ada72010-10-27 09:33:13 +00007315 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 { MaybeObject* maybe_result =
7317 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007318 if (!maybe_result->ToObject(&result)) return maybe_result;
7319 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007320 // Allocate the elements if needed.
7321 if (length > 0) {
7322 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007323 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007324 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007325 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7326 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007327
7328 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007329 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007330 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007331 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007332
7333 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007334 for (int i = 0; i < length; i++) {
7335 array->set(i, *--parameters, mode);
7336 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007337 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007338 }
7339 return result;
7340}
7341
7342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007343RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007345 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007346 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7347 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7348 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349
whesse@chromium.org7b260152011-06-20 15:33:18 +00007350 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007351 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007352 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7355 context,
7356 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357 return *result;
7358}
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007361// Find the arguments of the JavaScript function invocation that called
7362// into C++ code. Collect these in a newly allocated array of handles (possibly
7363// prefixed by a number of empty handles).
7364static SmartArrayPointer<Handle<Object> > GetCallerArguments(
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00007365 Isolate* isolate,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007366 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007367 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368 // Find frame containing arguments passed to the caller.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00007369 JavaScriptFrameIterator it(isolate);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370 JavaScriptFrame* frame = it.frame();
7371 List<JSFunction*> functions(2);
7372 frame->GetFunctions(&functions);
7373 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007374 int inlined_jsframe_index = functions.length() - 1;
7375 JSFunction* inlined_function = functions[inlined_jsframe_index];
7376 Vector<SlotRef> args_slots =
7377 SlotRef::ComputeSlotMappingForArguments(
7378 frame,
7379 inlined_jsframe_index,
7380 inlined_function->shared()->formal_parameter_count());
7381
7382 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007384 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007385 SmartArrayPointer<Handle<Object> > param_data(
7386 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007387 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007388 Handle<Object> val = args_slots[i].GetValue(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007389 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007390 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007391
7392 args_slots.Dispose();
7393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007394 return param_data;
7395 } else {
7396 it.AdvanceToArgumentsFrame();
7397 frame = it.frame();
7398 int args_count = frame->ComputeParametersCount();
7399
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007400 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007401 SmartArrayPointer<Handle<Object> > param_data(
7402 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403 for (int i = 0; i < args_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007404 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007405 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007406 }
7407 return param_data;
7408 }
7409}
7410
7411
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007412RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7413 HandleScope scope(isolate);
7414 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007415 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007416 RUNTIME_ASSERT(args[3]->IsNumber());
7417 Handle<Object> bindee = args.at<Object>(1);
7418
7419 // TODO(lrn): Create bound function in C++ code from premade shared info.
7420 bound_function->shared()->set_bound(true);
7421 // Get all arguments of calling function (Function.prototype.bind).
7422 int argc = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00007423 SmartArrayPointer<Handle<Object> > arguments =
7424 GetCallerArguments(isolate, 0, &argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007425 // Don't count the this-arg.
7426 if (argc > 0) {
7427 ASSERT(*arguments[0] == args[2]);
7428 argc--;
7429 } else {
7430 ASSERT(args[2]->IsUndefined());
7431 }
7432 // Initialize array of bindings (function, this, and any existing arguments
7433 // if the function was already bound).
7434 Handle<FixedArray> new_bindings;
7435 int i;
7436 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7437 Handle<FixedArray> old_bindings(
7438 JSFunction::cast(*bindee)->function_bindings());
7439 new_bindings =
7440 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007441 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex),
7442 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007443 i = 0;
7444 for (int n = old_bindings->length(); i < n; i++) {
7445 new_bindings->set(i, old_bindings->get(i));
7446 }
7447 } else {
7448 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7449 new_bindings = isolate->factory()->NewFixedArray(array_size);
7450 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7451 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7452 i = 2;
7453 }
7454 // Copy arguments, skipping the first which is "this_arg".
7455 for (int j = 0; j < argc; j++, i++) {
7456 new_bindings->set(i, *arguments[j + 1]);
7457 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007458 new_bindings->set_map_no_write_barrier(
7459 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007460 bound_function->set_function_bindings(*new_bindings);
7461
7462 // Update length.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007463 Handle<String> length_string = isolate->factory()->length_string();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007464 Handle<Object> new_length(args.at<Object>(3));
7465 PropertyAttributes attr =
7466 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007467 ForceSetProperty(bound_function, length_string, new_length, attr);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007468 return *bound_function;
7469}
7470
7471
7472RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7473 HandleScope handles(isolate);
7474 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007475 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007476 if (callable->IsJSFunction()) {
7477 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7478 if (function->shared()->bound()) {
7479 Handle<FixedArray> bindings(function->function_bindings());
7480 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7481 return *isolate->factory()->NewJSArrayWithElements(bindings);
7482 }
7483 }
7484 return isolate->heap()->undefined_value();
7485}
7486
7487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007488RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007490 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007491 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007492 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007493 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007494
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007495 // The argument is a bound function. Extract its bound arguments
7496 // and callable.
7497 Handle<FixedArray> bound_args =
7498 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7499 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7500 Handle<Object> bound_function(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007501 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)),
7502 isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007503 ASSERT(!bound_function->IsJSFunction() ||
7504 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007506 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007507 SmartArrayPointer<Handle<Object> > param_data =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00007508 GetCallerArguments(isolate, bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007509 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007510 param_data[i] = Handle<Object>(bound_args->get(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007511 JSFunction::kBoundArgumentsStartIndex + i), isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007512 }
7513
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007514 if (!bound_function->IsJSFunction()) {
7515 bool exception_thrown;
7516 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7517 &exception_thrown);
7518 if (exception_thrown) return Failure::Exception();
7519 }
7520 ASSERT(bound_function->IsJSFunction());
7521
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007522 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007523 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007524 Execution::New(Handle<JSFunction>::cast(bound_function),
7525 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007526 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007527 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007528 }
7529 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007530 return *result;
7531}
7532
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534static void TrySettingInlineConstructStub(Isolate* isolate,
7535 Handle<JSFunction> function) {
7536 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007537 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007539 }
7540 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007541 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007542 Handle<Code> code = compiler.CompileConstructStub(function);
7543 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007544 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007545}
7546
7547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007548RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007549 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007550 ASSERT(args.length() == 1);
7551
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007552 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007554 // If the constructor isn't a proper function we throw a type error.
7555 if (!constructor->IsJSFunction()) {
7556 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7557 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007558 isolate->factory()->NewTypeError("not_constructor", arguments);
7559 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007560 }
7561
7562 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007563
7564 // If function should not have prototype, construction is not allowed. In this
7565 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007566 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007567 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7568 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 isolate->factory()->NewTypeError("not_constructor", arguments);
7570 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007571 }
7572
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007573#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007574 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007575 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007576 if (debug->StepInActive()) {
7577 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007578 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007579#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007581 if (function->has_initial_map()) {
7582 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583 // The 'Function' function ignores the receiver object when
7584 // called using 'new' and creates a new JSFunction object that
7585 // is returned. The receiver object is only used for error
7586 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007587 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007588 // allocate JSFunctions since it does not properly initialize
7589 // the shared part of the function. Since the receiver is
7590 // ignored anyway, we use the global object as the receiver
7591 // instead of a new JSFunction object. This way, errors are
7592 // reported the same way whether or not 'Function' is called
7593 // using 'new'.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007594 return isolate->context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596 }
7597
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007598 // The function should be compiled for the optimization hints to be
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007599 // available.
7600 JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007601
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007602 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007603 if (!function->has_initial_map() &&
7604 shared->IsInobjectSlackTrackingInProgress()) {
7605 // The tracking is already in progress for another function. We can only
7606 // track one initial_map at a time, so we force the completion before the
7607 // function is called as a constructor for the first time.
7608 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007609 }
7610
7611 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007612 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7613 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007614 // Delay setting the stub if inobject slack tracking is in progress.
7615 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007616 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007617 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007619 isolate->counters()->constructed_objects()->Increment();
7620 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007621
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007622 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007623}
7624
7625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007626RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007628 ASSERT(args.length() == 1);
7629
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007630 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007631 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007632 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007635}
7636
7637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007638RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007639 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007640 ASSERT(args.length() == 1);
7641
7642 Handle<JSFunction> function = args.at<JSFunction>(0);
7643#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007644 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007645 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007646 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007647 PrintF("]\n");
7648 }
7649#endif
7650
lrn@chromium.org34e60782011-09-15 07:25:40 +00007651 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007653 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007654 return Failure::Exception();
7655 }
7656
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007657 // All done. Return the compiled code.
7658 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007659 return function->code();
7660}
7661
7662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007663RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007664 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007665 ASSERT(args.length() == 1);
7666 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00007667
7668 // If the function is not compiled ignore the lazy
7669 // recompilation. This can happen if the debugger is activated and
7670 // the function is returned to the not compiled state.
7671 if (!function->shared()->is_compiled()) {
7672 function->ReplaceCode(function->shared()->code());
7673 return function->code();
7674 }
7675
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007676 // If the function is not optimizable or debugger is active continue using the
7677 // code from the full compiler.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007678 if (!FLAG_crankshaft ||
7679 !function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007680 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007681 if (FLAG_trace_opt) {
7682 PrintF("[failed to optimize ");
7683 function->PrintName();
7684 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7685 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007686 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007687 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007688 function->ReplaceCode(function->shared()->code());
7689 return function->code();
7690 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007691 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007692 if (JSFunction::CompileOptimized(function,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007693 BailoutId::None(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007694 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007695 return function->code();
7696 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007697 if (FLAG_trace_opt) {
7698 PrintF("[failed to optimize ");
7699 function->PrintName();
7700 PrintF(": optimized compilation failed]\n");
7701 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007702 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007703 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007704}
7705
7706
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007707RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) {
7708 HandleScope handle_scope(isolate);
7709 ASSERT(FLAG_parallel_recompilation);
7710 Compiler::RecompileParallel(args.at<JSFunction>(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007711 return isolate->heap()->undefined_value();
7712}
7713
7714
7715RUNTIME_FUNCTION(MaybeObject*, Runtime_ForceParallelRecompile) {
7716 if (!V8::UseCrankshaft()) return isolate->heap()->undefined_value();
7717 HandleScope handle_scope(isolate);
7718 ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation);
7719 if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00007720 return isolate->Throw(*isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007721 STATIC_ASCII_VECTOR("Recompile queue is full.")));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007722 }
7723 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
7724 fun->ReplaceCode(isolate->builtins()->builtin(Builtins::kParallelRecompile));
7725 Compiler::RecompileParallel(fun);
7726 return isolate->heap()->undefined_value();
7727}
7728
7729
7730RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) {
7731 if (!V8::UseCrankshaft()) return isolate->heap()->undefined_value();
7732 HandleScope handle_scope(isolate);
7733 ASSERT(FLAG_parallel_recompilation && FLAG_manual_parallel_recompilation);
7734 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
7735 OptimizingCompilerThread* opt_thread = isolate->optimizing_compiler_thread();
7736 Handle<SharedFunctionInfo> shared(fun->shared());
7737 while (*opt_thread->InstallNextOptimizedFunction() != *shared) { }
7738 return isolate->heap()->undefined_value();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007739}
7740
7741
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007742class ActivationsFinder : public ThreadVisitor {
7743 public:
7744 explicit ActivationsFinder(JSFunction* function)
7745 : function_(function), has_activations_(false) {}
7746
7747 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
7748 if (has_activations_) return;
7749
7750 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
7751 JavaScriptFrame* frame = it.frame();
7752 if (frame->is_optimized() && frame->function() == function_) {
7753 has_activations_ = true;
7754 return;
7755 }
7756 }
7757 }
7758
7759 bool has_activations() { return has_activations_; }
7760
7761 private:
7762 JSFunction* function_;
7763 bool has_activations_;
7764};
7765
7766
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007767RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007768 HandleScope scope(isolate);
7769 ASSERT(args.length() == 0);
7770 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7771 ASSERT(isolate->heap()->IsAllocationAllowed());
7772 ASSERT(deoptimizer->compiled_code_kind() == Code::COMPILED_STUB);
7773 delete deoptimizer;
7774 return isolate->heap()->undefined_value();
7775}
7776
7777
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007778RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
7779 HandleScope scope(isolate);
7780 ASSERT(args.length() == 1);
7781 RUNTIME_ASSERT(args[0]->IsSmi());
7782 Deoptimizer::BailoutType type =
7783 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
7784 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7785 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007786
7787 ASSERT(deoptimizer->compiled_code_kind() != Code::COMPILED_STUB);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007788
7789 // Make sure to materialize objects before causing any allocation.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007790 JavaScriptFrameIterator it(isolate);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007791 deoptimizer->MaterializeHeapObjects(&it);
7792 delete deoptimizer;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007793
7794 JavaScriptFrame* frame = it.frame();
7795 RUNTIME_ASSERT(frame->function()->IsJSFunction());
7796 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007797 RUNTIME_ASSERT(type != Deoptimizer::EAGER || function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007798
7799 // Avoid doing too much work when running with --always-opt and keep
7800 // the optimized code around.
7801 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007802 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007803 }
7804
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00007805 // Find other optimized activations of the function or functions that
7806 // share the same optimized code.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007807 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007808 while (!it.done()) {
7809 JavaScriptFrame* frame = it.frame();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00007810 JSFunction* other_function = JSFunction::cast(frame->function());
7811 if (frame->is_optimized() && other_function->code() == function->code()) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007812 has_other_activations = true;
7813 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007814 }
7815 it.Advance();
7816 }
7817
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007818 if (!has_other_activations) {
7819 ActivationsFinder activations_finder(*function);
7820 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
7821 has_other_activations = activations_finder.has_activations();
7822 }
7823
7824 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007825 if (FLAG_trace_deopt) {
7826 PrintF("[removing optimized code for: ");
7827 function->PrintName();
7828 PrintF("]\n");
7829 }
7830 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00007831 } else {
7832 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007834 // Flush optimized code cache for this function.
7835 function->shared()->ClearOptimizedCodeMap();
7836
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007837 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007838}
7839
7840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007841RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007843 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007844 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007845}
7846
7847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007848RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007849 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007851 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007853
7854 Deoptimizer::DeoptimizeFunction(*function);
7855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007856 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007857}
7858
7859
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007860RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
7861 HandleScope scope(isolate);
7862 ASSERT(args.length() == 1);
7863 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
7864 Code* unoptimized = function->shared()->code();
7865 if (unoptimized->kind() == Code::FUNCTION) {
7866 unoptimized->ClearInlineCaches();
7867 unoptimized->ClearTypeFeedbackCells(isolate->heap());
7868 }
7869 return isolate->heap()->undefined_value();
7870}
7871
7872
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007873RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7874#if defined(USE_SIMULATOR)
7875 return isolate->heap()->true_value();
7876#else
7877 return isolate->heap()->false_value();
7878#endif
7879}
7880
7881
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007882RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7883 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007884 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007885 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007886
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007887 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7888 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007889
7890 Code* unoptimized = function->shared()->code();
7891 if (args.length() == 2 &&
7892 unoptimized->kind() == Code::FUNCTION) {
7893 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007894 CHECK(type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr")));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007895 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
7896 unoptimized->set_allow_osr_at_loop_nesting_level(
7897 Code::kMaxLoopNestingMarker);
7898 }
7899
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007900 return isolate->heap()->undefined_value();
7901}
7902
7903
lrn@chromium.org1c092762011-05-09 09:42:16 +00007904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7905 HandleScope scope(isolate);
7906 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007907 // The least significant bit (after untagging) indicates whether the
7908 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00007909 if (!V8::UseCrankshaft()) {
7910 return Smi::FromInt(4); // 4 == "never".
7911 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007912 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007913 if (FLAG_parallel_recompilation) {
7914 if (function->IsMarkedForLazyRecompilation()) {
7915 return Smi::FromInt(5);
7916 }
7917 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00007918 if (FLAG_always_opt) {
7919 // We may have always opt, but that is more best-effort than a real
7920 // promise, so we still say "no" if it is not optimized.
7921 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
7922 : Smi::FromInt(2); // 2 == "no".
7923 }
lrn@chromium.org1c092762011-05-09 09:42:16 +00007924 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7925 : Smi::FromInt(2); // 2 == "no".
7926}
7927
7928
7929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7930 HandleScope scope(isolate);
7931 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007932 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00007933 return Smi::FromInt(function->shared()->opt_count());
7934}
7935
7936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007937RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007939 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007940 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007941
7942 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007943 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007944
7945 // We have hit a back edge in an unoptimized frame for a function that was
7946 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007948 // Keep track of whether we've succeeded in optimizing.
7949 bool succeeded = unoptimized->optimizable();
7950 if (succeeded) {
7951 // If we are trying to do OSR when there are already optimized
7952 // activations of the function, it means (a) the function is directly or
7953 // indirectly recursive and (b) an optimized invocation has been
7954 // deoptimized so that we are currently in an unoptimized activation.
7955 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007956 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007957 while (succeeded && !it.done()) {
7958 JavaScriptFrame* frame = it.frame();
7959 succeeded = !frame->is_optimized() || frame->function() != *function;
7960 it.Advance();
7961 }
7962 }
7963
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007964 BailoutId ast_id = BailoutId::None();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007965 if (succeeded) {
7966 // The top JS function is this one, the PC is somewhere in the
7967 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007968 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007969 JavaScriptFrame* frame = it.frame();
7970 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007971 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007972 ASSERT(unoptimized->contains(frame->pc()));
7973
7974 // Use linear search of the unoptimized code's stack check table to find
7975 // the AST id matching the PC.
7976 Address start = unoptimized->instruction_start();
7977 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007978 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007979 uint32_t table_length = Memory::uint32_at(table_cursor);
7980 table_cursor += kIntSize;
7981 for (unsigned i = 0; i < table_length; ++i) {
7982 // Table entries are (AST id, pc offset) pairs.
7983 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7984 if (pc_offset == target_pc_offset) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007985 ast_id = BailoutId(static_cast<int>(Memory::uint32_at(table_cursor)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007986 break;
7987 }
7988 table_cursor += 2 * kIntSize;
7989 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007990 ASSERT(!ast_id.IsNone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007991 if (FLAG_trace_osr) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007992 PrintF("[replacing on-stack at AST id %d in ", ast_id.ToInt());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007993 function->PrintName();
7994 PrintF("]\n");
7995 }
7996
7997 // Try to compile the optimized code. A true return value from
7998 // CompileOptimized means that compilation succeeded, not necessarily
7999 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008000 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008001 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008002 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8003 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008004 if (data->OsrPcOffset()->value() >= 0) {
8005 if (FLAG_trace_osr) {
8006 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008007 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008008 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00008009 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008010 } else {
8011 // We may never generate the desired OSR entry if we emit an
8012 // early deoptimize.
8013 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008014 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008015 } else {
8016 succeeded = false;
8017 }
8018 }
8019
8020 // Revert to the original stack checks in the original unoptimized code.
8021 if (FLAG_trace_osr) {
8022 PrintF("[restoring original stack checks in ");
8023 function->PrintName();
8024 PrintF("]\n");
8025 }
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00008026 InterruptStub interrupt_stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00008027 Handle<Code> check_code = interrupt_stub.GetCode(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008028 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008029 Deoptimizer::RevertStackCheckCode(*unoptimized,
8030 *check_code,
8031 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008032
8033 // Allow OSR only at nesting level zero again.
8034 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8035
8036 // If the optimization attempt succeeded, return the AST id tagged as a
8037 // smi. This tells the builtin that we need to translate the unoptimized
8038 // frame to an optimized one.
8039 if (succeeded) {
8040 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00008041 return Smi::FromInt(ast_id.ToInt());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008042 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008043 if (function->IsMarkedForLazyRecompilation()) {
8044 function->ReplaceCode(function->shared()->code());
8045 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008046 return Smi::FromInt(-1);
8047 }
8048}
8049
8050
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008051RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8052 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8053 return isolate->heap()->undefined_value();
8054}
8055
8056
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008057RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8058 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8059 return isolate->heap()->nan_value();
8060}
8061
8062
danno@chromium.orgc612e022011-11-10 11:38:15 +00008063RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8064 HandleScope scope(isolate);
8065 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008066 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008067 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8068 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008069
8070 // If there are too many arguments, allocate argv via malloc.
8071 const int argv_small_size = 10;
8072 Handle<Object> argv_small_buffer[argv_small_size];
8073 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8074 Handle<Object>* argv = argv_small_buffer;
8075 if (argc > argv_small_size) {
8076 argv = new Handle<Object>[argc];
8077 if (argv == NULL) return isolate->StackOverflow();
8078 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8079 }
8080
8081 for (int i = 0; i < argc; ++i) {
8082 MaybeObject* maybe = args[1 + i];
8083 Object* object;
8084 if (!maybe->To<Object>(&object)) return maybe;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008085 argv[i] = Handle<Object>(object, isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008086 }
8087
8088 bool threw;
8089 Handle<JSReceiver> hfun(fun);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008090 Handle<Object> hreceiver(receiver, isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008091 Handle<Object> result =
8092 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8093
8094 if (threw) return Failure::Exception();
8095 return *result;
8096}
8097
8098
lrn@chromium.org34e60782011-09-15 07:25:40 +00008099RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8100 HandleScope scope(isolate);
8101 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008102 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008103 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008104 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008105 CONVERT_SMI_ARG_CHECKED(offset, 3);
8106 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008107 ASSERT(offset >= 0);
8108 ASSERT(argc >= 0);
8109
8110 // If there are too many arguments, allocate argv via malloc.
8111 const int argv_small_size = 10;
8112 Handle<Object> argv_small_buffer[argv_small_size];
8113 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8114 Handle<Object>* argv = argv_small_buffer;
8115 if (argc > argv_small_size) {
8116 argv = new Handle<Object>[argc];
8117 if (argv == NULL) return isolate->StackOverflow();
8118 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8119 }
8120
8121 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008122 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008123 }
8124
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008125 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008126 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008127 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008128
8129 if (threw) return Failure::Exception();
8130 return *result;
8131}
8132
8133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008134RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008135 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136 ASSERT(args.length() == 1);
8137 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8138 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8139}
8140
8141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008142RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008143 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008144 ASSERT(args.length() == 1);
8145 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8146 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8147}
8148
8149
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008150RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008151 NoHandleAllocation ha(isolate);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008152 ASSERT(args.length() == 2);
8153
8154 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8155 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1);
8156 Context* result;
8157 MaybeObject* maybe_result =
8158 isolate->heap()->AllocateGlobalContext(function, scope_info);
8159 if (!maybe_result->To(&result)) return maybe_result;
8160
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008161 ASSERT(function->context() == isolate->context());
8162 ASSERT(function->context()->global_object() == result->global_object());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008163 isolate->set_context(result);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00008164 result->global_object()->set_global_context(result);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008165
8166 return result; // non-failure
8167}
8168
8169
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008170RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008171 NoHandleAllocation ha(isolate);
kasper.lund7276f142008-07-30 08:49:36 +00008172 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008174 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008175 int length = function->shared()->scope_info()->ContextLength();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008176 Context* result;
8177 MaybeObject* maybe_result =
8178 isolate->heap()->AllocateFunctionContext(length, function);
8179 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008180
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008181 isolate->set_context(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008182
kasper.lund7276f142008-07-30 08:49:36 +00008183 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008184}
8185
lrn@chromium.org303ada72010-10-27 09:33:13 +00008186
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008187RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008188 NoHandleAllocation ha(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008189 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008190 JSObject* extension_object;
8191 if (args[0]->IsJSObject()) {
8192 extension_object = JSObject::cast(args[0]);
8193 } else {
8194 // Convert the object to a proper JavaScript object.
8195 MaybeObject* maybe_js_object = args[0]->ToObject();
8196 if (!maybe_js_object->To(&extension_object)) {
8197 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8198 HandleScope scope(isolate);
8199 Handle<Object> handle = args.at<Object>(0);
8200 Handle<Object> result =
8201 isolate->factory()->NewTypeError("with_expression",
8202 HandleVector(&handle, 1));
8203 return isolate->Throw(*result);
8204 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008205 return maybe_js_object;
8206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207 }
8208 }
8209
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008210 JSFunction* function;
8211 if (args[1]->IsSmi()) {
8212 // A smi sentinel indicates a context nested inside global code rather
8213 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008214 // gotten from the native context.
8215 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008216 } else {
8217 function = JSFunction::cast(args[1]);
8218 }
8219
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008220 Context* context;
8221 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008222 isolate->heap()->AllocateWithContext(function,
8223 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008224 extension_object);
8225 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008226 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008227 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008228}
8229
8230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008231RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008232 NoHandleAllocation ha(isolate);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008233 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008234 String* name = String::cast(args[0]);
8235 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008236 JSFunction* function;
8237 if (args[2]->IsSmi()) {
8238 // A smi sentinel indicates a context nested inside global code rather
8239 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008240 // gotten from the native context.
8241 function = isolate->context()->native_context()->closure();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008242 } else {
8243 function = JSFunction::cast(args[2]);
8244 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008245 Context* context;
8246 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008247 isolate->heap()->AllocateCatchContext(function,
8248 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008249 name,
8250 thrown_object);
8251 if (!maybe_context->To(&context)) return maybe_context;
8252 isolate->set_context(context);
8253 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008254}
8255
8256
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008258 NoHandleAllocation ha(isolate);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008259 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008260 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008261 JSFunction* function;
8262 if (args[1]->IsSmi()) {
8263 // A smi sentinel indicates a context nested inside global code rather
8264 // than some function. There is a canonical empty function that can be
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008265 // gotten from the native context.
8266 function = isolate->context()->native_context()->closure();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008267 } else {
8268 function = JSFunction::cast(args[1]);
8269 }
8270 Context* context;
8271 MaybeObject* maybe_context =
8272 isolate->heap()->AllocateBlockContext(function,
8273 isolate->context(),
8274 scope_info);
8275 if (!maybe_context->To(&context)) return maybe_context;
8276 isolate->set_context(context);
8277 return context;
8278}
8279
8280
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008281RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) {
8282 ASSERT(args.length() == 1);
8283 Object* obj = args[0];
8284 return isolate->heap()->ToBoolean(obj->IsJSModule());
8285}
8286
8287
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008288RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008289 ASSERT(args.length() == 2);
8290 CONVERT_SMI_ARG_CHECKED(index, 0);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008291
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008292 if (!args[1]->IsScopeInfo()) {
8293 // Module already initialized. Find hosting context and retrieve context.
8294 Context* host = Context::cast(isolate->context())->global_context();
8295 Context* context = Context::cast(host->get(index));
8296 ASSERT(context->previous() == isolate->context());
8297 isolate->set_context(context);
8298 return context;
8299 }
8300
8301 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
8302
8303 // Allocate module context.
8304 HandleScope scope(isolate);
8305 Factory* factory = isolate->factory();
8306 Handle<Context> context = factory->NewModuleContext(scope_info);
8307 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
8308 context->set_module(*module);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008309 Context* previous = isolate->context();
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008310 context->set_previous(previous);
8311 context->set_closure(previous->closure());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008312 context->set_global_object(previous->global_object());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008313 isolate->set_context(*context);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008314
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008315 // Find hosting scope and initialize internal variable holding module there.
8316 previous->global_context()->set(index, *context);
8317
8318 return *context;
8319}
8320
8321
8322RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) {
8323 HandleScope scope(isolate);
8324 ASSERT(args.length() == 1);
8325 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
8326 Context* host_context = isolate->context();
8327
8328 for (int i = 0; i < descriptions->length(); ++i) {
8329 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
8330 int host_index = description->host_index();
8331 Handle<Context> context(Context::cast(host_context->get(host_index)));
8332 Handle<JSModule> module(context->module());
8333
8334 for (int j = 0; j < description->length(); ++j) {
8335 Handle<String> name(description->name(j));
8336 VariableMode mode = description->mode(j);
8337 int index = description->index(j);
8338 switch (mode) {
8339 case VAR:
8340 case LET:
8341 case CONST:
8342 case CONST_HARMONY: {
8343 PropertyAttributes attr =
8344 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
8345 Handle<AccessorInfo> info =
8346 Accessors::MakeModuleExport(name, index, attr);
8347 Handle<Object> result = SetAccessor(module, info);
8348 ASSERT(!(result.is_null() || result->IsUndefined()));
8349 USE(result);
8350 break;
8351 }
8352 case MODULE: {
8353 Object* referenced_context = Context::cast(host_context)->get(index);
8354 Handle<JSModule> value(Context::cast(referenced_context)->module());
8355 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode);
8356 break;
8357 }
8358 case INTERNAL:
8359 case TEMPORARY:
8360 case DYNAMIC:
8361 case DYNAMIC_GLOBAL:
8362 case DYNAMIC_LOCAL:
8363 UNREACHABLE();
8364 }
8365 }
8366
8367 JSObject::PreventExtensions(module);
8368 }
8369
8370 ASSERT(!isolate->has_pending_exception());
8371 return isolate->heap()->undefined_value();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008372}
8373
8374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008375RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377 ASSERT(args.length() == 2);
8378
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008379 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8380 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008381
8382 int index;
8383 PropertyAttributes attributes;
8384 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008385 BindingFlags binding_flags;
8386 Handle<Object> holder = context->Lookup(name,
8387 flags,
8388 &index,
8389 &attributes,
8390 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008391
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008392 // If the slot was not found the result is true.
8393 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008394 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008395 }
8396
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008397 // If the slot was found in a context, it should be DONT_DELETE.
8398 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008399 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008400 }
8401
8402 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008403 // the global object, or the subject of a with. Try to delete it
8404 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008405 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008406 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407}
8408
8409
ager@chromium.orga1645e22009-09-09 19:27:10 +00008410// A mechanism to return a pair of Object pointers in registers (if possible).
8411// How this is achieved is calling convention-dependent.
8412// All currently supported x86 compiles uses calling conventions that are cdecl
8413// variants where a 64-bit value is returned in two 32-bit registers
8414// (edx:eax on ia32, r1:r0 on ARM).
8415// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8416// In Win64 calling convention, a struct of two pointers is returned in memory,
8417// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008418#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008419struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008420 MaybeObject* x;
8421 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008422};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008423
lrn@chromium.org303ada72010-10-27 09:33:13 +00008424static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008425 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008426 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8427 // In Win64 they are assigned to a hidden first argument.
8428 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008429}
8430#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008431typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008432static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008433 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008434 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008436#endif
8437
8438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439static inline MaybeObject* Unhole(Heap* heap,
8440 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008441 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008442 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8443 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008444 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008445}
8446
8447
danno@chromium.org40cb8782011-05-25 07:58:50 +00008448static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8449 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008450 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008451 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008452 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008453 JSFunction* context_extension_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008454 top->native_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008455 // If the holder isn't a context extension object, we just return it
8456 // as the receiver. This allows arguments objects to be used as
8457 // receivers, but only if they are put in the context scope chain
8458 // explicitly via a with-statement.
8459 Object* constructor = holder->map()->constructor();
8460 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008461 // Fall back to using the global object as the implicit receiver if
8462 // the property turns out to be a local variable allocated in a
8463 // context extension object - introduced via eval. Implicit global
8464 // receivers are indicated with the hole value.
8465 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008466}
8467
8468
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469static ObjectPair LoadContextSlotHelper(Arguments args,
8470 Isolate* isolate,
8471 bool throw_error) {
8472 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008473 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008475 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008477 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008479 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008480
8481 int index;
8482 PropertyAttributes attributes;
8483 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008484 BindingFlags binding_flags;
8485 Handle<Object> holder = context->Lookup(name,
8486 flags,
8487 &index,
8488 &attributes,
8489 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008491 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008493 ASSERT(holder->IsContext());
8494 // If the "property" we were looking for is a local variable, the
8495 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008496 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008497 // Use the hole as the receiver to signal that the receiver is implicit
8498 // and that the global receiver should be used (as distinguished from an
8499 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008500 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008501 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008502 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008503 switch (binding_flags) {
8504 case MUTABLE_CHECK_INITIALIZED:
8505 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8506 if (value->IsTheHole()) {
8507 Handle<Object> reference_error =
8508 isolate->factory()->NewReferenceError("not_defined",
8509 HandleVector(&name, 1));
8510 return MakePair(isolate->Throw(*reference_error), NULL);
8511 }
8512 // FALLTHROUGH
8513 case MUTABLE_IS_INITIALIZED:
8514 case IMMUTABLE_IS_INITIALIZED:
8515 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8516 ASSERT(!value->IsTheHole());
8517 return MakePair(value, *receiver);
8518 case IMMUTABLE_CHECK_INITIALIZED:
8519 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8520 case MISSING_BINDING:
8521 UNREACHABLE();
8522 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008524 }
8525
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008526 // Otherwise, if the slot was found the holder is a context extension
8527 // object, subject of a with, or a global object. We read the named
8528 // property from it.
8529 if (!holder.is_null()) {
8530 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8531 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008532 // GetProperty below can cause GC.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008533 Handle<Object> receiver_handle(
8534 object->IsGlobalObject()
8535 ? GlobalObject::cast(*object)->global_receiver()
8536 : ComputeReceiverForNonGlobal(isolate, *object),
8537 isolate);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008538
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008539 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008540 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008541 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008542 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543 }
8544
8545 if (throw_error) {
8546 // The property doesn't exist - throw exception.
8547 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 isolate->factory()->NewReferenceError("not_defined",
8549 HandleVector(&name, 1));
8550 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008552 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008553 return MakePair(isolate->heap()->undefined_value(),
8554 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555 }
8556}
8557
8558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008559RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008560 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008561}
8562
8563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008564RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566}
8567
8568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008569RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008571 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008574 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8575 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008576 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8577 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8578 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579
8580 int index;
8581 PropertyAttributes attributes;
8582 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008583 BindingFlags binding_flags;
8584 Handle<Object> holder = context->Lookup(name,
8585 flags,
8586 &index,
8587 &attributes,
8588 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589
8590 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008591 // The property was found in a context slot.
8592 Handle<Context> context = Handle<Context>::cast(holder);
8593 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8594 context->get(index)->IsTheHole()) {
8595 Handle<Object> error =
8596 isolate->factory()->NewReferenceError("not_defined",
8597 HandleVector(&name, 1));
8598 return isolate->Throw(*error);
8599 }
8600 // Ignore if read_only variable.
8601 if ((attributes & READ_ONLY) == 0) {
8602 // Context is a fixed array and set cannot fail.
8603 context->set(index, *value);
8604 } else if (strict_mode == kStrictMode) {
8605 // Setting read only property in strict mode.
8606 Handle<Object> error =
8607 isolate->factory()->NewTypeError("strict_cannot_assign",
8608 HandleVector(&name, 1));
8609 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008610 }
8611 return *value;
8612 }
8613
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008614 // Slow case: The property is not in a context slot. It is either in a
8615 // context extension object, a property of the subject of a with, or a
8616 // property of the global object.
8617 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008619 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008620 // The property exists on the holder.
8621 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008623 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008625
8626 if (strict_mode == kStrictMode) {
8627 // Throw in strict mode (assignment to undefined variable).
8628 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008629 isolate->factory()->NewReferenceError(
8630 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008631 return isolate->Throw(*error);
8632 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008633 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008634 attributes = NONE;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008635 object = Handle<JSObject>(isolate->context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636 }
8637
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008638 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008639 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008640 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008641 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008642 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008643 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008644 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008645 // Setting read only property in strict mode.
8646 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008647 isolate->factory()->NewTypeError(
8648 "strict_cannot_assign", HandleVector(&name, 1));
8649 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008650 }
8651 return *value;
8652}
8653
8654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008655RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008656 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657 ASSERT(args.length() == 1);
8658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660}
8661
8662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008663RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 ASSERT(args.length() == 1);
8666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008667 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668}
8669
8670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008671RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008672 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008674}
8675
8676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008677RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008678 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 ASSERT(args.length() == 1);
8680
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683 isolate->factory()->NewReferenceError("not_defined",
8684 HandleVector(&name, 1));
8685 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686}
8687
8688
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00008689RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) {
8690 HandleScope scope(isolate);
8691 ASSERT(args.length() == 0);
8692 return isolate->Throw(*isolate->factory()->NewTypeError(
8693 "not_date_object", HandleVector<Object>(NULL, 0)));
8694}
8695
8696
8697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008698RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008699 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700
8701 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702 if (isolate->stack_guard()->IsStackOverflow()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008703 NoHandleAllocation na(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008704 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706
ulan@chromium.org812308e2012-02-29 15:58:45 +00008707 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708}
8709
8710
yangguo@chromium.org56454712012-02-16 15:33:53 +00008711RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8712 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008713 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008714}
8715
8716
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008717static int StackSize(Isolate* isolate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008718 int n = 0;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008719 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008720 return n;
8721}
8722
8723
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008724static void PrintTransition(Isolate* isolate, Object* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725 // indentation
8726 { const int nmax = 80;
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008727 int n = StackSize(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008728 if (n <= nmax)
8729 PrintF("%4d:%*s", n, n, "");
8730 else
8731 PrintF("%4d:%*s", n, nmax, "...");
8732 }
8733
8734 if (result == NULL) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008735 JavaScriptFrame::PrintTop(isolate, stdout, true, false);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008736 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 } else {
8738 // function result
8739 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008740 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008741 PrintF("\n");
8742 }
8743}
8744
8745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008746RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008747 ASSERT(args.length() == 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008748 NoHandleAllocation ha(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008749 PrintTransition(isolate, NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008750 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008751}
8752
8753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008755 NoHandleAllocation ha(isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00008756 PrintTransition(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008757 return args[0]; // return TOS
8758}
8759
8760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008761RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008762 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 ASSERT(args.length() == 1);
8764
8765#ifdef DEBUG
8766 if (args[0]->IsString()) {
8767 // If we have a string, assume it's a code "marker"
8768 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008769 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008770 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008771 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8772 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773 } else {
8774 PrintF("DebugPrint: ");
8775 }
8776 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008777 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008778 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008779 HeapObject::cast(args[0])->map()->Print();
8780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008782 // ShortPrint is available in release mode. Print is not.
8783 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784#endif
8785 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008786 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787
8788 return args[0]; // return TOS
8789}
8790
8791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008792RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008793 ASSERT(args.length() == 0);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008794 NoHandleAllocation ha(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 isolate->PrintStack();
8796 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797}
8798
8799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008800RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008801 NoHandleAllocation ha(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +00008802 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803
8804 // According to ECMA-262, section 15.9.1, page 117, the precision of
8805 // the number in a Date object representing a particular instant in
8806 // time is milliseconds. Therefore, we floor the result of getting
8807 // the OS time.
8808 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810}
8811
8812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008813RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008814 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008815 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008817 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008818 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008820 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008821
8822 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008823 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008824 if (maybe_result_array->IsFailure()) return maybe_result_array;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008825 RUNTIME_ASSERT(output->HasFastObjectElements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008826
8827 AssertNoAllocation no_allocation;
8828
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008829 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008830 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8831 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008832 String::FlatContent str_content = str->GetFlatContent();
8833 if (str_content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008834 result = DateParser::Parse(str_content.ToOneByteVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008835 output_array,
8836 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008838 ASSERT(str_content.IsTwoByte());
8839 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008840 output_array,
8841 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008842 }
8843
8844 if (result) {
8845 return *output;
8846 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008847 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 }
8849}
8850
8851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008852RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008853 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854 ASSERT(args.length() == 1);
8855
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008856 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008857 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
8858 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860}
8861
8862
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008863RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00008864 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865 ASSERT(args.length() == 1);
8866
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008867 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008868 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
8869
8870 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871}
8872
8873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008874RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008875 ASSERT(args.length() == 1);
8876 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008877 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008878 return JSGlobalObject::cast(global)->global_receiver();
8879}
8880
8881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008882RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008884 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008885 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008886
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008887 Zone* zone = isolate->runtime_zone();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008888 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00008889 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008890 Handle<Object> result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008891 if (source->IsSeqOneByteString()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008892 result = JsonParser<true>::Parse(source, zone);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008893 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008894 result = JsonParser<false>::Parse(source, zone);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008895 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008896 if (result.is_null()) {
8897 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008898 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008899 return Failure::Exception();
8900 }
8901 return *result;
8902}
8903
8904
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008905bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8906 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008907 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
8908 // Check with callback if set.
8909 AllowCodeGenerationFromStringsCallback callback =
8910 isolate->allow_code_gen_callback();
8911 if (callback == NULL) {
8912 // No callback set and code generation disallowed.
8913 return false;
8914 } else {
8915 // Callback set. Let it decide if code generation is allowed.
8916 VMState state(isolate, EXTERNAL);
8917 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008918 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008919}
8920
8921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008922RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008923 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008924 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008925 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008926
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008927 // Extract native context.
8928 Handle<Context> context(isolate->context()->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008929
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008930 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008931 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008932 if (context->allow_code_gen_from_strings()->IsFalse() &&
8933 !CodeGenerationFromStringsAllowed(isolate, context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008934 Handle<Object> error_message =
8935 context->ErrorMessageForCodeGenerationFromStrings();
8936 return isolate->Throw(*isolate->factory()->NewEvalError(
8937 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008938 }
8939
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008940 // Compile source string in the native context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008941 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008942 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008943 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008945 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8946 context,
8947 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008948 return *fun;
8949}
8950
8951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952static ObjectPair CompileGlobalEval(Isolate* isolate,
8953 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008954 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008955 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008956 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008957 Handle<Context> context = Handle<Context>(isolate->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008958 Handle<Context> native_context = Handle<Context>(context->native_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008959
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008960 // Check if native context allows code generation from
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008961 // strings. Throw an exception if it doesn't.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008962 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
8963 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008964 Handle<Object> error_message =
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00008965 native_context->ErrorMessageForCodeGenerationFromStrings();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00008966 isolate->Throw(*isolate->factory()->NewEvalError(
8967 "code_gen_from_strings", HandleVector<Object>(&error_message, 1)));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008968 return MakePair(Failure::Exception(), NULL);
8969 }
8970
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008971 // Deal with a normal eval call with a string argument. Compile it
8972 // and return the compiled function bound in the local context.
8973 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8974 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008975 Handle<Context>(isolate->context()),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008976 context->IsNativeContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008977 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008978 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008979 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008980 Handle<JSFunction> compiled =
8981 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008982 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008983 return MakePair(*compiled, *receiver);
8984}
8985
8986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008987RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008988 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008990 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008991 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008992
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008993 // If "eval" didn't refer to the original GlobalEval, it's not a
8994 // direct call to eval.
8995 // (And even if it is, but the first argument isn't a string, just let
8996 // execution default to an indirect call to eval, which will also return
8997 // the first argument without doing anything).
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008998 if (*callee != isolate->native_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008999 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009000 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009001 }
9002
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009003 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009004 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 return CompileGlobalEval(isolate,
9006 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009007 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009008 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009009 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009010}
9011
9012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009013RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 // This utility adjusts the property attributes for newly created Function
9015 // object ("new Function(...)") by changing the map.
9016 // All it does is changing the prototype property to enumerable
9017 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009020 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009021
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009022 Handle<Map> map = func->shared()->is_classic_mode()
9023 ? isolate->function_instance_map()
9024 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009025
9026 ASSERT(func->map()->instance_type() == map->instance_type());
9027 ASSERT(func->map()->instance_size() == map->instance_size());
9028 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029 return *func;
9030}
9031
9032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009033RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009034 // Allocate a block of memory in NewSpace (filled with a filler).
9035 // Use as fallback for allocation in generated code when NewSpace
9036 // is full.
9037 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009038 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009039 int size = size_smi->value();
9040 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9041 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009042 Heap* heap = isolate->heap();
9043 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009044 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009045 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009046 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009047 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009048 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009049 }
9050 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009051 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009052}
9053
9054
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009055// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009056// array. Returns true if the element was pushed on the stack and
9057// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009058RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009059 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009060 CONVERT_ARG_CHECKED(JSArray, array, 0);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00009061 CONVERT_ARG_CHECKED(JSReceiver, element, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009062 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009063 int length = Smi::cast(array->length())->value();
9064 FixedArray* elements = FixedArray::cast(array->elements());
9065 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009067 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009068 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009069 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009070 { MaybeObject* maybe_obj =
9071 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009072 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9073 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009075}
9076
9077
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009078/**
9079 * A simple visitor visits every element of Array's.
9080 * The backend storage can be a fixed array for fast elements case,
9081 * or a dictionary for sparse array. Since Dictionary is a subtype
9082 * of FixedArray, the class can be used by both fast and slow cases.
9083 * The second parameter of the constructor, fast_elements, specifies
9084 * whether the storage is a FixedArray or Dictionary.
9085 *
9086 * An index limit is used to deal with the situation that a result array
9087 * length overflows 32-bit non-negative integer.
9088 */
9089class ArrayConcatVisitor {
9090 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 ArrayConcatVisitor(Isolate* isolate,
9092 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009093 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 isolate_(isolate),
9095 storage_(Handle<FixedArray>::cast(
9096 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009097 index_offset_(0u),
9098 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009099
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009100 ~ArrayConcatVisitor() {
9101 clear_storage();
9102 }
9103
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009104 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009105 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009106 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009107
9108 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009109 if (index < static_cast<uint32_t>(storage_->length())) {
9110 storage_->set(index, *elm);
9111 return;
9112 }
9113 // Our initial estimate of length was foiled, possibly by
9114 // getters on the arrays increasing the length of later arrays
9115 // during iteration.
9116 // This shouldn't happen in anything but pathological cases.
9117 SetDictionaryMode(index);
9118 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009119 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009120 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009121 Handle<SeededNumberDictionary> dict(
9122 SeededNumberDictionary::cast(*storage_));
9123 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009125 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009126 // Dictionary needed to grow.
9127 clear_storage();
9128 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009129 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009130 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009131
9132 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009133 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9134 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009135 } else {
9136 index_offset_ += delta;
9137 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009138 }
9139
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009140 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009142 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009143 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009144 Handle<Map> map;
9145 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009146 map = isolate_->factory()->GetElementsTransitionMap(array,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009147 FAST_HOLEY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009148 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009149 map = isolate_->factory()->GetElementsTransitionMap(array,
9150 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009151 }
9152 array->set_map(*map);
9153 array->set_length(*length);
9154 array->set_elements(*storage_);
9155 return array;
9156 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009157
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009158 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009159 // Convert storage to dictionary mode.
9160 void SetDictionaryMode(uint32_t index) {
9161 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009162 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009163 Handle<SeededNumberDictionary> slow_storage(
9164 isolate_->factory()->NewSeededNumberDictionary(
9165 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009166 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9167 for (uint32_t i = 0; i < current_length; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009168 HandleScope loop_scope(isolate_);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009169 Handle<Object> element(current_storage->get(i), isolate_);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009170 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009171 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009173 if (!new_storage.is_identical_to(slow_storage)) {
9174 slow_storage = loop_scope.CloseAndEscape(new_storage);
9175 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009176 }
9177 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009178 clear_storage();
9179 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009180 fast_elements_ = false;
9181 }
9182
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009183 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 isolate_->global_handles()->Destroy(
9185 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009186 }
9187
9188 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 storage_ = Handle<FixedArray>::cast(
9190 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009191 }
9192
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009193 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009194 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009195 // Index after last seen index. Always less than or equal to
9196 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009197 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009198 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009199};
9200
9201
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009202static uint32_t EstimateElementCount(Handle<JSArray> array) {
9203 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9204 int element_count = 0;
9205 switch (array->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009206 case FAST_SMI_ELEMENTS:
9207 case FAST_HOLEY_SMI_ELEMENTS:
9208 case FAST_ELEMENTS:
9209 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009210 // Fast elements can't have lengths that are not representable by
9211 // a 32-bit signed integer.
9212 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9213 int fast_length = static_cast<int>(length);
9214 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9215 for (int i = 0; i < fast_length; i++) {
9216 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009217 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009218 break;
9219 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009220 case FAST_DOUBLE_ELEMENTS:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009221 case FAST_HOLEY_DOUBLE_ELEMENTS: {
9222 // Fast elements can't have lengths that are not representable by
9223 // a 32-bit signed integer.
9224 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
9225 int fast_length = static_cast<int>(length);
9226 if (array->elements()->IsFixedArray()) {
9227 ASSERT(FixedArray::cast(array->elements())->length() == 0);
9228 break;
9229 }
9230 Handle<FixedDoubleArray> elements(
9231 FixedDoubleArray::cast(array->elements()));
9232 for (int i = 0; i < fast_length; i++) {
9233 if (!elements->is_the_hole(i)) element_count++;
9234 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009235 break;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009236 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009237 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009238 Handle<SeededNumberDictionary> dictionary(
9239 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009240 int capacity = dictionary->Capacity();
9241 for (int i = 0; i < capacity; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009242 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009243 if (dictionary->IsKey(*key)) {
9244 element_count++;
9245 }
9246 }
9247 break;
9248 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009249 case NON_STRICT_ARGUMENTS_ELEMENTS:
9250 case EXTERNAL_BYTE_ELEMENTS:
9251 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9252 case EXTERNAL_SHORT_ELEMENTS:
9253 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9254 case EXTERNAL_INT_ELEMENTS:
9255 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9256 case EXTERNAL_FLOAT_ELEMENTS:
9257 case EXTERNAL_DOUBLE_ELEMENTS:
9258 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009259 // External arrays are always dense.
9260 return length;
9261 }
9262 // As an estimate, we assume that the prototype doesn't contain any
9263 // inherited elements.
9264 return element_count;
9265}
9266
9267
9268
9269template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270static void IterateExternalArrayElements(Isolate* isolate,
9271 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009272 bool elements_are_ints,
9273 bool elements_are_guaranteed_smis,
9274 ArrayConcatVisitor* visitor) {
9275 Handle<ExternalArrayClass> array(
9276 ExternalArrayClass::cast(receiver->elements()));
9277 uint32_t len = static_cast<uint32_t>(array->length());
9278
9279 ASSERT(visitor != NULL);
9280 if (elements_are_ints) {
9281 if (elements_are_guaranteed_smis) {
9282 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009283 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009284 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
9285 isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009286 visitor->visit(j, e);
9287 }
9288 } else {
9289 for (uint32_t j = 0; j < len; j++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009290 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009291 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009292 if (Smi::IsValid(static_cast<intptr_t>(val))) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009293 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009294 visitor->visit(j, e);
9295 } else {
9296 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009298 visitor->visit(j, e);
9299 }
9300 }
9301 }
9302 } else {
9303 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009304 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009305 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009306 visitor->visit(j, e);
9307 }
9308 }
9309}
9310
9311
9312// Used for sorting indices in a List<uint32_t>.
9313static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9314 uint32_t a = *ap;
9315 uint32_t b = *bp;
9316 return (a == b) ? 0 : (a < b) ? -1 : 1;
9317}
9318
9319
9320static void CollectElementIndices(Handle<JSObject> object,
9321 uint32_t range,
9322 List<uint32_t>* indices) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009323 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009324 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009325 switch (kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009326 case FAST_SMI_ELEMENTS:
9327 case FAST_ELEMENTS:
9328 case FAST_HOLEY_SMI_ELEMENTS:
9329 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009330 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9331 uint32_t length = static_cast<uint32_t>(elements->length());
9332 if (range < length) length = range;
9333 for (uint32_t i = 0; i < length; i++) {
9334 if (!elements->get(i)->IsTheHole()) {
9335 indices->Add(i);
9336 }
9337 }
9338 break;
9339 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009340 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009341 case FAST_DOUBLE_ELEMENTS: {
9342 // TODO(1810): Decide if it's worthwhile to implement this.
9343 UNREACHABLE();
9344 break;
9345 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009346 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009347 Handle<SeededNumberDictionary> dict(
9348 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009349 uint32_t capacity = dict->Capacity();
9350 for (uint32_t j = 0; j < capacity; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009351 HandleScope loop_scope(isolate);
9352 Handle<Object> k(dict->KeyAt(j), isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009353 if (dict->IsKey(*k)) {
9354 ASSERT(k->IsNumber());
9355 uint32_t index = static_cast<uint32_t>(k->Number());
9356 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009357 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009358 }
9359 }
9360 }
9361 break;
9362 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009363 default: {
9364 int dense_elements_length;
9365 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009366 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009367 dense_elements_length =
9368 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009369 break;
9370 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009371 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009372 dense_elements_length =
9373 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009374 break;
9375 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009376 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009377 dense_elements_length =
9378 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009379 break;
9380 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009381 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009382 dense_elements_length =
9383 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009384 break;
9385 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009386 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009387 dense_elements_length =
9388 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 break;
9390 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009391 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009392 dense_elements_length =
9393 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009394 break;
9395 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009396 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009397 dense_elements_length =
9398 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009399 break;
9400 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009401 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009402 dense_elements_length =
9403 ExternalFloatArray::cast(object->elements())->length();
9404 break;
9405 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009406 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009407 dense_elements_length =
9408 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009409 break;
9410 }
9411 default:
9412 UNREACHABLE();
9413 dense_elements_length = 0;
9414 break;
9415 }
9416 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9417 if (range <= length) {
9418 length = range;
9419 // We will add all indices, so we might as well clear it first
9420 // and avoid duplicates.
9421 indices->Clear();
9422 }
9423 for (uint32_t i = 0; i < length; i++) {
9424 indices->Add(i);
9425 }
9426 if (length == range) return; // All indices accounted for already.
9427 break;
9428 }
9429 }
9430
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009431 Handle<Object> prototype(object->GetPrototype(), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009432 if (prototype->IsJSObject()) {
9433 // The prototype will usually have no inherited element indices,
9434 // but we have to check.
9435 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9436 }
9437}
9438
9439
9440/**
9441 * A helper function that visits elements of a JSArray in numerical
9442 * order.
9443 *
9444 * The visitor argument called for each existing element in the array
9445 * with the element index and the element's value.
9446 * Afterwards it increments the base-index of the visitor by the array
9447 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009448 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009449 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450static bool IterateElements(Isolate* isolate,
9451 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009452 ArrayConcatVisitor* visitor) {
9453 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9454 switch (receiver->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009455 case FAST_SMI_ELEMENTS:
9456 case FAST_ELEMENTS:
9457 case FAST_HOLEY_SMI_ELEMENTS:
9458 case FAST_HOLEY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009459 // Run through the elements FixedArray and use HasElement and GetElement
9460 // to check the prototype for missing elements.
9461 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9462 int fast_length = static_cast<int>(length);
9463 ASSERT(fast_length <= elements->length());
9464 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 HandleScope loop_scope(isolate);
9466 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009467 if (!element_value->IsTheHole()) {
9468 visitor->visit(j, element_value);
9469 } else if (receiver->HasElement(j)) {
9470 // Call GetElement on receiver, not its prototype, or getters won't
9471 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009472 element_value = Object::GetElement(receiver, j);
9473 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 visitor->visit(j, element_value);
9475 }
9476 }
9477 break;
9478 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009479 case FAST_HOLEY_DOUBLE_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009480 case FAST_DOUBLE_ELEMENTS: {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009481 // Run through the elements FixedArray and use HasElement and GetElement
9482 // to check the prototype for missing elements.
9483 Handle<FixedDoubleArray> elements(
9484 FixedDoubleArray::cast(receiver->elements()));
9485 int fast_length = static_cast<int>(length);
9486 ASSERT(fast_length <= elements->length());
9487 for (int j = 0; j < fast_length; j++) {
9488 HandleScope loop_scope(isolate);
9489 if (!elements->is_the_hole(j)) {
9490 double double_value = elements->get_scalar(j);
9491 Handle<Object> element_value =
9492 isolate->factory()->NewNumber(double_value);
9493 visitor->visit(j, element_value);
9494 } else if (receiver->HasElement(j)) {
9495 // Call GetElement on receiver, not its prototype, or getters won't
9496 // have the correct receiver.
9497 Handle<Object> element_value = Object::GetElement(receiver, j);
9498 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
9499 visitor->visit(j, element_value);
9500 }
9501 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009502 break;
9503 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009504 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009505 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009506 List<uint32_t> indices(dict->Capacity() / 2);
9507 // Collect all indices in the object and the prototypes less
9508 // than length. This might introduce duplicates in the indices list.
9509 CollectElementIndices(receiver, length, &indices);
9510 indices.Sort(&compareUInt32);
9511 int j = 0;
9512 int n = indices.length();
9513 while (j < n) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009514 HandleScope loop_scope(isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009515 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009516 Handle<Object> element = Object::GetElement(receiver, index);
9517 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009518 visitor->visit(index, element);
9519 // Skip to next different index (i.e., omit duplicates).
9520 do {
9521 j++;
9522 } while (j < n && indices[j] == index);
9523 }
9524 break;
9525 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009526 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009527 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9528 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009529 for (uint32_t j = 0; j < length; j++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009530 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009531 visitor->visit(j, e);
9532 }
9533 break;
9534 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009535 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009536 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009537 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009538 break;
9539 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009540 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009541 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009543 break;
9544 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009545 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009546 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009548 break;
9549 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009550 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009551 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009553 break;
9554 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009555 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009556 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009558 break;
9559 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009560 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009561 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009562 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009563 break;
9564 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009565 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009566 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009567 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009568 break;
9569 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009570 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009571 IterateExternalArrayElements<ExternalDoubleArray, double>(
9572 isolate, receiver, false, false, visitor);
9573 break;
9574 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009575 default:
9576 UNREACHABLE();
9577 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009578 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009580 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009581}
9582
9583
9584/**
9585 * Array::concat implementation.
9586 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009587 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009588 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009589 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009590RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009591 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009592 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009593
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009594 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009595 int argument_count = static_cast<int>(arguments->length()->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009596 RUNTIME_ASSERT(arguments->HasFastObjectElements());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009597 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009598
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009599 // Pass 1: estimate the length and number of elements of the result.
9600 // The actual length can be larger if any of the arguments have getters
9601 // that mutate other arguments (but will otherwise be precise).
9602 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009604 ElementsKind kind = FAST_SMI_ELEMENTS;
9605
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009606 uint32_t estimate_result_length = 0;
9607 uint32_t estimate_nof_elements = 0;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009608 for (int i = 0; i < argument_count; i++) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00009609 HandleScope loop_scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009610 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009611 uint32_t length_estimate;
9612 uint32_t element_estimate;
9613 if (obj->IsJSArray()) {
9614 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9615 length_estimate = static_cast<uint32_t>(array->length()->Number());
9616 if (length_estimate != 0) {
9617 ElementsKind array_kind =
9618 GetPackedElementsKind(array->map()->elements_kind());
9619 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
9620 kind = array_kind;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009621 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009623 element_estimate = EstimateElementCount(array);
9624 } else {
9625 if (obj->IsHeapObject()) {
9626 if (obj->IsNumber()) {
9627 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
9628 kind = FAST_DOUBLE_ELEMENTS;
9629 }
9630 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
9631 kind = FAST_ELEMENTS;
9632 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009634 length_estimate = 1;
9635 element_estimate = 1;
9636 }
9637 // Avoid overflows by capping at kMaxElementCount.
9638 if (JSObject::kMaxElementCount - estimate_result_length <
9639 length_estimate) {
9640 estimate_result_length = JSObject::kMaxElementCount;
9641 } else {
9642 estimate_result_length += length_estimate;
9643 }
9644 if (JSObject::kMaxElementCount - estimate_nof_elements <
9645 element_estimate) {
9646 estimate_nof_elements = JSObject::kMaxElementCount;
9647 } else {
9648 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009649 }
9650 }
9651
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009652 // If estimated number of elements is more than half of length, a
9653 // fixed array (fast case) is more time and space-efficient than a
9654 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009655 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009656
9657 Handle<FixedArray> storage;
9658 if (fast_case) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009659 if (kind == FAST_DOUBLE_ELEMENTS) {
9660 Handle<FixedDoubleArray> double_storage =
9661 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
9662 int j = 0;
9663 bool failure = false;
9664 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009665 Handle<Object> obj(elements->get(i), isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009666 if (obj->IsSmi()) {
9667 double_storage->set(j, Smi::cast(*obj)->value());
9668 j++;
9669 } else if (obj->IsNumber()) {
9670 double_storage->set(j, obj->Number());
9671 j++;
9672 } else {
9673 JSArray* array = JSArray::cast(*obj);
9674 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9675 switch (array->map()->elements_kind()) {
9676 case FAST_HOLEY_DOUBLE_ELEMENTS:
9677 case FAST_DOUBLE_ELEMENTS: {
9678 // Empty fixed array indicates that there are no elements.
9679 if (array->elements()->IsFixedArray()) break;
9680 FixedDoubleArray* elements =
9681 FixedDoubleArray::cast(array->elements());
9682 for (uint32_t i = 0; i < length; i++) {
9683 if (elements->is_the_hole(i)) {
9684 failure = true;
9685 break;
9686 }
9687 double double_value = elements->get_scalar(i);
9688 double_storage->set(j, double_value);
9689 j++;
9690 }
9691 break;
9692 }
9693 case FAST_HOLEY_SMI_ELEMENTS:
9694 case FAST_SMI_ELEMENTS: {
9695 FixedArray* elements(
9696 FixedArray::cast(array->elements()));
9697 for (uint32_t i = 0; i < length; i++) {
9698 Object* element = elements->get(i);
9699 if (element->IsTheHole()) {
9700 failure = true;
9701 break;
9702 }
9703 int32_t int_value = Smi::cast(element)->value();
9704 double_storage->set(j, int_value);
9705 j++;
9706 }
9707 break;
9708 }
9709 case FAST_HOLEY_ELEMENTS:
9710 ASSERT_EQ(0, length);
9711 break;
9712 default:
9713 UNREACHABLE();
9714 }
9715 }
9716 if (failure) break;
9717 }
9718 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
9719 Smi* length = Smi::FromInt(j);
9720 Handle<Map> map;
9721 map = isolate->factory()->GetElementsTransitionMap(array, kind);
9722 array->set_map(*map);
9723 array->set_length(length);
9724 array->set_elements(*double_storage);
9725 return *array;
9726 }
9727 // The backing storage array must have non-existing elements to preserve
9728 // holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 storage = isolate->factory()->NewFixedArrayWithHoles(
9730 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009731 } else {
9732 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9733 uint32_t at_least_space_for = estimate_nof_elements +
9734 (estimate_nof_elements >> 2);
9735 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009736 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009737 }
9738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009740
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 for (int i = 0; i < argument_count; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009742 Handle<Object> obj(elements->get(i), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 if (obj->IsJSArray()) {
9744 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009746 return Failure::Exception();
9747 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 } else {
9749 visitor.visit(0, obj);
9750 visitor.increase_index_offset(1);
9751 }
9752 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009753
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009755}
9756
9757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009758// This will not allocate (flatten the string), but it may run
9759// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009760RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00009761 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762 ASSERT(args.length() == 1);
9763
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009764 CONVERT_ARG_CHECKED(String, string, 0);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009765 ConsStringIteratorOp op;
9766 StringCharacterStream stream(string, &op);
9767 while (stream.HasMore()) {
9768 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769 PrintF("%c", character);
9770 }
9771 return string;
9772}
9773
ager@chromium.org5ec48922009-05-05 07:25:34 +00009774// Moves all own elements of an object, that are below a limit, to positions
9775// starting at zero. All undefined values are placed after non-undefined values,
9776// and are followed by non-existing element. Does not change the length
9777// property.
9778// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009779RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009780 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009781 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009782 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9783 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009784}
9785
9786
9787// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009788RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009790 CONVERT_ARG_CHECKED(JSArray, from, 0);
9791 CONVERT_ARG_CHECKED(JSArray, to, 1);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009792 from->ValidateElements();
9793 to->ValidateElements();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009794 FixedArrayBase* new_elements = from->elements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009795 ElementsKind from_kind = from->GetElementsKind();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009796 MaybeObject* maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009797 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798 Object* new_map;
9799 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009800 to->set_map_and_elements(Map::cast(new_map), new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009801 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 Object* obj;
9803 { MaybeObject* maybe_obj = from->ResetElements();
9804 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9805 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009806 from->set_length(Smi::FromInt(0));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009807 to->ValidateElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 return to;
9809}
9810
9811
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009812// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009813RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009815 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009816 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009818 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9819 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009820 } else if (object->IsJSArray()) {
9821 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009823 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824 }
9825}
9826
9827
9828// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009829// might have elements. Can either return keys (positive integers) or
9830// intervals (pair of a negative integer (-start-1) followed by a
9831// positive (length)) or undefined values.
9832// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009833RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009835 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009836 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009838 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 // Create an array and get all the keys into it, then remove all the
9840 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009841 bool threw = false;
9842 Handle<FixedArray> keys =
9843 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9844 if (threw) return Failure::Exception();
9845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009846 int keys_length = keys->length();
9847 for (int i = 0; i < keys_length; i++) {
9848 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009849 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009850 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009851 // Zap invalid keys.
9852 keys->set_undefined(i);
9853 }
9854 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009857 ASSERT(array->HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009858 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009861 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009862 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009863 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009864 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009865 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009867 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009869 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870 }
9871}
9872
9873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009874RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 ASSERT(args.length() == 3);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009876 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009877 CONVERT_ARG_CHECKED(String, name, 1);
9878 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00009879 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009880 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
9881 return JSObject::cast(receiver)->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882}
9883
9884
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009885#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009886RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009887 ASSERT(args.length() == 0);
9888 return Execution::DebugBreakHelper();
9889}
9890
9891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892// Helper functions for wrapping and unwrapping stack frame ids.
9893static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009894 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 return Smi::FromInt(id >> 2);
9896}
9897
9898
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009899static StackFrame::Id UnwrapFrameId(int wrapped) {
9900 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901}
9902
9903
9904// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009905// args[0]: debug event listener function to set or null or undefined for
9906// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009908RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009910 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9911 args[0]->IsUndefined() ||
9912 args[0]->IsNull());
9913 Handle<Object> callback = args.at<Object>(0);
9914 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009915 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009917 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918}
9919
9920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009921RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009922 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009923 isolate->stack_guard()->DebugBreak();
9924 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925}
9926
9927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928static MaybeObject* DebugLookupResultValue(Heap* heap,
9929 Object* receiver,
9930 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009931 LookupResult* result,
9932 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009933 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009935 case NORMAL:
9936 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009937 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939 }
9940 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009941 case FIELD:
9942 value =
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00009943 JSObject::cast(result->holder())->FastPropertyAt(
9944 result->GetFieldIndex().field_index());
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009945 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009947 }
9948 return value;
9949 case CONSTANT_FUNCTION:
9950 return result->GetConstantFunction();
9951 case CALLBACKS: {
9952 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009953 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009954 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
9955 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009956 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009957 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009958 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 maybe_value = heap->isolate()->pending_exception();
9960 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009961 if (caught_exception != NULL) {
9962 *caught_exception = true;
9963 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009964 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009965 }
9966 return value;
9967 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009969 }
9970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 case INTERCEPTOR:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009972 case TRANSITION:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009973 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +00009974 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009975 case NONEXISTENT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00009977 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00009979 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981}
9982
9983
ager@chromium.org32912102009-01-16 10:38:43 +00009984// Get debugger related details for an object property.
9985// args[0]: object holding property
9986// args[1]: name of the property
9987//
9988// The array returned contains the following information:
9989// 0: Property value
9990// 1: Property details
9991// 2: Property value is exception
9992// 3: Getter function if defined
9993// 4: Setter function if defined
9994// Items 2-4 are only filled if the property has either a getter or a setter
9995// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009996RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998
9999 ASSERT(args.length() == 2);
10000
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010001 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10002 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010004 // Make sure to set the current context to the context before the debugger was
10005 // entered (if the debugger is entered). The reason for switching context here
10006 // is that for some property lookups (accessors and interceptors) callbacks
10007 // into the embedding application can occour, and the embedding application
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010008 // could have the assumption that its own native context is the current
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010009 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 SaveContext save(isolate);
10011 if (isolate->debug()->InDebugger()) {
10012 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010013 }
10014
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010015 // Skip the global proxy as it has no properties and always delegates to the
10016 // real global object.
10017 if (obj->IsJSGlobalProxy()) {
10018 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10019 }
10020
10021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 // Check if the name is trivially convertible to an index and get the element
10023 // if so.
10024 uint32_t index;
10025 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010026 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010027 Object* element_or_char;
10028 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010030 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10031 return maybe_element_or_char;
10032 }
10033 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010034 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037 }
10038
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010039 // Find the number of objects making up this.
10040 int length = LocalPrototypeChainLength(*obj);
10041
10042 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010043 Handle<JSObject> jsproto = obj;
10044 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010045 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010046 jsproto->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010047 if (result.IsFound()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010048 // LookupResult is not GC safe as it holds raw object pointers.
10049 // GC can happen later in this code so put the required fields into
10050 // local variables using handles when required for later use.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010051 Handle<Object> result_callback_obj;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010052 if (result.IsPropertyCallbacks()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10054 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010055 }
10056 Smi* property_details = result.GetPropertyDetails().AsSmi();
10057 // DebugLookupResultValue can cause GC so details from LookupResult needs
10058 // to be copied to handles before this.
10059 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010060 Object* raw_value;
10061 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062 DebugLookupResultValue(isolate->heap(), *obj, *name,
10063 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010064 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010067
10068 // If the callback object is a fixed array then it contains JavaScript
10069 // getter and/or setter.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010070 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010071 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010072 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010074 details->set(0, *value);
10075 details->set(1, property_details);
10076 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010077 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010078 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010079 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10080 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010081 }
10082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010084 }
10085 if (i < length - 1) {
10086 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10087 }
10088 }
10089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091}
10092
10093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010094RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096
10097 ASSERT(args.length() == 2);
10098
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010099 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10100 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010102 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 obj->Lookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010104 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010105 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010107 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108}
10109
10110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111// Return the property type calculated from the property details.
10112// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010113RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010115 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10116 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117}
10118
10119
10120// Return the property attribute calculated from the property details.
10121// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010122RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010124 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10125 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126}
10127
10128
10129// Return the property insertion index calculated from the property details.
10130// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010131RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010132 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010133 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010134 // TODO(verwaest): Depends on the type of details.
10135 return Smi::FromInt(details.dictionary_index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136}
10137
10138
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010139// Return property value from named interceptor.
10140// args[0]: object
10141// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010142RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010145 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010146 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010147 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148
10149 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010150 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151}
10152
10153
10154// Return element value from indexed interceptor.
10155// args[0]: object
10156// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010157RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010159 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010160 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10162 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10163
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010164 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165}
10166
10167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010168RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010169 ASSERT(args.length() >= 1);
10170 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010171 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010172 if (isolate->debug()->break_id() == 0 ||
10173 break_id != isolate->debug()->break_id()) {
10174 return isolate->Throw(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010175 isolate->heap()->illegal_execution_state_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 }
10177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010178 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179}
10180
10181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010182RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010184 ASSERT(args.length() == 1);
10185
10186 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010187 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010188 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10189 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010190 if (!maybe_result->ToObject(&result)) return maybe_result;
10191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192
10193 // Count all frames which are relevant to debugging stack trace.
10194 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010195 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010196 if (id == StackFrame::NO_ID) {
10197 // If there is no JavaScript stack frame count is 0.
10198 return Smi::FromInt(0);
10199 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010200
10201 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10202 n += it.frame()->GetInlineCount();
10203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204 return Smi::FromInt(n);
10205}
10206
10207
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010208class FrameInspector {
10209 public:
10210 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010211 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010212 Isolate* isolate)
10213 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10214 // Calculate the deoptimized frame.
10215 if (frame->is_optimized()) {
10216 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010217 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010218 }
10219 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010220 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010221 is_optimized_ = frame_->is_optimized();
10222 }
10223
10224 ~FrameInspector() {
10225 // Get rid of the calculated deoptimized frame if any.
10226 if (deoptimized_frame_ != NULL) {
10227 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10228 isolate_);
10229 }
10230 }
10231
10232 int GetParametersCount() {
10233 return is_optimized_
10234 ? deoptimized_frame_->parameters_count()
10235 : frame_->ComputeParametersCount();
10236 }
10237 int expression_count() { return deoptimized_frame_->expression_count(); }
10238 Object* GetFunction() {
10239 return is_optimized_
10240 ? deoptimized_frame_->GetFunction()
10241 : frame_->function();
10242 }
10243 Object* GetParameter(int index) {
10244 return is_optimized_
10245 ? deoptimized_frame_->GetParameter(index)
10246 : frame_->GetParameter(index);
10247 }
10248 Object* GetExpression(int index) {
10249 return is_optimized_
10250 ? deoptimized_frame_->GetExpression(index)
10251 : frame_->GetExpression(index);
10252 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010253 int GetSourcePosition() {
10254 return is_optimized_
10255 ? deoptimized_frame_->GetSourcePosition()
10256 : frame_->LookupCode()->SourcePosition(frame_->pc());
10257 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010258 bool IsConstructor() {
10259 return is_optimized_ && !is_bottommost_
10260 ? deoptimized_frame_->HasConstructStub()
10261 : frame_->IsConstructor();
10262 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010263
10264 // To inspect all the provided arguments the frame might need to be
10265 // replaced with the arguments frame.
10266 void SetArgumentsFrame(JavaScriptFrame* frame) {
10267 ASSERT(has_adapted_arguments_);
10268 frame_ = frame;
10269 is_optimized_ = frame_->is_optimized();
10270 ASSERT(!is_optimized_);
10271 }
10272
10273 private:
10274 JavaScriptFrame* frame_;
10275 DeoptimizedFrameInfo* deoptimized_frame_;
10276 Isolate* isolate_;
10277 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010278 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010279 bool has_adapted_arguments_;
10280
10281 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10282};
10283
10284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285static const int kFrameDetailsFrameIdIndex = 0;
10286static const int kFrameDetailsReceiverIndex = 1;
10287static const int kFrameDetailsFunctionIndex = 2;
10288static const int kFrameDetailsArgumentCountIndex = 3;
10289static const int kFrameDetailsLocalCountIndex = 4;
10290static const int kFrameDetailsSourcePositionIndex = 5;
10291static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010292static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010293static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010294static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010296
10297static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10298 JavaScriptFrame* frame) {
10299 SaveContext* save = isolate->save_context();
10300 while (save != NULL && !save->IsBelowFrame(frame)) {
10301 save = save->prev();
10302 }
10303 ASSERT(save != NULL);
10304 return save;
10305}
10306
10307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308// Return an array with frame details
10309// args[0]: number: break id
10310// args[1]: number: frame index
10311//
10312// The array returned contains the following information:
10313// 0: Frame id
10314// 1: Receiver
10315// 2: Function
10316// 3: Argument count
10317// 4: Local count
10318// 5: Source position
10319// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010320// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010321// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322// Arguments name, value
10323// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010324// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010325RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 ASSERT(args.length() == 2);
10328
10329 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010330 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010331 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10332 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010333 if (!maybe_check->ToObject(&check)) return maybe_check;
10334 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337
10338 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010340 if (id == StackFrame::NO_ID) {
10341 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010343 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010345 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010346 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010348 if (index < count + it.frame()->GetInlineCount()) break;
10349 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010351 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010353 bool is_optimized = it.frame()->is_optimized();
10354
10355 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10356 if (is_optimized) {
10357 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010358 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010359 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010360 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 // Traverse the saved contexts chain to find the active context for the
10363 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010364 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365
10366 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010369 // Find source position in unoptimized code.
10370 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371
ulan@chromium.org967e2702012-02-28 09:49:15 +000010372 // Check for constructor frame.
10373 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010374
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010375 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010376 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010377 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010378 Handle<ScopeInfo> scope_info(shared->scope_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010379 ASSERT(*scope_info != ScopeInfo::Empty(isolate));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 // Get the locals names and values into a temporary array.
10382 //
10383 // TODO(1240907): Hide compiler-introduced stack variables
10384 // (e.g. .result)? For users of the debugger, they will probably be
10385 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010387 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010389 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010390 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010391 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010392 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010393 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010394 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010395 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010396 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010397 // Get the context containing declarations.
10398 Handle<Context> context(
10399 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010400 for (; i < scope_info->LocalCount(); ++i) {
10401 Handle<String> name(scope_info->LocalName(i));
10402 VariableMode mode;
10403 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010404 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010405 locals->set(i * 2 + 1, context->get(
10406 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 }
10408 }
10409
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010410 // Check whether this frame is positioned at return. If not top
10411 // frame or if the frame is optimized it cannot be at a return.
10412 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010413 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010415 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010416
10417 // If positioned just before return find the value to be returned and add it
10418 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010420 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010421 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010422 Address internal_frame_sp = NULL;
10423 while (!it2.done()) {
10424 if (it2.frame()->is_internal()) {
10425 internal_frame_sp = it2.frame()->sp();
10426 } else {
10427 if (it2.frame()->is_java_script()) {
10428 if (it2.frame()->id() == it.frame()->id()) {
10429 // The internal frame just before the JavaScript frame contains the
10430 // value to return on top. A debug break at return will create an
10431 // internal frame to store the return value (eax/rax/r0) before
10432 // entering the debug break exit frame.
10433 if (internal_frame_sp != NULL) {
10434 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010435 Handle<Object>(Memory::Object_at(internal_frame_sp),
10436 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010437 break;
10438 }
10439 }
10440 }
10441
10442 // Indicate that the previous frame was not an internal frame.
10443 internal_frame_sp = NULL;
10444 }
10445 it2.Advance();
10446 }
10447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448
10449 // Now advance to the arguments adapter frame (if any). It contains all
10450 // the provided parameters whereas the function frame always have the number
10451 // of arguments matching the functions parameters. The rest of the
10452 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010453 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010454 it.AdvanceToArgumentsFrame();
10455 frame_inspector.SetArgumentsFrame(it.frame());
10456 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457
10458 // Find the number of arguments to fill. At least fill the number of
10459 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010460 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010461 if (argument_count < frame_inspector.GetParametersCount()) {
10462 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010463 }
10464
10465 // Calculate the size of the result.
10466 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010467 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010468 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010470
10471 // Add the frame id.
10472 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10473
10474 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010475 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476
10477 // Add the arguments count.
10478 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10479
10480 // Add the locals count
10481 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010482 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483
10484 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010485 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10487 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010488 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010489 }
10490
10491 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010494 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010495 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010496
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010497 // Add flags to indicate information on whether this frame is
10498 // bit 0: invoked in the debugger context.
10499 // bit 1: optimized frame.
10500 // bit 2: inlined in optimized frame
10501 int flags = 0;
10502 if (*save->context() == *isolate->debug()->debug_context()) {
10503 flags |= 1 << 0;
10504 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010505 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010506 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010507 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010508 }
10509 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510
10511 // Fill the dynamic part.
10512 int details_index = kFrameDetailsFirstDynamicIndex;
10513
10514 // Add arguments name and value.
10515 for (int i = 0; i < argument_count; i++) {
10516 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010517 if (i < scope_info->ParameterCount()) {
10518 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010520 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521 }
10522
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010523 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010524 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010525 // Get the value from the stack.
10526 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010528 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529 }
10530 }
10531
10532 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010533 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 details->set(details_index++, locals->get(i));
10535 }
10536
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010537 // Add the value being returned.
10538 if (at_return) {
10539 details->set(details_index++, *return_value);
10540 }
10541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 // Add the receiver (same as in function frame).
10543 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10544 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010545 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010546 if (!receiver->IsJSObject() &&
10547 shared->is_classic_mode() &&
10548 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010549 // If the receiver is not a JSObject and the function is not a
10550 // builtin or strict-mode we have hit an optimization where a
10551 // value object is not converted into a wrapped JS objects. To
10552 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 // by creating correct wrapper object based on the calling frame's
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010554 // native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010555 it.Advance();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010556 Handle<Context> calling_frames_native_context(
10557 Context::cast(Context::cast(it.frame()->context())->native_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 receiver =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010559 isolate->factory()->ToObject(receiver, calling_frames_native_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560 }
10561 details->set(kFrameDetailsReceiverIndex, *receiver);
10562
10563 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010565}
10566
10567
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010568// Create a plain JSObject which materializes the local scope for the specified
10569// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010570static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010571 Isolate* isolate,
10572 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010573 FrameInspector* frame_inspector) {
10574 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010575 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010576 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010577
10578 // Allocate and initialize a JSObject with all the arguments, stack locals
10579 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 Handle<JSObject> local_scope =
10581 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010582
10583 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010584 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010585 Handle<Object> value(i < frame_inspector->GetParametersCount()
10586 ? frame_inspector->GetParameter(i)
10587 : isolate->heap()->undefined_value(),
10588 isolate);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010589
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010590 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010592 SetProperty(isolate,
10593 local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010594 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010595 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010596 NONE,
10597 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010598 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010599 }
10600
10601 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010602 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010603 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010605 SetProperty(isolate,
10606 local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010607 Handle<String>(scope_info->StackLocalName(i)),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010608 Handle<Object>(frame_inspector->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010609 NONE,
10610 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010611 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010612 }
10613
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010614 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010615 // Third fill all context locals.
10616 Handle<Context> frame_context(Context::cast(frame->context()));
10617 Handle<Context> function_context(frame_context->declaration_context());
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000010618 if (!scope_info->CopyContextLocalsToScopeObject(
10619 isolate, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010620 return Handle<JSObject>();
10621 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010622
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010623 // Finally copy any properties from the function context extension.
10624 // These will be variables introduced by eval.
10625 if (function_context->closure() == *function) {
10626 if (function_context->has_extension() &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010627 !function_context->IsNativeContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010628 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010629 bool threw = false;
10630 Handle<FixedArray> keys =
10631 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10632 if (threw) return Handle<JSObject>();
10633
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010634 for (int i = 0; i < keys->length(); i++) {
10635 // Names of variables introduced by eval are strings.
10636 ASSERT(keys->get(i)->IsString());
10637 Handle<String> key(String::cast(keys->get(i)));
10638 RETURN_IF_EMPTY_HANDLE_VALUE(
10639 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010640 SetProperty(isolate,
10641 local_scope,
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010642 key,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010643 GetProperty(isolate, ext, key),
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010644 NONE,
10645 kNonStrictMode),
10646 Handle<JSObject>());
10647 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010648 }
10649 }
10650 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010651
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010652 return local_scope;
10653}
10654
10655
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010656static Handle<JSObject> MaterializeLocalScope(
10657 Isolate* isolate,
10658 JavaScriptFrame* frame,
10659 int inlined_jsframe_index) {
10660 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10661 return MaterializeLocalScopeWithFrameInspector(isolate,
10662 frame,
10663 &frame_inspector);
10664}
10665
10666
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010667// Set the context local variable value.
10668static bool SetContextLocalValue(Isolate* isolate,
10669 Handle<ScopeInfo> scope_info,
10670 Handle<Context> context,
10671 Handle<String> variable_name,
10672 Handle<Object> new_value) {
10673 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10674 Handle<String> next_name(scope_info->ContextLocalName(i));
10675 if (variable_name->Equals(*next_name)) {
10676 VariableMode mode;
10677 InitializationFlag init_flag;
10678 int context_index =
10679 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag);
10680 context->set(context_index, *new_value);
10681 return true;
10682 }
10683 }
10684
10685 return false;
10686}
10687
10688
10689static bool SetLocalVariableValue(Isolate* isolate,
10690 JavaScriptFrame* frame,
10691 int inlined_jsframe_index,
10692 Handle<String> variable_name,
10693 Handle<Object> new_value) {
10694 if (inlined_jsframe_index != 0 || frame->is_optimized()) {
10695 // Optimized frames are not supported.
10696 return false;
10697 }
10698
10699 Handle<JSFunction> function(JSFunction::cast(frame->function()));
10700 Handle<SharedFunctionInfo> shared(function->shared());
10701 Handle<ScopeInfo> scope_info(shared->scope_info());
10702
10703 bool default_result = false;
10704
10705 // Parameters.
10706 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
10707 if (scope_info->ParameterName(i)->Equals(*variable_name)) {
10708 frame->SetParameterValue(i, *new_value);
10709 // Argument might be shadowed in heap context, don't stop here.
10710 default_result = true;
10711 }
10712 }
10713
10714 // Stack locals.
10715 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
10716 if (scope_info->StackLocalName(i)->Equals(*variable_name)) {
10717 frame->SetExpression(i, *new_value);
10718 return true;
10719 }
10720 }
10721
10722 if (scope_info->HasContext()) {
10723 // Context locals.
10724 Handle<Context> frame_context(Context::cast(frame->context()));
10725 Handle<Context> function_context(frame_context->declaration_context());
10726 if (SetContextLocalValue(
10727 isolate, scope_info, function_context, variable_name, new_value)) {
10728 return true;
10729 }
10730
10731 // Function context extension. These are variables introduced by eval.
10732 if (function_context->closure() == *function) {
10733 if (function_context->has_extension() &&
10734 !function_context->IsNativeContext()) {
10735 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10736
10737 if (ext->HasProperty(*variable_name)) {
10738 // We don't expect this to do anything except replacing
10739 // property value.
10740 SetProperty(isolate,
10741 ext,
10742 variable_name,
10743 new_value,
10744 NONE,
10745 kNonStrictMode);
10746 return true;
10747 }
10748 }
10749 }
10750 }
10751
10752 return default_result;
10753}
10754
10755
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010756// Create a plain JSObject which materializes the closure content for the
10757// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10759 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010760 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010761
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010762 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010763 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010764
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010765 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010766 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 Handle<JSObject> closure_scope =
10768 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010769
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010770 // Fill all context locals to the context extension.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000010771 if (!scope_info->CopyContextLocalsToScopeObject(
10772 isolate, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010773 return Handle<JSObject>();
10774 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010775
10776 // Finally copy any properties from the function context extension. This will
10777 // be variables introduced by eval.
10778 if (context->has_extension()) {
10779 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010780 bool threw = false;
10781 Handle<FixedArray> keys =
10782 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10783 if (threw) return Handle<JSObject>();
10784
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785 for (int i = 0; i < keys->length(); i++) {
10786 // Names of variables introduced by eval are strings.
10787 ASSERT(keys->get(i)->IsString());
10788 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010789 RETURN_IF_EMPTY_HANDLE_VALUE(
10790 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010791 SetProperty(isolate,
10792 closure_scope,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010793 key,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010794 GetProperty(isolate, ext, key),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010795 NONE,
10796 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010797 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010798 }
10799 }
10800
10801 return closure_scope;
10802}
10803
10804
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010805// This method copies structure of MaterializeClosure method above.
10806static bool SetClosureVariableValue(Isolate* isolate,
10807 Handle<Context> context,
10808 Handle<String> variable_name,
10809 Handle<Object> new_value) {
10810 ASSERT(context->IsFunctionContext());
10811
10812 Handle<SharedFunctionInfo> shared(context->closure()->shared());
10813 Handle<ScopeInfo> scope_info(shared->scope_info());
10814
10815 // Context locals to the context extension.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010816 if (SetContextLocalValue(
10817 isolate, scope_info, context, variable_name, new_value)) {
10818 return true;
mmassi@chromium.org49a44672012-12-04 13:52:03 +000010819 }
10820
10821 // Properties from the function context extension. This will
10822 // be variables introduced by eval.
10823 if (context->has_extension()) {
10824 Handle<JSObject> ext(JSObject::cast(context->extension()));
10825 if (ext->HasProperty(*variable_name)) {
10826 // We don't expect this to do anything except replacing property value.
10827 SetProperty(isolate,
10828 ext,
10829 variable_name,
10830 new_value,
10831 NONE,
10832 kNonStrictMode);
10833 return true;
10834 }
10835 }
10836
10837 return false;
10838}
10839
10840
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010841// Create a plain JSObject which materializes the scope for the specified
10842// catch context.
10843static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10844 Handle<Context> context) {
10845 ASSERT(context->IsCatchContext());
10846 Handle<String> name(String::cast(context->extension()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010847 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
10848 isolate);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010849 Handle<JSObject> catch_scope =
10850 isolate->factory()->NewJSObject(isolate->object_function());
10851 RETURN_IF_EMPTY_HANDLE_VALUE(
10852 isolate,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010853 SetProperty(isolate,
10854 catch_scope,
10855 name,
10856 thrown_object,
10857 NONE,
10858 kNonStrictMode),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010859 Handle<JSObject>());
10860 return catch_scope;
10861}
10862
10863
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010864static bool SetCatchVariableValue(Isolate* isolate,
10865 Handle<Context> context,
10866 Handle<String> variable_name,
10867 Handle<Object> new_value) {
10868 ASSERT(context->IsCatchContext());
10869 Handle<String> name(String::cast(context->extension()));
10870 if (!name->Equals(*variable_name)) {
10871 return false;
10872 }
10873 context->set(Context::THROWN_OBJECT_INDEX, *new_value);
10874 return true;
10875}
10876
10877
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010878// Create a plain JSObject which materializes the block scope for the specified
10879// block context.
10880static Handle<JSObject> MaterializeBlockScope(
10881 Isolate* isolate,
10882 Handle<Context> context) {
10883 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010884 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010885
10886 // Allocate and initialize a JSObject with all the arguments, stack locals
10887 // heap locals and extension properties of the debugged function.
10888 Handle<JSObject> block_scope =
10889 isolate->factory()->NewJSObject(isolate->object_function());
10890
10891 // Fill all context locals.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000010892 if (!scope_info->CopyContextLocalsToScopeObject(
10893 isolate, context, block_scope)) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010894 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010895 }
10896
10897 return block_scope;
10898}
10899
10900
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010901// Create a plain JSObject which materializes the module scope for the specified
10902// module context.
10903static Handle<JSObject> MaterializeModuleScope(
10904 Isolate* isolate,
10905 Handle<Context> context) {
10906 ASSERT(context->IsModuleContext());
10907 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10908
10909 // Allocate and initialize a JSObject with all the members of the debugged
10910 // module.
10911 Handle<JSObject> module_scope =
10912 isolate->factory()->NewJSObject(isolate->object_function());
10913
10914 // Fill all context locals.
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +000010915 if (!scope_info->CopyContextLocalsToScopeObject(
10916 isolate, context, module_scope)) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010917 return Handle<JSObject>();
10918 }
10919
10920 return module_scope;
10921}
10922
10923
danno@chromium.org1044a4d2012-04-30 12:34:39 +000010924// Iterate over the actual scopes visible from a stack frame or from a closure.
10925// The iteration proceeds from the innermost visible nested scope outwards.
10926// All scopes are backed by an actual context except the local scope,
10927// which is inserted "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010928class ScopeIterator {
10929 public:
10930 enum ScopeType {
10931 ScopeTypeGlobal = 0,
10932 ScopeTypeLocal,
10933 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010934 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010935 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010936 ScopeTypeBlock,
10937 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010938 };
10939
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010940 ScopeIterator(Isolate* isolate,
10941 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010942 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010943 : isolate_(isolate),
10944 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010945 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010946 function_(JSFunction::cast(frame->function())),
10947 context_(Context::cast(frame->context())),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000010948 nested_scope_chain_(4),
10949 failed_(false) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010950
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010951 // Catch the case when the debugger stops in an internal function.
10952 Handle<SharedFunctionInfo> shared_info(function_->shared());
10953 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10954 if (shared_info->script() == isolate->heap()->undefined_value()) {
10955 while (context_->closure() == *function_) {
10956 context_ = Handle<Context>(context_->previous(), isolate_);
10957 }
10958 return;
10959 }
10960
10961 // Get the debug info (create it if it does not exist).
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010962 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010963 // Return if ensuring debug info failed.
10964 return;
10965 }
10966 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10967
10968 // Find the break point where execution has stopped.
10969 BreakLocationIterator break_location_iterator(debug_info,
10970 ALL_BREAK_LOCATIONS);
10971 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10972 if (break_location_iterator.IsExit()) {
10973 // We are within the return sequence. At the momemt it is not possible to
10974 // get a source position which is consistent with the current scope chain.
10975 // Thus all nested with, catch and block contexts are skipped and we only
10976 // provide the function scope.
10977 if (scope_info->HasContext()) {
10978 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10979 } else {
10980 while (context_->closure() == *function_) {
10981 context_ = Handle<Context>(context_->previous(), isolate_);
10982 }
10983 }
10984 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10985 } else {
10986 // Reparse the code and analyze the scopes.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010987 Handle<Script> script(Script::cast(shared_info->script()));
10988 Scope* scope = NULL;
10989
10990 // Check whether we are in global, eval or function code.
10991 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10992 if (scope_info->Type() != FUNCTION_SCOPE) {
10993 // Global or eval code.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010994 CompilationInfoWithZone info(script);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010995 if (scope_info->Type() == GLOBAL_SCOPE) {
10996 info.MarkAsGlobal();
10997 } else {
10998 ASSERT(scope_info->Type() == EVAL_SCOPE);
10999 info.MarkAsEval();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000011000 info.SetContext(Handle<Context>(function_->context()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011001 }
11002 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11003 scope = info.function()->scope();
11004 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011005 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011006 } else {
11007 // Function code
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011008 CompilationInfoWithZone info(shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011009 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11010 scope = info.function()->scope();
11011 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011012 RetrieveScopeChain(scope, shared_info);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011013 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011014 }
11015 }
11016
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011017 ScopeIterator(Isolate* isolate,
11018 Handle<JSFunction> function)
11019 : isolate_(isolate),
11020 frame_(NULL),
11021 inlined_jsframe_index_(0),
11022 function_(function),
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011023 context_(function->context()),
11024 failed_(false) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011025 if (function->IsBuiltin()) {
11026 context_ = Handle<Context>();
11027 }
11028 }
11029
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011030 // More scopes?
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011031 bool Done() {
11032 ASSERT(!failed_);
11033 return context_.is_null();
11034 }
11035
11036 bool Failed() { return failed_; }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011037
11038 // Move to the next scope.
11039 void Next() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011040 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011041 ScopeType scope_type = Type();
11042 if (scope_type == ScopeTypeGlobal) {
11043 // The global scope is always the last in the chain.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011044 ASSERT(context_->IsNativeContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045 context_ = Handle<Context>();
11046 return;
11047 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011048 if (nested_scope_chain_.is_empty()) {
11049 context_ = Handle<Context>(context_->previous(), isolate_);
11050 } else {
11051 if (nested_scope_chain_.last()->HasContext()) {
11052 ASSERT(context_->previous() != NULL);
11053 context_ = Handle<Context>(context_->previous(), isolate_);
11054 }
11055 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011056 }
11057 }
11058
11059 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011060 ScopeType Type() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011061 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011062 if (!nested_scope_chain_.is_empty()) {
11063 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11064 switch (scope_info->Type()) {
11065 case FUNCTION_SCOPE:
11066 ASSERT(context_->IsFunctionContext() ||
11067 !scope_info->HasContext());
11068 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011069 case MODULE_SCOPE:
11070 ASSERT(context_->IsModuleContext());
11071 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011072 case GLOBAL_SCOPE:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011073 ASSERT(context_->IsNativeContext());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011074 return ScopeTypeGlobal;
11075 case WITH_SCOPE:
11076 ASSERT(context_->IsWithContext());
11077 return ScopeTypeWith;
11078 case CATCH_SCOPE:
11079 ASSERT(context_->IsCatchContext());
11080 return ScopeTypeCatch;
11081 case BLOCK_SCOPE:
11082 ASSERT(!scope_info->HasContext() ||
11083 context_->IsBlockContext());
11084 return ScopeTypeBlock;
11085 case EVAL_SCOPE:
11086 UNREACHABLE();
11087 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011089 if (context_->IsNativeContext()) {
11090 ASSERT(context_->global_object()->IsGlobalObject());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011091 return ScopeTypeGlobal;
11092 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011093 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 return ScopeTypeClosure;
11095 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011096 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011097 return ScopeTypeCatch;
11098 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011099 if (context_->IsBlockContext()) {
11100 return ScopeTypeBlock;
11101 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011102 if (context_->IsModuleContext()) {
11103 return ScopeTypeModule;
11104 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011105 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011106 return ScopeTypeWith;
11107 }
11108
11109 // Return the JavaScript object with the content of the current scope.
11110 Handle<JSObject> ScopeObject() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011111 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 switch (Type()) {
11113 case ScopeIterator::ScopeTypeGlobal:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011114 return Handle<JSObject>(CurrentContext()->global_object());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011115 case ScopeIterator::ScopeTypeLocal:
11116 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011117 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011118 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011119 case ScopeIterator::ScopeTypeWith:
11120 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011121 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11122 case ScopeIterator::ScopeTypeCatch:
11123 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 case ScopeIterator::ScopeTypeClosure:
11125 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011127 case ScopeIterator::ScopeTypeBlock:
11128 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011129 case ScopeIterator::ScopeTypeModule:
11130 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011131 }
11132 UNREACHABLE();
11133 return Handle<JSObject>();
11134 }
11135
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011136 bool SetVariableValue(Handle<String> variable_name,
11137 Handle<Object> new_value) {
11138 ASSERT(!failed_);
11139 switch (Type()) {
11140 case ScopeIterator::ScopeTypeGlobal:
11141 break;
11142 case ScopeIterator::ScopeTypeLocal:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011143 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_,
11144 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011145 case ScopeIterator::ScopeTypeWith:
11146 break;
11147 case ScopeIterator::ScopeTypeCatch:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011148 return SetCatchVariableValue(isolate_, CurrentContext(),
11149 variable_name, new_value);
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011150 case ScopeIterator::ScopeTypeClosure:
11151 return SetClosureVariableValue(isolate_, CurrentContext(),
11152 variable_name, new_value);
11153 case ScopeIterator::ScopeTypeBlock:
11154 // TODO(2399): should we implement it?
11155 break;
11156 case ScopeIterator::ScopeTypeModule:
11157 // TODO(2399): should we implement it?
11158 break;
11159 }
11160 return false;
11161 }
11162
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011163 Handle<ScopeInfo> CurrentScopeInfo() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011164 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011165 if (!nested_scope_chain_.is_empty()) {
11166 return nested_scope_chain_.last();
11167 } else if (context_->IsBlockContext()) {
11168 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11169 } else if (context_->IsFunctionContext()) {
11170 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11171 }
11172 return Handle<ScopeInfo>::null();
11173 }
11174
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175 // Return the context for this scope. For the local context there might not
11176 // be an actual context.
11177 Handle<Context> CurrentContext() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011178 ASSERT(!failed_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011179 if (Type() == ScopeTypeGlobal ||
11180 nested_scope_chain_.is_empty()) {
11181 return context_;
11182 } else if (nested_scope_chain_.last()->HasContext()) {
11183 return context_;
11184 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 return Handle<Context>();
11186 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011187 }
11188
11189#ifdef DEBUG
11190 // Debug print of the content of the current scope.
11191 void DebugPrint() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011192 ASSERT(!failed_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 switch (Type()) {
11194 case ScopeIterator::ScopeTypeGlobal:
11195 PrintF("Global:\n");
11196 CurrentContext()->Print();
11197 break;
11198
11199 case ScopeIterator::ScopeTypeLocal: {
11200 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011201 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202 if (!CurrentContext().is_null()) {
11203 CurrentContext()->Print();
11204 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011205 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206 if (extension->IsJSContextExtensionObject()) {
11207 extension->Print();
11208 }
11209 }
11210 }
11211 break;
11212 }
11213
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011214 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011215 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011216 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011218
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011219 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011220 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011221 CurrentContext()->extension()->Print();
11222 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011223 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011224
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011225 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011226 PrintF("Closure:\n");
11227 CurrentContext()->Print();
11228 if (CurrentContext()->has_extension()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011229 Handle<Object> extension(CurrentContext()->extension(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230 if (extension->IsJSContextExtensionObject()) {
11231 extension->Print();
11232 }
11233 }
11234 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011235
11236 default:
11237 UNREACHABLE();
11238 }
11239 PrintF("\n");
11240 }
11241#endif
11242
11243 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011244 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011245 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011246 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011247 Handle<JSFunction> function_;
11248 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011249 List<Handle<ScopeInfo> > nested_scope_chain_;
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011250 bool failed_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011251
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011252 void RetrieveScopeChain(Scope* scope,
11253 Handle<SharedFunctionInfo> shared_info) {
11254 if (scope != NULL) {
11255 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11256 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11257 } else {
11258 // A failed reparse indicates that the preparser has diverged from the
11259 // parser or that the preparse data given to the initial parse has been
11260 // faulty. We fail in debug mode but in release mode we only provide the
11261 // information we get from the context chain but nothing about
11262 // completely stack allocated scopes or stack allocated locals.
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011263 // Or it could be due to stack overflow.
11264 ASSERT(isolate_->has_pending_exception());
11265 failed_ = true;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011266 }
11267 }
11268
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011269 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11270};
11271
11272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011273RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011274 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275 ASSERT(args.length() == 2);
11276
11277 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011278 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011279 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11280 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011281 if (!maybe_check->ToObject(&check)) return maybe_check;
11282 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011283 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011284
11285 // Get the frame where the debugging is performed.
11286 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011287 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011288 JavaScriptFrame* frame = it.frame();
11289
11290 // Count the visible scopes.
11291 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011292 for (ScopeIterator it(isolate, frame, 0);
11293 !it.Done();
11294 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295 n++;
11296 }
11297
11298 return Smi::FromInt(n);
11299}
11300
11301
11302static const int kScopeDetailsTypeIndex = 0;
11303static const int kScopeDetailsObjectIndex = 1;
11304static const int kScopeDetailsSize = 2;
11305
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011306
11307static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
11308 ScopeIterator* it) {
11309 // Calculate the size of the result.
11310 int details_size = kScopeDetailsSize;
11311 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
11312
11313 // Fill in scope details.
11314 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
11315 Handle<JSObject> scope_object = it->ScopeObject();
11316 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
11317 details->set(kScopeDetailsObjectIndex, *scope_object);
11318
11319 return *isolate->factory()->NewJSArrayWithElements(details);
11320}
11321
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322// Return an array with scope details
11323// args[0]: number: break id
11324// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011325// args[2]: number: inlined frame index
11326// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011327//
11328// The array returned contains the following information:
11329// 0: Scope type
11330// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011331RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011333 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011334
11335 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011336 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011337 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11338 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011339 if (!maybe_check->ToObject(&check)) return maybe_check;
11340 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011341 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011342 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011343 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011344
11345 // Get the frame where the debugging is performed.
11346 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011347 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011348 JavaScriptFrame* frame = frame_it.frame();
11349
11350 // Find the requested scope.
11351 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011352 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011353 for (; !it.Done() && n < index; it.Next()) {
11354 n++;
11355 }
11356 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011358 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011359 return MaterializeScopeDetails(isolate, &it);
11360}
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011361
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011362
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011363RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
11364 HandleScope scope(isolate);
11365 ASSERT(args.length() == 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011366
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011367 // Check arguments.
11368 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11369
11370 // Count the visible scopes.
11371 int n = 0;
11372 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
11373 n++;
11374 }
11375
11376 return Smi::FromInt(n);
11377}
11378
11379
11380RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
11381 HandleScope scope(isolate);
11382 ASSERT(args.length() == 2);
11383
11384 // Check arguments.
11385 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11386 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11387
11388 // Find the requested scope.
11389 int n = 0;
11390 ScopeIterator it(isolate, fun);
11391 for (; !it.Done() && n < index; it.Next()) {
11392 n++;
11393 }
11394 if (it.Done()) {
11395 return isolate->heap()->undefined_value();
11396 }
11397
11398 return MaterializeScopeDetails(isolate, &it);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011399}
11400
11401
mmassi@chromium.org49a44672012-12-04 13:52:03 +000011402static bool SetScopeVariableValue(ScopeIterator* it, int index,
11403 Handle<String> variable_name,
11404 Handle<Object> new_value) {
11405 for (int n = 0; !it->Done() && n < index; it->Next()) {
11406 n++;
11407 }
11408 if (it->Done()) {
11409 return false;
11410 }
11411 return it->SetVariableValue(variable_name, new_value);
11412}
11413
11414
11415// Change variable value in closure or local scope
11416// args[0]: number or JsFunction: break id or function
11417// args[1]: number: frame index (when arg[0] is break id)
11418// args[2]: number: inlined frame index (when arg[0] is break id)
11419// args[3]: number: scope index
11420// args[4]: string: variable name
11421// args[5]: object: new value
11422//
11423// Return true if success and false otherwise
11424RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) {
11425 HandleScope scope(isolate);
11426 ASSERT(args.length() == 6);
11427
11428 // Check arguments.
11429 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
11430 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4);
11431 Handle<Object> new_value = args.at<Object>(5);
11432
11433 bool res;
11434 if (args[0]->IsNumber()) {
11435 Object* check;
11436 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11437 RUNTIME_ARGUMENTS(isolate, args));
11438 if (!maybe_check->ToObject(&check)) return maybe_check;
11439 }
11440 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11441 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
11442
11443 // Get the frame where the debugging is performed.
11444 StackFrame::Id id = UnwrapFrameId(wrapped_id);
11445 JavaScriptFrameIterator frame_it(isolate, id);
11446 JavaScriptFrame* frame = frame_it.frame();
11447
11448 ScopeIterator it(isolate, frame, inlined_jsframe_index);
11449 res = SetScopeVariableValue(&it, index, variable_name, new_value);
11450 } else {
11451 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11452 ScopeIterator it(isolate, fun);
11453 res = SetScopeVariableValue(&it, index, variable_name, new_value);
11454 }
11455
11456 return isolate->heap()->ToBoolean(res);
11457}
11458
11459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011460RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011462 ASSERT(args.length() == 0);
11463
11464#ifdef DEBUG
11465 // Print the scopes for the top frame.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000011466 StackFrameLocator locator(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011467 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011468 for (ScopeIterator it(isolate, frame, 0);
11469 !it.Done();
11470 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011471 it.DebugPrint();
11472 }
11473#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011474 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011475}
11476
11477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011479 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011480 ASSERT(args.length() == 1);
11481
11482 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011483 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011484 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11485 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011486 if (!maybe_result->ToObject(&result)) return maybe_result;
11487 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011488
11489 // Count all archived V8 threads.
11490 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011491 for (ThreadState* thread =
11492 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011493 thread != NULL;
11494 thread = thread->Next()) {
11495 n++;
11496 }
11497
11498 // Total number of threads is current thread and archived threads.
11499 return Smi::FromInt(n + 1);
11500}
11501
11502
11503static const int kThreadDetailsCurrentThreadIndex = 0;
11504static const int kThreadDetailsThreadIdIndex = 1;
11505static const int kThreadDetailsSize = 2;
11506
11507// Return an array with thread details
11508// args[0]: number: break id
11509// args[1]: number: thread index
11510//
11511// The array returned contains the following information:
11512// 0: Is current thread?
11513// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011516 ASSERT(args.length() == 2);
11517
11518 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011519 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011520 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11521 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011522 if (!maybe_check->ToObject(&check)) return maybe_check;
11523 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011524 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11525
11526 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011527 Handle<FixedArray> details =
11528 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011529
11530 // Thread index 0 is current thread.
11531 if (index == 0) {
11532 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 details->set(kThreadDetailsCurrentThreadIndex,
11534 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011535 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011536 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011537 } else {
11538 // Find the thread with the requested index.
11539 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 ThreadState* thread =
11541 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011542 while (index != n && thread != NULL) {
11543 thread = thread->Next();
11544 n++;
11545 }
11546 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011548 }
11549
11550 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 details->set(kThreadDetailsCurrentThreadIndex,
11552 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011553 details->set(kThreadDetailsThreadIdIndex,
11554 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011555 }
11556
11557 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011559}
11560
11561
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011562// Sets the disable break state
11563// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011564RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011566 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011567 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 isolate->debug()->set_disable_break(disable_break);
11569 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011570}
11571
11572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011573RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 ASSERT(args.length() == 1);
11576
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011577 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011578 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579 // Find the number of break points
11580 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011582 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584 Handle<FixedArray>::cast(break_locations));
11585}
11586
11587
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011588// Set a break point in a function.
11589// args[0]: function
11590// args[1]: number: break source position (within the function source)
11591// args[2]: number: break point object
11592RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
11593 HandleScope scope(isolate);
11594 ASSERT(args.length() == 3);
11595 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
11596 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11597 RUNTIME_ASSERT(source_position >= 0);
11598 Handle<Object> break_point_object_arg = args.at<Object>(2);
11599
11600 // Set break point.
11601 isolate->debug()->SetBreakPoint(function, break_point_object_arg,
11602 &source_position);
11603
11604 return Smi::FromInt(source_position);
11605}
11606
11607
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011608// Changes the state of a break point in a script and returns source position
11609// where break point was set. NOTE: Regarding performance see the NOTE for
11610// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011611// args[0]: script to set break point in
11612// args[1]: number: break source position (within the script source)
11613// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011614RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011616 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011617 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11619 RUNTIME_ASSERT(source_position >= 0);
11620 Handle<Object> break_point_object_arg = args.at<Object>(2);
11621
11622 // Get the script from the script wrapper.
11623 RUNTIME_ASSERT(wrapper->value()->IsScript());
11624 Handle<Script> script(Script::cast(wrapper->value()));
11625
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011626 // Set break point.
11627 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
11628 &source_position)) {
11629 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011630 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011631
11632 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633}
11634
11635
11636// Clear a break point
11637// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011638RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011640 ASSERT(args.length() == 1);
11641 Handle<Object> break_point_object_arg = args.at<Object>(0);
11642
11643 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647}
11648
11649
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011650// Change the state of break on exceptions.
11651// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11652// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011655 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011656 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011657 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011659 // If the number doesn't match an enum value, the ChangeBreakOnException
11660 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661 ExceptionBreakType type =
11662 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011663 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 isolate->debug()->ChangeBreakOnException(type, enable);
11665 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666}
11667
11668
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011669// Returns the state of break on exceptions
11670// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011673 ASSERT(args.length() == 1);
11674 RUNTIME_ASSERT(args[0]->IsNumber());
11675
11676 ExceptionBreakType type =
11677 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011679 return Smi::FromInt(result);
11680}
11681
11682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011683// Prepare for stepping
11684// args[0]: break id for checking execution state
11685// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011686// args[2]: number of times to perform the step, for step out it is the number
11687// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011688RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 ASSERT(args.length() == 3);
11691 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011692 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011693 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11694 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011695 if (!maybe_check->ToObject(&check)) return maybe_check;
11696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011697 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011698 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 }
11700
11701 // Get the step action and check validity.
11702 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11703 if (step_action != StepIn &&
11704 step_action != StepNext &&
11705 step_action != StepOut &&
11706 step_action != StepInMin &&
11707 step_action != StepMin) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011708 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709 }
11710
11711 // Get the number of steps.
11712 int step_count = NumberToInt32(args[2]);
11713 if (step_count < 1) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011714 return isolate->Throw(isolate->heap()->illegal_argument_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 }
11716
ager@chromium.orga1645e22009-09-09 19:27:10 +000011717 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011720 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11722 step_count);
11723 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724}
11725
11726
11727// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011728RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011730 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 isolate->debug()->ClearStepping();
11732 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733}
11734
11735
11736// Creates a copy of the with context chain. The copy of the context chain is
11737// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011738static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11739 Handle<JSFunction> function,
11740 Handle<Context> base,
11741 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011742 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011743 HandleScope scope(isolate);
11744 List<Handle<ScopeInfo> > scope_chain;
11745 List<Handle<Context> > context_chain;
11746
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011747 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011748 if (it.Failed()) return Handle<Context>::null();
11749
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011750 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11751 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11752 ASSERT(!it.Done());
11753 scope_chain.Add(it.CurrentScopeInfo());
11754 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011755 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011756
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011757 // At the end of the chain. Return the base context to link to.
11758 Handle<Context> context = base;
11759
11760 // Iteratively copy and or materialize the nested contexts.
11761 while (!scope_chain.is_empty()) {
11762 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11763 Handle<Context> current = context_chain.RemoveLast();
11764 ASSERT(!(scope_info->HasContext() & current.is_null()));
11765
11766 if (scope_info->Type() == CATCH_SCOPE) {
11767 Handle<String> name(String::cast(current->extension()));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011768 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX),
11769 isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011770 context =
11771 isolate->factory()->NewCatchContext(function,
11772 context,
11773 name,
11774 thrown_object);
11775 } else if (scope_info->Type() == BLOCK_SCOPE) {
11776 // Materialize the contents of the block scope into a JSObject.
11777 Handle<JSObject> block_scope_object =
11778 MaterializeBlockScope(isolate, current);
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011779 CHECK(!block_scope_object.is_null());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011780 // Allocate a new function context for the debug evaluation and set the
11781 // extension object.
11782 Handle<Context> new_context =
11783 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11784 function);
11785 new_context->set_extension(*block_scope_object);
11786 new_context->set_previous(*context);
11787 context = new_context;
11788 } else {
11789 ASSERT(scope_info->Type() == WITH_SCOPE);
11790 ASSERT(current->IsWithContext());
11791 Handle<JSObject> extension(JSObject::cast(current->extension()));
11792 context =
11793 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011794 }
erikcorry0ad885c2011-11-21 13:51:57 +000011795 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011796
11797 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798}
11799
11800
11801// Helper function to find or create the arguments object for
11802// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011803static Handle<Object> GetArgumentsObject(Isolate* isolate,
11804 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011805 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011806 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807 Handle<Context> function_context) {
11808 // Try to find the value of 'arguments' to pass as parameter. If it is not
11809 // found (that is the debugged function does not reference 'arguments' and
11810 // does not support eval) then create an 'arguments' object.
11811 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011812 if (scope_info->StackLocalCount() > 0) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011813 index = scope_info->StackSlotIndex(isolate->heap()->arguments_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 }
11817 }
11818
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011819 if (scope_info->HasHeapAllocatedLocals()) {
11820 VariableMode mode;
11821 InitializationFlag init_flag;
11822 index = scope_info->ContextSlotIndex(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011823 isolate->heap()->arguments_string(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826 }
11827 }
11828
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011829 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11830 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 Handle<JSObject> arguments =
11832 isolate->factory()->NewArgumentsObject(function, length);
11833 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011834
11835 AssertNoAllocation no_gc;
11836 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011838 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011840 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 return arguments;
11842}
11843
11844
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845static const char kSourceStr[] =
11846 "(function(arguments,__source__){return eval(__source__);})";
11847
11848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011850// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851// extension part has all the parameters and locals of the function on the
11852// stack frame. A function which calls eval with the code to evaluate is then
11853// compiled in this context and called in this context. As this context
11854// replaces the context of the function on the stack frame a new (empty)
11855// function is created as well to be used as the closure for the context.
11856// This function and the context acts as replacements for the function on the
11857// stack frame presenting the same view of the values of parameters and
11858// local variables as if the piece of JavaScript was evaluated at the point
11859// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011860RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862
11863 // Check the execution state and decode arguments frame and source to be
11864 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011865 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011866 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011867 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11868 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011869 if (!maybe_check_result->ToObject(&check_result)) {
11870 return maybe_check_result;
11871 }
11872 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011873 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011874 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011875 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11876 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011877 Handle<Object> additional_context(args[5], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011878
11879 // Handle the processing of break.
11880 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881
11882 // Get the frame where the debugging is performed.
11883 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011884 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011886 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11887 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011888 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889
11890 // Traverse the saved contexts chain to find the active context for the
11891 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011892 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 SaveContext savex(isolate);
11895 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896
11897 // Create the (empty) function replacing the function on the stack frame for
11898 // the purpose of evaluating in the context created below. It is important
11899 // that this function does not describe any parameters and local variables
11900 // in the context. If it does then this will cause problems with the lookup
11901 // in Context::Lookup, where context slots for parameters and local variables
11902 // are looked at before the extension object.
11903 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11905 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011906 go_between->set_context(function->context());
11907#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011908 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11909 ASSERT(go_between_scope_info->ParameterCount() == 0);
11910 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911#endif
11912
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011913 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011914 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11915 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011916 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917
11918 // Allocate a new context for the debug evaluation and set the extension
11919 // object build.
11920 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11922 go_between);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000011923
11924 // Use the materialized local scope in a with context.
11925 context =
11926 isolate->factory()->NewWithContext(go_between, context, local_scope);
11927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011929 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011930 Handle<Context> function_context;
11931 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011932 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011933 function_context = Handle<Context>(frame_context->declaration_context());
11934 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011935 context = CopyNestedScopeContextChain(isolate,
11936 go_between,
11937 context,
11938 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011939 inlined_jsframe_index);
ulan@chromium.org56c14af2012-09-20 12:51:09 +000011940 if (context.is_null()) {
11941 ASSERT(isolate->has_pending_exception());
11942 MaybeObject* exception = isolate->pending_exception();
11943 isolate->clear_pending_exception();
11944 return exception;
11945 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011947 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011948 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011949 context =
11950 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011951 }
11952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953 // Wrap the evaluation statement in a new function compiled in the newly
11954 // created context. The function has one parameter which has to be called
11955 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011956 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011957 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011959 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 isolate->factory()->NewStringFromAscii(
11961 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011962
11963 // Currently, the eval code will be executed in non-strict mode,
11964 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011965 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011966 Compiler::CompileEval(function_source,
11967 context,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011968 context->IsNativeContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011969 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011970 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011971 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011972 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974
11975 // Invoke the result of the compilation to get the evaluation function.
11976 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011977 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978 Handle<Object> evaluation_function =
11979 Execution::Call(compiled_function, receiver, 0, NULL,
11980 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011981 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011982
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011983 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011984 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011985 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011986 scope_info,
11987 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011989 // Check if eval is blocked in the context and temporarily allow it
11990 // for debugger.
11991 Handle<Context> native_context = Handle<Context>(context->native_context());
11992 bool eval_disabled =
11993 native_context->allow_code_gen_from_strings()->IsFalse();
11994 if (eval_disabled) {
11995 native_context->set_allow_code_gen_from_strings(
11996 isolate->heap()->true_value());
11997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011999 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012000 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012001 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12002 receiver,
12003 ARRAY_SIZE(argv),
12004 argv,
12005 &has_pending_exception);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000012006 if (eval_disabled) {
12007 native_context->set_allow_code_gen_from_strings(
12008 isolate->heap()->false_value());
12009 }
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012010 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012011
12012 // Skip the global proxy as it has no properties and always delegates to the
12013 // real global object.
12014 if (result->IsJSGlobalProxy()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012015 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate)));
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012016 }
12017
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012018 return *result;
12019}
12020
12021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012022RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012023 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024
12025 // Check the execution state and decode arguments frame and source to be
12026 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012027 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012028 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12030 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012031 if (!maybe_check_result->ToObject(&check_result)) {
12032 return maybe_check_result;
12033 }
12034 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012035 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12036 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012037 Handle<Object> additional_context(args[3], isolate);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012038
12039 // Handle the processing of break.
12040 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012041
12042 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012044 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012045 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046 top = top->prev();
12047 }
12048 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012049 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 }
12051
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012052 // Get the native context now set to the top context from before the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 // debugger was invoked.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012054 Handle<Context> context = isolate->native_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012056 bool is_global = true;
12057
12058 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012059 // Create a new with context with the additional context information between
12060 // the context of the debugged function and the eval code to be executed.
12061 context = isolate->factory()->NewWithContext(
12062 Handle<JSFunction>(context->closure()),
12063 context,
12064 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012065 is_global = false;
12066 }
12067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012069 // Currently, the eval code will be executed in non-strict mode,
12070 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012071 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012072 Compiler::CompileEval(source,
12073 context,
12074 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012075 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012076 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012077 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 Handle<JSFunction>(
12080 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12081 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012082
12083 // Invoke the result of the compilation to get the evaluation function.
12084 bool has_pending_exception;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012085 Handle<Object> receiver = isolate->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086 Handle<Object> result =
12087 Execution::Call(compiled_function, receiver, 0, NULL,
12088 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012089 // Clear the oneshot breakpoints so that the debugger does not step further.
12090 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012091 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092 return *result;
12093}
12094
12095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012096RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012097 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012098 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012101 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102
12103 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012104 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012105 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12106 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12107 // because using
12108 // instances->set(i, *GetScriptWrapper(script))
12109 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012110 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012111 Handle<JSValue> wrapper = GetScriptWrapper(script);
12112 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012113 }
12114
12115 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116 Handle<JSObject> result =
12117 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012118 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 return *result;
12120}
12121
12122
12123// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012124static int DebugReferencedBy(HeapIterator* iterator,
12125 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012126 Object* instance_filter, int max_references,
12127 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012128 JSFunction* arguments_function) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012129 Isolate* isolate = target->GetIsolate();
12130 NoHandleAllocation ha(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 AssertNoAllocation no_alloc;
12132
12133 // Iterate the heap.
12134 int count = 0;
12135 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012136 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012137 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012138 (max_references == 0 || count < max_references)) {
12139 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 if (heap_obj->IsJSObject()) {
12141 // Skip context extension objects and argument arrays as these are
12142 // checked in the context of functions using them.
12143 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012144 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012145 obj->map()->constructor() == arguments_function) {
12146 continue;
12147 }
12148
12149 // Check if the JS object has a reference to the object looked for.
12150 if (obj->ReferencesObject(target)) {
12151 // Check instance filter if supplied. This is normally used to avoid
12152 // references from mirror objects (see Runtime_IsInPrototypeChain).
12153 if (!instance_filter->IsUndefined()) {
12154 Object* V = obj;
12155 while (true) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000012156 Object* prototype = V->GetPrototype(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 if (prototype->IsNull()) {
12158 break;
12159 }
12160 if (instance_filter == prototype) {
12161 obj = NULL; // Don't add this object.
12162 break;
12163 }
12164 V = prototype;
12165 }
12166 }
12167
12168 if (obj != NULL) {
12169 // Valid reference found add to instance array if supplied an update
12170 // count.
12171 if (instances != NULL && count < instances_size) {
12172 instances->set(count, obj);
12173 }
12174 last = obj;
12175 count++;
12176 }
12177 }
12178 }
12179 }
12180
12181 // Check for circular reference only. This can happen when the object is only
12182 // referenced from mirrors and has a circular reference in which case the
12183 // object is not really alive and would have been garbage collected if not
12184 // referenced from the mirror.
12185 if (count == 1 && last == target) {
12186 count = 0;
12187 }
12188
12189 // Return the number of referencing objects found.
12190 return count;
12191}
12192
12193
12194// Scan the heap for objects with direct references to an object
12195// args[0]: the object to find references to
12196// args[1]: constructor function for instances to exclude (Mirror)
12197// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012198RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 ASSERT(args.length() == 3);
12200
12201 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012202 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12203 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012204 // The heap iterator reserves the right to do a GC to make the heap iterable.
12205 // Due to the GC above we know it won't need to do that, but it seems cleaner
12206 // to get the heap iterator constructed before we start having unprotected
12207 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208
12209 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012210 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 Object* instance_filter = args[1];
12212 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12213 instance_filter->IsJSObject());
12214 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12215 RUNTIME_ASSERT(max_references >= 0);
12216
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012220 isolate->context()->native_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221 JSFunction* arguments_function =
12222 JSFunction::cast(arguments_boilerplate->map()->constructor());
12223
12224 // Get the number of referencing objects.
12225 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012226 Heap* heap = isolate->heap();
12227 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012228 count = DebugReferencedBy(&heap_iterator,
12229 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012230 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231
12232 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012233 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012234 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012235 if (!maybe_object->ToObject(&object)) return maybe_object;
12236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237 FixedArray* instances = FixedArray::cast(object);
12238
12239 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012240 // AllocateFixedArray above does not make the heap non-iterable.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012241 ASSERT(heap->IsHeapIterable());
12242 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012243 count = DebugReferencedBy(&heap_iterator2,
12244 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012245 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246
12247 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012248 Object* result;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012249 MaybeObject* maybe_result = heap->AllocateJSObject(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012250 isolate->context()->native_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012251 if (!maybe_result->ToObject(&result)) return maybe_result;
12252 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012253}
12254
12255
12256// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012257static int DebugConstructedBy(HeapIterator* iterator,
12258 JSFunction* constructor,
12259 int max_references,
12260 FixedArray* instances,
12261 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 AssertNoAllocation no_alloc;
12263
12264 // Iterate the heap.
12265 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012266 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012267 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012268 (max_references == 0 || count < max_references)) {
12269 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012270 if (heap_obj->IsJSObject()) {
12271 JSObject* obj = JSObject::cast(heap_obj);
12272 if (obj->map()->constructor() == constructor) {
12273 // Valid reference found add to instance array if supplied an update
12274 // count.
12275 if (instances != NULL && count < instances_size) {
12276 instances->set(count, obj);
12277 }
12278 count++;
12279 }
12280 }
12281 }
12282
12283 // Return the number of referencing objects found.
12284 return count;
12285}
12286
12287
12288// Scan the heap for objects constructed by a specific function.
12289// args[0]: the constructor to find instances of
12290// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012291RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012292 ASSERT(args.length() == 2);
12293
12294 // First perform a full GC in order to avoid dead objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012295 Heap* heap = isolate->heap();
12296 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297
12298 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012299 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12301 RUNTIME_ASSERT(max_references >= 0);
12302
12303 // Get the number of referencing objects.
12304 int count;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012305 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012306 count = DebugConstructedBy(&heap_iterator,
12307 constructor,
12308 max_references,
12309 NULL,
12310 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311
12312 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012313 Object* object;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012314 { MaybeObject* maybe_object = heap->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012315 if (!maybe_object->ToObject(&object)) return maybe_object;
12316 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012317 FixedArray* instances = FixedArray::cast(object);
12318
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012319 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012320 // Fill the referencing objects.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012321 HeapIterator heap_iterator2(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012322 count = DebugConstructedBy(&heap_iterator2,
12323 constructor,
12324 max_references,
12325 instances,
12326 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012327
12328 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012329 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012330 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012331 isolate->context()->native_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012332 if (!maybe_result->ToObject(&result)) return maybe_result;
12333 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012334 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012335}
12336
12337
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012338// Find the effective prototype object as returned by __proto__.
12339// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012340RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341 ASSERT(args.length() == 1);
12342
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012343 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012344
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012345 // Use the __proto__ accessor.
12346 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347}
12348
12349
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012350// Patches script source (should be called upon BeforeCompile event).
12351RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12352 HandleScope scope(isolate);
12353 ASSERT(args.length() == 2);
12354
12355 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012356 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012357
12358 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12359 Handle<Script> script(Script::cast(script_wrapper->value()));
12360
12361 int compilation_state = Smi::cast(script->compilation_state())->value();
12362 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12363 script->set_source(*source);
12364
12365 return isolate->heap()->undefined_value();
12366}
12367
12368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012369RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012370 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012371 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012372 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012373}
12374
12375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012376RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012377#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012379 ASSERT(args.length() == 1);
12380 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012381 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012382 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012383 return Failure::Exception();
12384 }
12385 func->code()->PrintLn();
12386#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012387 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012388}
ager@chromium.org9085a012009-05-11 19:22:57 +000012389
12390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012391RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012392#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012393 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012394 ASSERT(args.length() == 1);
12395 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012396 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012397 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012398 return Failure::Exception();
12399 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +000012400 func->shared()->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012401#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012402 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012403}
12404
12405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012406RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012407 NoHandleAllocation ha(isolate);
ager@chromium.org9085a012009-05-11 19:22:57 +000012408 ASSERT(args.length() == 1);
12409
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012410 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012411 return f->shared()->inferred_name();
12412}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012413
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012414
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012415static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12416 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012417 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012418 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012419 int counter = 0;
12420 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012421 for (HeapObject* obj = iterator->next();
12422 obj != NULL;
12423 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424 ASSERT(obj != NULL);
12425 if (!obj->IsSharedFunctionInfo()) {
12426 continue;
12427 }
12428 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12429 if (shared->script() != script) {
12430 continue;
12431 }
12432 if (counter < buffer_size) {
12433 buffer->set(counter, shared);
12434 }
12435 counter++;
12436 }
12437 return counter;
12438}
12439
12440// For a script finds all SharedFunctionInfo's in the heap that points
12441// to this script. Returns JSArray of SharedFunctionInfo wrapped
12442// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012443RUNTIME_FUNCTION(MaybeObject*,
12444 Runtime_LiveEditFindSharedFunctionInfosForScript) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012445 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012446 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012448 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012449
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012450 RUNTIME_ASSERT(script_value->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012451 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12452
12453 const int kBufferSize = 32;
12454
12455 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012457 int number;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012458 Heap* heap = isolate->heap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012459 {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012460 heap->EnsureHeapIsIterable();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 AssertNoAllocation no_allocations;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012462 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012463 Script* scr = *script;
12464 FixedArray* arr = *array;
12465 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12466 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012467 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 array = isolate->factory()->NewFixedArray(number);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012469 heap->EnsureHeapIsIterable();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012470 AssertNoAllocation no_allocations;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012471 HeapIterator heap_iterator(heap);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012472 Script* scr = *script;
12473 FixedArray* arr = *array;
12474 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012475 }
12476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012477 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012478 result->set_length(Smi::FromInt(number));
12479
12480 LiveEdit::WrapSharedFunctionInfos(result);
12481
12482 return *result;
12483}
12484
12485// For a script calculates compilation information about all its functions.
12486// The script source is explicitly specified by the second argument.
12487// The source of the actual script is not used, however it is important that
12488// all generated code keeps references to this particular instance of script.
12489// Returns a JSArray of compilation infos. The array is ordered so that
12490// each function with all its descendant is always stored in a continues range
12491// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012492RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012493 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012494 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012496 CONVERT_ARG_CHECKED(JSValue, script, 0);
12497 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012498
12499 RUNTIME_ASSERT(script->value()->IsScript());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012500 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12501
12502 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012505 return Failure::Exception();
12506 }
12507
12508 return result;
12509}
12510
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012511// Changes the source of the script to a new_source.
12512// If old_script_name is provided (i.e. is a String), also creates a copy of
12513// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012514RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012515 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012516 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012517 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012518 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12519 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012520 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012521
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012522 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12523 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012524
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012525 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12526 new_source,
12527 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012528
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012529 if (old_script->IsScript()) {
12530 Handle<Script> script_handle(Script::cast(old_script));
12531 return *(GetScriptWrapper(script_handle));
12532 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012533 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012534 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012535}
12536
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012538RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012539 CHECK(isolate->debugger()->live_edit_enabled());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012540 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012541 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012542 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012543 return LiveEdit::FunctionSourceUpdated(shared_info);
12544}
12545
12546
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012547// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012548RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012549 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012550 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012551 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012552 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12553 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012554
ager@chromium.orgac091b72010-05-05 07:34:42 +000012555 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012556}
12557
12558// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012559RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012560 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012561 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 HandleScope scope(isolate);
12563 Handle<Object> function_object(args[0], isolate);
12564 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012565
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012566 if (function_object->IsJSValue()) {
12567 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12568 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012569 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12570 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012572 }
12573
12574 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12575 } else {
12576 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12577 // and we check it in this function.
12578 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012580 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012581}
12582
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012583
12584// In a code of a parent function replaces original function as embedded object
12585// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012586RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012587 CHECK(isolate->debugger()->live_edit_enabled());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012588 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012589 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012590
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012591 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12592 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12593 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012594
12595 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12596 subst_wrapper);
12597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012598 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012599}
12600
12601
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012602// Updates positions of a shared function info (first parameter) according
12603// to script source change. Text change is described in second parameter as
12604// array of groups of 3 numbers:
12605// (change_begin, change_end, change_end_new_position).
12606// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012607RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012608 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012609 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012611 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12612 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012613
ager@chromium.orgac091b72010-05-05 07:34:42 +000012614 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012615}
12616
12617
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012618// For array of SharedFunctionInfo's (each wrapped in JSValue)
12619// checks that none of them have activations on stacks (of any thread).
12620// Returns array of the same length with corresponding results of
12621// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012622RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012623 CHECK(isolate->debugger()->live_edit_enabled());
ager@chromium.org357bf652010-04-12 11:30:10 +000012624 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012625 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012626 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12627 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012628
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012629 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012630 isolate->runtime_zone());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012631}
12632
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012633// Compares 2 strings line-by-line, then token-wise and returns diff in form
12634// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12635// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012636RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012637 CHECK(isolate->debugger()->live_edit_enabled());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012638 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012639 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012640 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12641 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012642
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012643 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012644}
12645
12646
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012647// Restarts a call frame and completely drops all frames above.
12648// Returns true if successful. Otherwise returns undefined or an error message.
12649RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012650 CHECK(isolate->debugger()->live_edit_enabled());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012651 HandleScope scope(isolate);
12652 ASSERT(args.length() == 2);
12653
12654 // Check arguments.
12655 Object* check;
12656 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12657 RUNTIME_ARGUMENTS(isolate, args));
12658 if (!maybe_check->ToObject(&check)) return maybe_check;
12659 }
12660 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
12661 Heap* heap = isolate->heap();
12662
12663 // Find the relevant frame with the requested index.
12664 StackFrame::Id id = isolate->debug()->break_frame_id();
12665 if (id == StackFrame::NO_ID) {
12666 // If there are no JavaScript stack frames return undefined.
12667 return heap->undefined_value();
12668 }
12669
12670 int count = 0;
12671 JavaScriptFrameIterator it(isolate, id);
12672 for (; !it.done(); it.Advance()) {
12673 if (index < count + it.frame()->GetInlineCount()) break;
12674 count += it.frame()->GetInlineCount();
12675 }
12676 if (it.done()) return heap->undefined_value();
12677
12678 const char* error_message =
12679 LiveEdit::RestartFrame(it.frame(), isolate->runtime_zone());
12680 if (error_message) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012681 return *(isolate->factory()->InternalizeUtf8String(error_message));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000012682 }
12683 return heap->true_value();
12684}
12685
12686
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012687// A testing entry. Returns statement position which is the closest to
12688// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012689RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012690 CHECK(isolate->debugger()->live_edit_enabled());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012691 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012693 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012694 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012696 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012697
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012698 if (code->kind() != Code::FUNCTION &&
12699 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012700 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012701 }
12702
12703 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012704 int closest_pc = 0;
12705 int distance = kMaxInt;
12706 while (!it.done()) {
12707 int statement_position = static_cast<int>(it.rinfo()->data());
12708 // Check if this break point is closer that what was previously found.
12709 if (source_position <= statement_position &&
12710 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012711 closest_pc =
12712 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012713 distance = statement_position - source_position;
12714 // Check whether we can't get any closer.
12715 if (distance == 0) break;
12716 }
12717 it.next();
12718 }
12719
12720 return Smi::FromInt(closest_pc);
12721}
12722
12723
ager@chromium.org357bf652010-04-12 11:30:10 +000012724// Calls specified function with or without entering the debugger.
12725// This is used in unit tests to run code as if debugger is entered or simply
12726// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012727RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012728 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012729 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012730 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12731 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012732
12733 Handle<Object> result;
12734 bool pending_exception;
12735 {
12736 if (without_debugger) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012737 result = Execution::Call(function, isolate->global_object(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012738 &pending_exception);
12739 } else {
12740 EnterDebugger enter_debugger;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012741 result = Execution::Call(function, isolate->global_object(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012742 &pending_exception);
12743 }
12744 }
12745 if (!pending_exception) {
12746 return *result;
12747 } else {
12748 return Failure::Exception();
12749 }
12750}
12751
12752
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012753// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012754RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012755 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012756 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012757 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12758 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012759 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012760}
12761
12762
12763// Performs a GC.
12764// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012765RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012766 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012767 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012768}
12769
12770
12771// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012772RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012774 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012776 }
12777 return Smi::FromInt(usage);
12778}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012779
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012780#endif // ENABLE_DEBUGGER_SUPPORT
12781
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012784 NoHandleAllocation ha(isolate);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012785 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012786 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012787}
12788
12789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012790RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012791 NoHandleAllocation ha(isolate);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012792 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012793 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012794}
12795
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012797// Finds the script object from the script data. NOTE: This operation uses
12798// heap traversal to find the function generated for the source position
12799// for the requested break point. For lazily compiled functions several heap
12800// traversals might be required rendering this operation as a rather slow
12801// operation. However for setting break points which is normally done through
12802// some kind of user interaction the performance is not crucial.
12803static Handle<Object> Runtime_GetScriptFromScriptName(
12804 Handle<String> script_name) {
12805 // Scan the heap for Script objects to find the script with the requested
12806 // script data.
12807 Handle<Script> script;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012808 Heap* heap = script_name->GetHeap();
12809 heap->EnsureHeapIsIterable();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012810 AssertNoAllocation no_allocation_during_heap_iteration;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012811 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012812 HeapObject* obj = NULL;
12813 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012814 // If a script is found check if it has the script data requested.
12815 if (obj->IsScript()) {
12816 if (Script::cast(obj)->name()->IsString()) {
12817 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12818 script = Handle<Script>(Script::cast(obj));
12819 }
12820 }
12821 }
12822 }
12823
12824 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012826
12827 // Return the script found.
12828 return GetScriptWrapper(script);
12829}
12830
12831
12832// Get the script object from script data. NOTE: Regarding performance
12833// see the NOTE for GetScriptFromScriptData.
12834// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012835RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012837
12838 ASSERT(args.length() == 1);
12839
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012840 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012841
12842 // Find the requested script.
12843 Handle<Object> result =
12844 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12845 return *result;
12846}
12847
12848
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012849// Collect the raw data for a stack trace. Returns an array of 4
12850// element segments each containing a receiver, function, code and
12851// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012852RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012853 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012854 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012855 Handle<Object> caller = args.at<Object>(1);
12856 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 HandleScope scope(isolate);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000012859 // Optionally capture a more detailed stack trace for the message.
12860 isolate->CaptureAndSetDetailedStackTrace(error_object);
12861 // Capture a simple stack trace for the stack property.
12862 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit);
12863}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012864
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012865
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012866// Mark a function to recognize when called after GC to format the stack trace.
12867RUNTIME_FUNCTION(MaybeObject*, Runtime_MarkOneShotGetter) {
12868 ASSERT_EQ(args.length(), 1);
12869 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
12870 HandleScope scope(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012871 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012872 JSObject::SetHiddenProperty(fun, key, key);
12873 return *fun;
12874}
12875
12876
12877// Retrieve the stack trace. This could be the raw stack trace collected
12878// on stack overflow or the already formatted stack trace string.
12879RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOverflowedStackTrace) {
12880 HandleScope scope(isolate);
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000012881 ASSERT_EQ(args.length(), 1);
12882 CONVERT_ARG_CHECKED(JSObject, error_object, 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012883 String* key = isolate->heap()->hidden_stack_trace_string();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000012884 Object* result = error_object->GetHiddenProperty(key);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012885 RUNTIME_ASSERT(result->IsJSArray() ||
12886 result->IsString() ||
12887 result->IsUndefined());
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +000012888 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012889}
12890
12891
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012892// Set or clear the stack trace attached to an stack overflow error object.
12893RUNTIME_FUNCTION(MaybeObject*, Runtime_SetOverflowedStackTrace) {
12894 HandleScope scope(isolate);
12895 ASSERT_EQ(args.length(), 2);
12896 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
12897 CONVERT_ARG_HANDLE_CHECKED(HeapObject, value, 1);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012898 Handle<String> key = isolate->factory()->hidden_stack_trace_string();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012899 if (value->IsUndefined()) {
12900 error_object->DeleteHiddenProperty(*key);
12901 } else {
12902 RUNTIME_ASSERT(value->IsString());
12903 JSObject::SetHiddenProperty(error_object, key, value);
12904 }
12905 return *error_object;
12906}
12907
12908
ager@chromium.org3811b432009-10-28 14:53:37 +000012909// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012911 ASSERT_EQ(args.length(), 0);
12912
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012913 NoHandleAllocation ha(isolate);
ager@chromium.org3811b432009-10-28 14:53:37 +000012914
12915 const char* version_string = v8::V8::GetVersion();
12916
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012917 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012919}
12920
12921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012922RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012923 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012924 OS::PrintError("abort: %s\n",
12925 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012927 OS::Abort();
12928 UNREACHABLE();
12929 return NULL;
12930}
12931
12932
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012933RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) {
12934 HandleScope scope(isolate);
12935 ASSERT(args.length() == 1);
12936 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
12937 FlattenString(str);
12938 return isolate->heap()->undefined_value();
12939}
12940
12941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012942RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012943 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012944 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012945 Object* key = args[1];
12946
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012947 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012948 Object* o = cache->get(finger_index);
12949 if (o == key) {
12950 // The fastest case: hit the same place again.
12951 return cache->get(finger_index + 1);
12952 }
12953
12954 for (int i = finger_index - 2;
12955 i >= JSFunctionResultCache::kEntriesIndex;
12956 i -= 2) {
12957 o = cache->get(i);
12958 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012959 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012960 return cache->get(i + 1);
12961 }
12962 }
12963
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012964 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012965 ASSERT(size <= cache->length());
12966
12967 for (int i = size - 2; i > finger_index; i -= 2) {
12968 o = cache->get(i);
12969 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012970 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012971 return cache->get(i + 1);
12972 }
12973 }
12974
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012975 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012976 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012977
12978 Handle<JSFunctionResultCache> cache_handle(cache);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012979 Handle<Object> key_handle(key, isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012980 Handle<Object> value;
12981 {
12982 Handle<JSFunction> factory(JSFunction::cast(
12983 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12984 // TODO(antonm): consider passing a receiver when constructing a cache.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012985 Handle<Object> receiver(isolate->native_context()->global_object(),
12986 isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012987 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012988 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012989 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012990 value = Execution::Call(factory,
12991 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012992 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012993 argv,
12994 &pending_exception);
12995 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012996 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012997
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000012998#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012999 if (FLAG_verify_heap) {
13000 cache_handle->JSFunctionResultCacheVerify();
13001 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013002#endif
13003
13004 // Function invocation may have cleared the cache. Reread all the data.
13005 finger_index = cache_handle->finger_index();
13006 size = cache_handle->size();
13007
13008 // If we have spare room, put new data into it, otherwise evict post finger
13009 // entry which is likely to be the least recently used.
13010 int index = -1;
13011 if (size < cache_handle->length()) {
13012 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13013 index = size;
13014 } else {
13015 index = finger_index + JSFunctionResultCache::kEntrySize;
13016 if (index == cache_handle->length()) {
13017 index = JSFunctionResultCache::kEntriesIndex;
13018 }
13019 }
13020
13021 ASSERT(index % 2 == 0);
13022 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13023 ASSERT(index < cache_handle->length());
13024
13025 cache_handle->set(index, *key_handle);
13026 cache_handle->set(index + 1, *value);
13027 cache_handle->set_finger_index(index);
13028
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000013029#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013030 if (FLAG_verify_heap) {
13031 cache_handle->JSFunctionResultCacheVerify();
13032 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013033#endif
13034
13035 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013036}
13037
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013039RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013040 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013041 return Smi::FromInt(message->start_position());
13042}
13043
13044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013045RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013046 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013047 return message->script();
13048}
13049
13050
kasper.lund44510672008-07-25 07:37:58 +000013051#ifdef DEBUG
13052// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13053// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013054RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013055 ASSERT(args.length() == 0);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000013056 HandleScope scope(isolate);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013057#define COUNT_ENTRY(Name, argc, ressize) + 1
13058 int entry_count = 0
13059 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13060 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13061 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13062#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013063 Factory* factory = isolate->factory();
13064 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013065 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013066 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013067#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013068 { \
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000013069 HandleScope inner(isolate); \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013070 Handle<String> name; \
13071 /* Inline runtime functions have an underscore in front of the name. */ \
13072 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013073 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013074 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13075 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013076 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013077 Vector<const char>(#Name, StrLength(#Name))); \
13078 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013079 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013080 pair_elements->set(0, *name); \
13081 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013082 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013083 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013084 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013085 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013086 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013087 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013088 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013089 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013091 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013092 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013093 return *result;
13094}
kasper.lund44510672008-07-25 07:37:58 +000013095#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013096
13097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013098RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013099 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013100 CONVERT_ARG_CHECKED(String, format, 0);
13101 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013102 String::FlatContent format_content = format->GetFlatContent();
13103 RUNTIME_ASSERT(format_content.IsAscii());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013104 Vector<const uint8_t> chars = format_content.ToOneByteVector();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000013105 LOGGER->LogRuntime(isolate, Vector<const char>::cast(chars), elms);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013106 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013107}
13108
13109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013110RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013111 UNREACHABLE(); // implemented as macro in the parser
13112 return NULL;
13113}
13114
13115
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013116#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13117 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013118 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013119 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13120 }
13121
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013122ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements)
13123ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements)
13124ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013125ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013126ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013127ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13128ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13129ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13130ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13131ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13132ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13133ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13134ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13135ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13136ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13137ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013138// Properties test sitting with elements tests - not fooling anyone.
13139ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013140
13141#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13142
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013143
13144RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13145 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013146 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13147 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013148 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13149}
13150
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013151
13152RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) {
13153 ASSERT(args.length() == 1);
13154 CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000013155 if (obj->IsJSGlobalProxy()) {
13156 Object* proto = obj->GetPrototype();
13157 if (obj->IsNull()) return isolate->heap()->false_value();
13158 ASSERT(proto->IsJSGlobalObject());
13159 obj = JSReceiver::cast(proto);
13160 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013161 return isolate->heap()->ToBoolean(obj->map()->is_observed());
13162}
13163
13164
13165RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
13166 ASSERT(args.length() == 2);
13167 CONVERT_ARG_CHECKED(JSReceiver, obj, 0);
13168 CONVERT_BOOLEAN_ARG_CHECKED(is_observed, 1);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000013169 if (obj->IsJSGlobalProxy()) {
13170 Object* proto = obj->GetPrototype();
13171 if (obj->IsNull()) return isolate->heap()->undefined_value();
13172 ASSERT(proto->IsJSGlobalObject());
13173 obj = JSReceiver::cast(proto);
13174 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013175 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
13176 JSObject::cast(obj)->HasFastElements()));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013177 if (obj->map()->is_observed() != is_observed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013178 if (is_observed && obj->IsJSObject() &&
13179 !JSObject::cast(obj)->HasExternalArrayElements()) {
13180 // Go to dictionary mode, so that we don't skip map checks.
13181 MaybeObject* maybe = JSObject::cast(obj)->NormalizeElements();
13182 if (maybe->IsFailure()) return maybe;
13183 ASSERT(!JSObject::cast(obj)->HasFastElements());
13184 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013185 MaybeObject* maybe = obj->map()->Copy();
13186 Map* map;
13187 if (!maybe->To(&map)) return maybe;
13188 map->set_is_observed(is_observed);
13189 obj->set_map(map);
13190 }
13191 return isolate->heap()->undefined_value();
13192}
13193
13194
13195RUNTIME_FUNCTION(MaybeObject*, Runtime_SetObserverDeliveryPending) {
13196 ASSERT(args.length() == 0);
13197 isolate->set_observer_delivery_pending(true);
13198 return isolate->heap()->undefined_value();
13199}
13200
13201
13202RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) {
13203 ASSERT(args.length() == 0);
13204 return isolate->heap()->observation_state();
13205}
13206
13207
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000013208RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013209 HandleScope scope(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000013210 ASSERT(args.length() == 0);
13211 // TODO(adamk): Currently this runtime function is only called three times per
13212 // isolate. If it's called more often, the map should be moved into the
13213 // strong root list.
13214 Handle<Map> map =
13215 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
13216 Handle<JSWeakMap> weakmap =
13217 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map));
13218 return WeakMapInitialize(isolate, weakmap);
13219}
13220
13221
13222RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) {
13223 ASSERT(args.length() == 1);
13224 Object* object = args[0];
13225 if (object->IsJSGlobalProxy()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000013226 object = object->GetPrototype(isolate);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000013227 if (object->IsNull()) return isolate->heap()->undefined_value();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +000013228 }
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000013229 return object;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000013230}
13231
13232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013233// ----------------------------------------------------------------------------
13234// Implementation of Runtime
13235
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013236#define F(name, number_of_args, result_size) \
13237 { Runtime::k##name, Runtime::RUNTIME, #name, \
13238 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013239
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013240
13241#define I(name, number_of_args, result_size) \
13242 { Runtime::kInline##name, Runtime::INLINE, \
13243 "_" #name, NULL, number_of_args, result_size },
13244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013245static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013246 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013247 INLINE_FUNCTION_LIST(I)
13248 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013249};
13250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013252MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13253 Object* dictionary) {
13254 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013255 ASSERT(dictionary != NULL);
13256 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13257 for (int i = 0; i < kNumFunctions; ++i) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013258 Object* name_string;
13259 { MaybeObject* maybe_name_string =
13260 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name);
13261 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000013262 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013263 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013264 { MaybeObject* maybe_dictionary = string_dictionary->Add(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013265 String::cast(name_string),
lrn@chromium.org303ada72010-10-27 09:33:13 +000013266 Smi::FromInt(i),
13267 PropertyDetails(NONE, NORMAL));
13268 if (!maybe_dictionary->ToObject(&dictionary)) {
13269 // Non-recoverable failure. Calling code must restart heap
13270 // initialization.
13271 return maybe_dictionary;
13272 }
13273 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013274 }
13275 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013276}
13277
13278
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013279const Runtime::Function* Runtime::FunctionForName(Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013280 Heap* heap = name->GetHeap();
13281 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013282 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013283 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013284 int function_index = Smi::cast(smi_index)->value();
13285 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013286 }
13287 return NULL;
13288}
13289
13290
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013291const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013292 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13293}
13294
13295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013296void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013297 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013298 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013299 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013300 if (isolate->heap()->new_space()->AddFreshPage()) {
13301 return;
13302 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013303
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013304 // Try to do a garbage collection; ignore it if it fails. The C
13305 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013306 isolate->heap()->CollectGarbage(failure->allocation_space(),
13307 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013308 } else {
13309 // Handle last resort GC and make sure to allow future allocations
13310 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013311 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013312 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13313 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013315}
13316
13317
13318} } // namespace v8::internal