blob: b377e6e54ba78d882713223bec38e6be17fe28f8 [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000074 Type* name = Type::cast(args[index]);
75
76#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000083#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
84 RUNTIME_ASSERT(args[index]->IsBoolean()); \
85 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000109// Cast the given argument to PropertyDetails and store its value in a
110// variable with the given name. If the argument is not a Smi call
111// IllegalOperation and return.
112#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
113 RUNTIME_ASSERT(args[index]->IsSmi()); \
114 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
115
116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000117// Assert that the given argument has a valid value for a StrictModeFlag
118// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000119#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
120 RUNTIME_ASSERT(args[index]->IsSmi()); \
121 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
122 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 StrictModeFlag name = \
124 static_cast<StrictModeFlag>(args.smi_at(index));
125
126
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000127// Assert that the given argument has a valid value for a LanguageMode
128// and store it in a LanguageMode variable with the given name.
129#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
130 ASSERT(args[index]->IsSmi()); \
131 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
132 args.smi_at(index) == STRICT_MODE || \
133 args.smi_at(index) == EXTENDED_MODE); \
134 LanguageMode name = \
135 static_cast<LanguageMode>(args.smi_at(index));
136
137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
139 JSObject* boilerplate) {
140 StackLimitCheck check(isolate);
141 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 JSObject* copy = JSObject::cast(result);
149
150 // Deep copy local properties.
151 if (copy->HasFastProperties()) {
152 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 for (int i = 0; i < properties->length(); i++) {
154 Object* value = properties->get(i);
155 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 }
162 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000163 int nof = copy->map()->inobject_properties();
164 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 Object* value = copy->InObjectPropertyAt(i);
166 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000176 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 FixedArray* names = FixedArray::cast(result);
180 copy->GetLocalPropertyNames(names, 0);
181 for (int i = 0; i < names->length(); i++) {
182 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000183 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 // Only deep copy fields from the object literal expression.
187 // In particular, don't try to copy the length attribute of
188 // an array.
189 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190 Object* value =
191 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000192 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
197 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000198 // Creating object copy for literals. No strict mode needed.
199 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000200 if (!maybe_result->ToObject(&result)) return maybe_result;
201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
203 }
204 }
205
206 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000208 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000211 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 if (elements->map() == heap->fixed_cow_array_map()) {
214 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000215#ifdef DEBUG
216 for (int i = 0; i < elements->length(); i++) {
217 ASSERT(!elements->get(i)->IsJSObject());
218 }
219#endif
220 } else {
221 for (int i = 0; i < elements->length(); i++) {
222 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 ASSERT(value->IsSmi() ||
224 value->IsTheHole() ||
225 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000226 if (value->IsJSObject()) {
227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000232 elements->set(i, result);
233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234 }
235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 int capacity = element_dictionary->Capacity();
241 for (int i = 0; i < capacity; i++) {
242 Object* k = element_dictionary->KeyAt(i);
243 if (element_dictionary->IsKey(k)) {
244 Object* value = element_dictionary->ValueAt(i);
245 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
248 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000249 if (!maybe_result->ToObject(&result)) return maybe_result;
250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000251 element_dictionary->ValueAtPut(i, result);
252 }
253 }
254 }
255 break;
256 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000257 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000258 UNIMPLEMENTED();
259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000260 case EXTERNAL_PIXEL_ELEMENTS:
261 case EXTERNAL_BYTE_ELEMENTS:
262 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
263 case EXTERNAL_SHORT_ELEMENTS:
264 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
265 case EXTERNAL_INT_ELEMENTS:
266 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
267 case EXTERNAL_FLOAT_ELEMENTS:
268 case EXTERNAL_DOUBLE_ELEMENTS:
269 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000270 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000271 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 }
273 return copy;
274}
275
276
ager@chromium.org236ad962008-09-25 09:45:57 +0000277static Handle<Map> ComputeObjectLiteralMap(
278 Handle<Context> context,
279 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000282 int properties_length = constant_properties->length();
283 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000284 // Check that there are only symbols and array indices among keys.
285 int number_of_symbol_keys = 0;
286 for (int p = 0; p != properties_length; p += 2) {
287 Object* key = constant_properties->get(p);
288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 number_of_symbol_keys++;
291 } else if (key->ToArrayIndex(&element_index)) {
292 // An index key does not require space in the property backing store.
293 number_of_properties--;
294 } else {
295 // Bail out as a non-symbol non-index key makes caching impossible.
296 // ASSERT to make sure that the if condition after the loop is false.
297 ASSERT(number_of_symbol_keys != number_of_properties);
298 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000300 }
301 // If we only have symbols and array indices among keys then we can
302 // use the map cache in the global context.
303 const int kMaxKeys = 10;
304 if ((number_of_symbol_keys == number_of_properties) &&
305 (number_of_symbol_keys < kMaxKeys)) {
306 // Create the fixed array with the key.
307 Handle<FixedArray> keys =
308 isolate->factory()->NewFixedArray(number_of_symbol_keys);
309 if (number_of_symbol_keys > 0) {
310 int index = 0;
311 for (int p = 0; p < properties_length; p += 2) {
312 Object* key = constant_properties->get(p);
313 if (key->IsSymbol()) {
314 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000315 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000319 *is_result_from_cache = true;
320 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000322 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000324 Handle<Map>(context->object_function()->initial_map()),
325 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000326}
327
328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
332 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334
335static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000338 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 bool should_have_fast_elements,
340 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341 // Get the global context from the literals array. This is the
342 // context in which the function was created and we use the object
343 // function from this context to create the object literal. We do
344 // not use the object function from the current global context
345 // because this might be the object function from another context
346 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000347 Handle<Context> context =
348 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 // In case we have function literals, we want the object to be in
351 // slow properties mode for now. We don't go in the map cache because
352 // maps with constant functions can't be shared if the functions are
353 // not the same (which is the common case).
354 bool is_result_from_cache = false;
355 Handle<Map> map = has_function_literal
356 ? Handle<Map>(context->object_function()->initial_map())
357 : ComputeObjectLiteralMap(context,
358 constant_properties,
359 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000362
363 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000364 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Add the constant properties to the boilerplate.
367 int length = constant_properties->length();
368 bool should_transform =
369 !is_result_from_cache && boilerplate->HasFastProperties();
370 if (should_transform || has_function_literal) {
371 // Normalize the properties of object to avoid n^2 behavior
372 // when extending the object multiple properties. Indicate the number of
373 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000374 JSObject::NormalizeProperties(
375 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 }
377
378 for (int index = 0; index < length; index +=2) {
379 Handle<Object> key(constant_properties->get(index+0), isolate);
380 Handle<Object> value(constant_properties->get(index+1), isolate);
381 if (value->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object or array literal.
384 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
385 value = CreateLiteralBoilerplate(isolate, literals, array);
386 if (value.is_null()) return value;
387 }
388 Handle<Object> result;
389 uint32_t element_index = 0;
390 if (key->IsSymbol()) {
391 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
392 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000393 result = JSObject::SetOwnElement(
394 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<String> name(String::cast(*key));
397 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000398 result = JSObject::SetLocalPropertyIgnoreAttributes(
399 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 } else if (key->ToArrayIndex(&element_index)) {
402 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000403 result = JSObject::SetOwnElement(
404 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 } else {
406 // Non-uint32 number.
407 ASSERT(key->IsNumber());
408 double num = key->Number();
409 char arr[100];
410 Vector<char> buffer(arr, ARRAY_SIZE(arr));
411 const char* str = DoubleToCString(num, buffer);
412 Handle<String> name =
413 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000414 result = JSObject::SetLocalPropertyIgnoreAttributes(
415 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 // If setting the property on the boilerplate throws an
418 // exception, the exception is converted to an empty handle in
419 // the handle based operations. In that case, we need to
420 // convert back to an exception.
421 if (result.is_null()) return result;
422 }
423
424 // Transform to fast properties if necessary. For object literals with
425 // containing function literals we defer this operation until after all
426 // computed properties have been assigned so that we can generate
427 // constant function properties.
428 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000429 JSObject::TransformToFastProperties(
430 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000434}
435
436
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000437MaybeObject* TransitionElements(Handle<Object> object,
438 ElementsKind to_kind,
439 Isolate* isolate) {
440 HandleScope scope(isolate);
441 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
442 ElementsKind from_kind =
443 Handle<JSObject>::cast(object)->map()->elements_kind();
444 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
445 Handle<Object> result = JSObject::TransitionElementsKind(
446 Handle<JSObject>::cast(object), to_kind);
447 if (result.is_null()) return isolate->ThrowIllegalOperation();
448 return *result;
449 }
450 return isolate->ThrowIllegalOperation();
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454static const int kSmiOnlyLiteralMinimumLength = 1024;
455
456
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000457Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 Handle<FixedArray> literals,
460 Handle<FixedArray> elements) {
461 // Create the JSArray.
462 Handle<JSFunction> constructor(
463 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<JSArray> object =
465 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 ElementsKind constant_elements_kind =
468 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
469 Handle<FixedArrayBase> constant_elements_values(
470 FixedArrayBase::cast(elements->get(1)));
471
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000472 Context* global_context = isolate->context()->global_context();
473 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
474 object->set_map(Map::cast(global_context->smi_js_array_map()));
475 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 object->set_map(Map::cast(global_context->double_js_array_map()));
477 } else {
478 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 Handle<FixedArrayBase> copied_elements_values;
482 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
483 ASSERT(FLAG_smi_only_arrays);
484 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
485 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000487 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
488 constant_elements_kind == FAST_ELEMENTS);
489 const bool is_cow =
490 (constant_elements_values->map() ==
491 isolate->heap()->fixed_cow_array_map());
492 if (is_cow) {
493 copied_elements_values = constant_elements_values;
494#if DEBUG
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(copied_elements_values);
497 for (int i = 0; i < fixed_array_values->length(); i++) {
498 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
499 }
500#endif
501 } else {
502 Handle<FixedArray> fixed_array_values =
503 Handle<FixedArray>::cast(constant_elements_values);
504 Handle<FixedArray> fixed_array_values_copy =
505 isolate->factory()->CopyFixedArray(fixed_array_values);
506 copied_elements_values = fixed_array_values_copy;
507 for (int i = 0; i < fixed_array_values->length(); i++) {
508 Object* current = fixed_array_values->get(i);
509 if (current->IsFixedArray()) {
510 // The value contains the constant_properties of a
511 // simple object or array literal.
512 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
513 Handle<Object> result =
514 CreateLiteralBoilerplate(isolate, literals, fa);
515 if (result.is_null()) return result;
516 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000519 }
520 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 object->set_elements(*copied_elements_values);
522 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000523
524 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
525 // on or the object is larger than the threshold.
526 if (!FLAG_smi_only_arrays &&
527 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
528 if (object->GetElementsKind() != FAST_ELEMENTS) {
529 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
530 }
531 }
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 return object;
534}
535
536
537static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 Handle<FixedArray> literals,
540 Handle<FixedArray> array) {
541 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000543 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 true,
549 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000550 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 return CreateObjectLiteralBoilerplate(isolate,
552 literals,
553 elements,
554 false,
555 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000557 return Runtime::CreateArrayLiteralBoilerplate(
558 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 default:
560 UNREACHABLE();
561 return Handle<Object>::null();
562 }
563}
564
565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000566RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000568 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000571 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
574 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateObjectLiteralBoilerplate(isolate,
580 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 should_have_fast_elements,
583 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 if (boilerplate.is_null()) return Failure::Exception();
585 // Update the functions literal and return the boilerplate.
586 literals->set(literals_index, *boilerplate);
587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
600 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601
602 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<Object> boilerplate(literals->get(literals_index), isolate);
604 if (*boilerplate == isolate->heap()->undefined_value()) {
605 boilerplate = CreateObjectLiteralBoilerplate(isolate,
606 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 should_have_fast_elements,
609 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000621 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000623 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000640 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000641 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000642 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644
645 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 Handle<Object> boilerplate(literals->get(literals_index), isolate);
647 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000648 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000649 boilerplate =
650 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 if (boilerplate.is_null()) return Failure::Exception();
652 // Update the functions literal and return the boilerplate.
653 literals->set(literals_index, *boilerplate);
654 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000655 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000657 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660}
661
662
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
664 ASSERT(args.length() == 2);
665 Object* handler = args[0];
666 Object* prototype = args[1];
667 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
670}
671
672
lrn@chromium.org34e60782011-09-15 07:25:40 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
674 ASSERT(args.length() == 4);
675 Object* handler = args[0];
676 Object* call_trap = args[1];
677 Object* construct_trap = args[2];
678 Object* prototype = args[3];
679 Object* used_prototype =
680 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
681 return isolate->heap()->AllocateJSFunctionProxy(
682 handler, call_trap, construct_trap, used_prototype);
683}
684
685
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
687 ASSERT(args.length() == 1);
688 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690}
691
692
lrn@chromium.org34e60782011-09-15 07:25:40 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
694 ASSERT(args.length() == 1);
695 Object* obj = args[0];
696 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
697}
698
699
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
701 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000702 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 return proxy->handler();
704}
705
706
lrn@chromium.org34e60782011-09-15 07:25:40 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->call_trap();
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
715 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000716 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000717 return proxy->construct_trap();
718}
719
720
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
722 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000723 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000724 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000725 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000726}
727
728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
734 holder->set_table(*table);
735 return *holder;
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000742 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetAdd(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000754 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 Handle<Object> key(args[1]);
756 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
757 return isolate->heap()->ToBoolean(table->Contains(*key));
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 Handle<Object> key(args[1]);
766 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
767 table = ObjectHashSetRemove(table, key);
768 holder->set_table(*table);
769 return isolate->heap()->undefined_symbol();
770}
771
772
773RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
774 HandleScope scope(isolate);
775 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
778 holder->set_table(*table);
779 return *holder;
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000786 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 Handle<Object> key(args[1]);
788 return ObjectHashTable::cast(holder->table())->Lookup(*key);
789}
790
791
792RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
793 HandleScope scope(isolate);
794 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000795 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<Object> key(args[1]);
797 Handle<Object> value(args[2]);
798 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
799 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
800 holder->set_table(*new_table);
801 return *value;
802}
803
804
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000808 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 ASSERT(weakmap->map()->inobject_properties() == 0);
810 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
811 weakmap->set_table(*table);
812 weakmap->set_next(Smi::FromInt(0));
813 return *weakmap;
814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
818 NoHandleAllocation ha;
819 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000820 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
821 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823}
824
825
826RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
827 HandleScope scope(isolate);
828 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000829 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
830 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000831 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000832 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
834 weakmap->set_table(*new_table);
835 return *value;
836}
837
838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
842 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 return JSObject::cast(obj)->class_name();
845}
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
849 NoHandleAllocation ha;
850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000851 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 Object* obj = input_obj;
853 // We don't expect access checks to be needed on JSProxy objects.
854 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000856 if (obj->IsAccessCheckNeeded() &&
857 !isolate->MayNamedAccess(JSObject::cast(obj),
858 isolate->heap()->Proto_symbol(),
859 v8::ACCESS_GET)) {
860 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
861 return isolate->heap()->undefined_value();
862 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000863 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000864 } while (obj->IsJSObject() &&
865 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 return obj;
867}
868
869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000870RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 NoHandleAllocation ha;
872 ASSERT(args.length() == 2);
873 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
874 Object* O = args[0];
875 Object* V = args[1];
876 while (true) {
877 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (prototype->IsNull()) return isolate->heap()->false_value();
879 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 V = prototype;
881 }
882}
883
884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000885RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000887 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000888 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000889 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890}
891
892
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000893// Recursively traverses hidden prototypes if property is not found
894static void GetOwnPropertyImplementation(JSObject* obj,
895 String* name,
896 LookupResult* result) {
897 obj->LocalLookupRealNamedProperty(name, result);
898
899 if (!result->IsProperty()) {
900 Object* proto = obj->GetPrototype();
901 if (proto->IsJSObject() &&
902 JSObject::cast(proto)->map()->is_hidden_prototype())
903 GetOwnPropertyImplementation(JSObject::cast(proto),
904 name, result);
905 }
906}
907
908
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000909static bool CheckAccessException(LookupResult* result,
910 v8::AccessType access_type) {
911 if (result->type() == CALLBACKS) {
912 Object* callback = result->GetCallbackObject();
913 if (callback->IsAccessorInfo()) {
914 AccessorInfo* info = AccessorInfo::cast(callback);
915 bool can_access =
916 (access_type == v8::ACCESS_HAS &&
917 (info->all_can_read() || info->all_can_write())) ||
918 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
919 (access_type == v8::ACCESS_SET && info->all_can_write());
920 return can_access;
921 }
922 }
923
924 return false;
925}
926
927
928static bool CheckAccess(JSObject* obj,
929 String* name,
930 LookupResult* result,
931 v8::AccessType access_type) {
932 ASSERT(result->IsProperty());
933
934 JSObject* holder = result->holder();
935 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000936 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000937 while (true) {
938 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000940 // Access check callback denied the access, but some properties
941 // can have a special permissions which override callbacks descision
942 // (currently see v8::AccessControl).
943 break;
944 }
945
946 if (current == holder) {
947 return true;
948 }
949
950 current = JSObject::cast(current->GetPrototype());
951 }
952
953 // API callbacks can have per callback access exceptions.
954 switch (result->type()) {
955 case CALLBACKS: {
956 if (CheckAccessException(result, access_type)) {
957 return true;
958 }
959 break;
960 }
961 case INTERCEPTOR: {
962 // If the object has an interceptor, try real named properties.
963 // Overwrite the result to fetch the correct property later.
964 holder->LookupRealNamedProperty(name, result);
965 if (result->IsProperty()) {
966 if (CheckAccessException(result, access_type)) {
967 return true;
968 }
969 }
970 break;
971 }
972 default:
973 break;
974 }
975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 return false;
978}
979
980
981// TODO(1095): we should traverse hidden prototype hierachy as well.
982static bool CheckElementAccess(JSObject* obj,
983 uint32_t index,
984 v8::AccessType access_type) {
985 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000987 return false;
988 }
989
990 return true;
991}
992
993
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000994// Enumerator used as indices into the array returned from GetOwnProperty
995enum PropertyDescriptorIndices {
996 IS_ACCESSOR_INDEX,
997 VALUE_INDEX,
998 GETTER_INDEX,
999 SETTER_INDEX,
1000 WRITABLE_INDEX,
1001 ENUMERABLE_INDEX,
1002 CONFIGURABLE_INDEX,
1003 DESCRIPTOR_SIZE
1004};
1005
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001006// Returns an array with the property description:
1007// if args[1] is not a property on args[0]
1008// returns undefined
1009// if args[1] is a data property on args[0]
1010// [false, value, Writeable, Enumerable, Configurable]
1011// if args[1] is an accessor on args[0]
1012// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001013RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001014 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 Heap* heap = isolate->heap();
1016 HandleScope scope(isolate);
1017 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1018 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001019 LookupResult result(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001020 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1021 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001022
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001023 // This could be an element.
1024 uint32_t index;
1025 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001026 switch (obj->HasLocalElement(index)) {
1027 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001029
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001030 case JSObject::STRING_CHARACTER_ELEMENT: {
1031 // Special handling of string objects according to ECMAScript 5
1032 // 15.5.5.2. Note that this might be a string object with elements
1033 // other than the actual string value. This is covered by the
1034 // subsequent cases.
1035 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1036 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001037 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001042 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001044 return *desc;
1045 }
1046
1047 case JSObject::INTERCEPTED_ELEMENT:
1048 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001050 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001052 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053 elms->set(WRITABLE_INDEX, heap->true_value());
1054 elms->set(ENUMERABLE_INDEX, heap->true_value());
1055 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001056 return *desc;
1057 }
1058
1059 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001060 Handle<JSObject> holder = obj;
1061 if (obj->IsJSGlobalProxy()) {
1062 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001063 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 ASSERT(proto->IsJSGlobalObject());
1065 holder = Handle<JSObject>(JSObject::cast(proto));
1066 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001067 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001068 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001069 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001070 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001071 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001072 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001073 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001075 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 PropertyDetails details = dictionary->DetailsAt(entry);
1077 switch (details.type()) {
1078 case CALLBACKS: {
1079 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001080 AccessorPair* accessors =
1081 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001083 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001084 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001085 }
1086 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001087 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001088 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 break;
1090 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001095 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001098 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001099 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 default:
1101 UNREACHABLE();
1102 break;
1103 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1105 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001106 return *desc;
1107 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 }
1109 }
1110
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001111 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001112 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001113
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001114 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001115 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001116 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001117
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001118 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001120 }
1121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1123 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001124
1125 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001127
1128 if (is_js_accessor) {
1129 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001131
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001132 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001133 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001134 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001135 }
1136 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001137 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001138 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001139 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1141 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001142
1143 PropertyAttributes attrs;
1144 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001145 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001146 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1147 if (!maybe_value->ToObject(&value)) return maybe_value;
1148 }
1149 elms->set(VALUE_INDEX, value);
1150 }
1151
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001152 return *desc;
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // Safari does not allow the invocation of callback setters for
1341 // function declarations. To mimic this behavior, we do not allow
1342 // the invocation of setters for function values. This makes a
1343 // difference for global functions with the same names as event
1344 // handlers such as "function onload() {}". Firefox does call the
1345 // onload setter in those case and Safari does not. We follow
1346 // Safari for compatibility.
1347 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 // Do not change DONT_DELETE to false from true.
1349 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001350 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001351 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1357 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001359 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1360 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1361 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001362 RETURN_IF_EMPTY_HANDLE(
1363 isolate,
1364 JSReceiver::SetProperty(global, name, value,
1365 static_cast<PropertyAttributes>(attr),
1366 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 }
1368 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 ASSERT(!isolate->has_pending_exception());
1371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372}
1373
1374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001375RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // Declarations are always made in a function or global context. In the
1380 // case of eval code, the context passed is the context of the caller,
1381 // which may be some nested context and not the declaration context.
1382 RUNTIME_ASSERT(args[0]->IsContext());
1383 Handle<Context> context(Context::cast(args[0])->declaration_context());
1384
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001386 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001387 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 int index;
1391 PropertyAttributes attributes;
1392 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001393 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001394 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396
1397 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1400 // Functions are not read-only.
1401 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1402 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 }
1405
1406 // Initialize it if necessary.
1407 if (*initial_value != NULL) {
1408 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 ASSERT(holder.is_identical_to(context));
1410 if (((attributes & READ_ONLY) == 0) ||
1411 context->get(index)->IsTheHole()) {
1412 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 // Slow case: The property is in the context extension object of a
1416 // function context or the global object of a global context.
1417 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001418 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001420 JSReceiver::SetProperty(object, name, initial_value, mode,
1421 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001427 // "declared" in the function context's extension context or as a
1428 // property of the the global object.
1429 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001430 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001432 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433 // Context extension objects are allocated lazily.
1434 ASSERT(context->IsFunctionContext());
1435 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 // Declare the property by setting it to the initial value if provided,
1442 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1443 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001446 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001447 // Declaring a const context slot is a conflicting declaration if
1448 // there is a callback with that name in a prototype. It is
1449 // allowed to introduce const variables in
1450 // JSContextExtensionObjects. They are treated specially in
1451 // SetProperty and no setters are invoked for those since they are
1452 // not real JSObjects.
1453 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001457 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001459 }
1460 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001461 RETURN_IF_EMPTY_HANDLE(
1462 isolate,
1463 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001464 }
1465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467}
1468
1469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001470RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001473 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001474 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 // Determine if we need to assign to the variable if it already
1477 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1479 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001481 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001484 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1485 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1486 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // According to ECMA-262, section 12.2, page 62, the property must
1489 // not be deletable.
1490 PropertyAttributes attributes = DONT_DELETE;
1491
1492 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001493 // there, there is a property with this name in the prototype chain.
1494 // We follow Safari and Firefox behavior and only set the property
1495 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001496 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001497 // Note that objects can have hidden prototypes, so we need to traverse
1498 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001500 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (object->IsJSObject() &&
1502 JSObject::cast(object)->map()->is_hidden_prototype()) {
1503 JSObject* raw_holder = JSObject::cast(object);
1504 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001505 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 HandleScope handle_scope(isolate);
1507 Handle<JSObject> holder(raw_holder);
1508 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1509 // Update the raw pointer in case it's changed due to GC.
1510 raw_holder = *holder;
1511 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1512 // Found an interceptor that's not read only.
1513 if (assign) {
1514 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001515 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 } else {
1517 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001518 }
1519 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001520 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 }
1523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001526 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001527 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530}
1531
1532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001533RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // All constants are declared with an initial value. The name
1535 // of the constant is the first argument and the initial value
1536 // is the second.
1537 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001538 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 Handle<Object> value = args.at<Object>(1);
1540
1541 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
1544 // According to ECMA-262, section 12.2, page 62, the property must
1545 // not be deletable. Since it's a const, it must be READ_ONLY too.
1546 PropertyAttributes attributes =
1547 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1548
1549 // Lookup the property locally in the global object. If it isn't
1550 // there, we add the property and take special precautions to always
1551 // add it as a local property even in case of callbacks in the
1552 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001553 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001554 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 global->LocalLookup(*name, &lookup);
1556 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001557 return global->SetLocalPropertyIgnoreAttributes(*name,
1558 *value,
1559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 HandleScope handle_scope(isolate);
1566 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001568 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 // property through an interceptor and only do it if it's
1570 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001572 RETURN_IF_EMPTY_HANDLE(
1573 isolate,
1574 JSReceiver::SetProperty(global, name, value, attributes,
1575 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 return *value;
1577 }
1578
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // constant. For now, we determine this by checking if the
1581 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 PropertyType type = lookup.type();
1584 if (type == FIELD) {
1585 FixedArray* properties = global->properties();
1586 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 properties->set(index, *value);
1589 }
1590 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1592 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001593 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595 } else {
1596 // Ignore re-initialization of constants that have already been
1597 // assigned a function value.
1598 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1599 }
1600
1601 // Use the set value as the result of the operation.
1602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 ASSERT(args.length() == 3);
1609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001613 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 RUNTIME_ASSERT(args[1]->IsContext());
1615 Handle<Context> context(Context::cast(args[1])->declaration_context());
1616
1617 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 int index;
1620 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001622 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001623 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001624 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001627 ASSERT(holder->IsContext());
1628 // Property was found in a context. Perform the assignment if we
1629 // found some non-constant or an uninitialized constant.
1630 Handle<Context> context = Handle<Context>::cast(holder);
1631 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1632 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
1634 return *value;
1635 }
1636
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 // The property could not be found, we introduce it as a property of the
1638 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001639 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 Handle<JSObject> global = Handle<JSObject>(
1641 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
1643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001645 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 return *value;
1647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 // The property was present in some function's context extension object,
1650 // as a property on the subject of a with, or as a property of the global
1651 // object.
1652 //
1653 // In most situations, eval-introduced consts should still be present in
1654 // the context extension object. However, because declaration and
1655 // initialization are separate, the property might have been deleted
1656 // before we reach the initialization point.
1657 //
1658 // Example:
1659 //
1660 // function f() { eval("delete x; const x;"); }
1661 //
1662 // In that case, the initialization behaves like a normal assignment.
1663 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001665 if (*object == context->extension()) {
1666 // This is the property that was introduced by the const declaration.
1667 // Set it if it hasn't been set before. NOTE: We cannot use
1668 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001669 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001671 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1673
1674 PropertyType type = lookup.type();
1675 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001676 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 int index = lookup.GetFieldIndex();
1678 if (properties->get(index)->IsTheHole()) {
1679 properties->set(index, *value);
1680 }
1681 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001682 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1683 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001684 }
1685 } else {
1686 // We should not reach here. Any real, named property should be
1687 // either a field or a dictionary slot.
1688 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 }
1690 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 // The property was found on some other object. Set it if it is not a
1692 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001694 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001695 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001697 JSReceiver::SetProperty(object, name, value, attributes,
1698 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001710 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001713 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001722 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001727 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001779 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1780 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001797 // Both true and false are immovable immortal objects so no need for write
1798 // barrier.
1799 regexp->InObjectPropertyAtPut(
1800 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1806 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808 return regexp;
1809 }
1810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001812 PropertyAttributes final =
1813 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1814 PropertyAttributes writable =
1815 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 source,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 global,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 ignoreCase,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 multiline,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 Smi::FromInt(0),
1838 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841 return regexp;
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001848 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 // This is necessary to enable fast checks for absence of elements
1850 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 return Smi::FromInt(0);
1853}
1854
1855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1857 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001858 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001859 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1861 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1862 Handle<JSFunction> optimized =
1863 isolate->factory()->NewFunction(key,
1864 JS_OBJECT_TYPE,
1865 JSObject::kHeaderSize,
1866 code,
1867 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001869 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 return optimized;
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001877 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001879 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1880 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1881 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1882 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1883 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1884 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1885 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001886
1887 return *holder;
1888}
1889
1890
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001892 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001893 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001894
1895 if (!callable->IsJSFunction()) {
1896 HandleScope scope(isolate);
1897 bool threw = false;
1898 Handle<Object> delegate =
1899 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1900 if (threw) return Failure::Exception();
1901 callable = JSFunction::cast(*delegate);
1902 }
1903 JSFunction* function = JSFunction::cast(callable);
1904
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001906 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001907 return isolate->heap()->undefined_value();
1908 }
1909 // Returns undefined for strict or native functions, or
1910 // the associated global receiver for "normal" functions.
1911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001912 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001913 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001914 return global_context->global()->global_receiver();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001921 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001922 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 Handle<String> pattern = args.at<String>(2);
1924 Handle<String> flags = args.at<String>(3);
1925
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001926 // Get the RegExp function from the context in the literals array.
1927 // This is the RegExp function from the context in which the
1928 // function was created. We do not use the RegExp function from the
1929 // current global context because this might be the RegExp function
1930 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001931 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001932 Handle<JSFunction>(
1933 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 // Compute the regular expression literal.
1935 bool has_pending_exception;
1936 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1938 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 return Failure::Exception();
1942 }
1943 literals->set(index, *regexp);
1944 return *regexp;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001952 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 return f->shared()->name();
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 2);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1962 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001963 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001965}
1966
1967
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001971 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001972 return isolate->heap()->ToBoolean(
1973 f->shared()->name_should_print_as_anonymous());
1974}
1975
1976
1977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 f->shared()->set_name_should_print_as_anonymous(true);
1982 return isolate->heap()->undefined_value();
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001990 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 Object* obj = f->RemovePrototype();
1992 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 1);
2001
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002002 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2004 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005
2006 return *GetScriptWrapper(Handle<Script>::cast(script));
2007}
2008
2009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002010RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002011 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 ASSERT(args.length() == 1);
2013
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002014 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002015 Handle<SharedFunctionInfo> shared(f->shared());
2016 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 NoHandleAllocation ha;
2022 ASSERT(args.length() == 1);
2023
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002024 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 int pos = fun->shared()->start_position();
2026 return Smi::FromInt(pos);
2027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002031 ASSERT(args.length() == 2);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002034 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2035
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2037
2038 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002047 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2048 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 NoHandleAllocation ha;
2056 ASSERT(args.length() == 2);
2057
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002058 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2059 CONVERT_SMI_ARG_CHECKED(length, 1);
2060 fun->shared()->set_length(length);
2061 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_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002066 NoHandleAllocation ha;
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);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002070 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002071 Object* obj;
2072 { MaybeObject* maybe_obj =
2073 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2074 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 return args[0]; // return TOS
2077}
2078
2079
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2081 NoHandleAllocation ha;
2082 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002083 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002084
2085 MaybeObject* maybe_name =
2086 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2087 String* name;
2088 if (!maybe_name->To(&name)) return maybe_name;
2089
2090 if (function->HasFastProperties()) {
2091 // Construct a new field descriptor with updated attributes.
2092 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2093 int index = instance_desc->Search(name);
2094 ASSERT(index != DescriptorArray::kNotFound);
2095 PropertyDetails details(instance_desc->GetDetails(index));
2096 CallbacksDescriptor new_desc(name,
2097 instance_desc->GetValue(index),
2098 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2099 details.index());
2100 // Construct a new field descriptors array containing the new descriptor.
2101 Object* descriptors_unchecked;
2102 { MaybeObject* maybe_descriptors_unchecked =
2103 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2104 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2105 return maybe_descriptors_unchecked;
2106 }
2107 }
2108 DescriptorArray* new_descriptors =
2109 DescriptorArray::cast(descriptors_unchecked);
2110 // Create a new map featuring the new field descriptors array.
2111 Object* map_unchecked;
2112 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2113 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2114 return maybe_map_unchecked;
2115 }
2116 }
2117 Map* new_map = Map::cast(map_unchecked);
2118 new_map->set_instance_descriptors(new_descriptors);
2119 function->set_map(new_map);
2120 } else { // Dictionary properties.
2121 // Directly manipulate the property details.
2122 int entry = function->property_dictionary()->FindEntry(name);
2123 ASSERT(entry != StringDictionary::kNotFound);
2124 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2125 PropertyDetails new_details(
2126 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2127 details.type(),
2128 details.index());
2129 function->property_dictionary()->DetailsAtPut(entry, new_details);
2130 }
2131 return function;
2132}
2133
2134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002135RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002136 NoHandleAllocation ha;
2137 ASSERT(args.length() == 1);
2138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002139 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002140 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141}
2142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002150}
2151
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 ASSERT(args.length() == 2);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 Handle<Object> code = args.at<Object>(1);
2159
2160 Handle<Context> context(target->context());
2161
2162 if (!code->IsNull()) {
2163 RUNTIME_ASSERT(code->IsJSFunction());
2164 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002167 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 return Failure::Exception();
2169 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 // Since we don't store the source for this we should never
2171 // optimize this.
2172 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002173 // Set the code, scope info, formal parameter count,
2174 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002175 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002176 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002177 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002178 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002181 // Set the source code of the target function to undefined.
2182 // SetCode is only used for built-in constructors like String,
2183 // Array, and Object, and some web code
2184 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002186 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002187 // Clear the optimization hints related to the compiled code as these are no
2188 // longer valid when the code is overwritten.
2189 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 context = Handle<Context>(fun->context());
2191
2192 // Make sure we get a fresh copy of the literal vector to avoid
2193 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002194 int number_of_literals = fun->NumberOfLiterals();
2195 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002196 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002198 // Insert the object, regexp and array functions in the literals
2199 // array prefix. These are the functions that will be used when
2200 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002201 literals->set(JSFunction::kLiteralGlobalContextIndex,
2202 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002206
2207 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2208 isolate->logger()->LogExistingFunction(
2209 shared, Handle<Code>(shared->code()));
2210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 }
2212
2213 target->set_context(*context);
2214 return *target;
2215}
2216
2217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002218RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002221 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002222 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002223 RUNTIME_ASSERT(num >= 0);
2224 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002226}
2227
2228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2230 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002231 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002232 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 }
2236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002237 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002238}
2239
2240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002241RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242 NoHandleAllocation ha;
2243 ASSERT(args.length() == 2);
2244
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002245 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002246 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 uint32_t i = 0;
2250 if (index->IsSmi()) {
2251 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002252 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 i = value;
2254 } else {
2255 ASSERT(index->IsHeapNumber());
2256 double value = HeapNumber::cast(index)->value();
2257 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259
2260 // Flatten the string. If someone wants to get a char at an index
2261 // in a cons string, it is likely that more indices will be
2262 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002263 Object* flat;
2264 { MaybeObject* maybe_flat = subject->TryFlatten();
2265 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2266 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 subject = String::cast(flat);
2268
2269 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002271 }
2272
2273 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002274}
2275
2276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002277RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278 NoHandleAllocation ha;
2279 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281}
2282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283
2284class FixedArrayBuilder {
2285 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002286 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2287 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002288 length_(0),
2289 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 // Require a non-zero initial size. Ensures that doubling the size to
2291 // extend the array will work.
2292 ASSERT(initial_capacity > 0);
2293 }
2294
2295 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2296 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002330 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002331 }
2332
2333 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 ASSERT(length_ < capacity());
2336 array_->set(length_, value);
2337 length_++;
2338 }
2339
2340 Handle<FixedArray> array() {
2341 return array_;
2342 }
2343
2344 int length() {
2345 return length_;
2346 }
2347
2348 int capacity() {
2349 return array_->length();
2350 }
2351
2352 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002353 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354 result_array->set_length(Smi::FromInt(length_));
2355 return result_array;
2356 }
2357
2358 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 target_array->set_length(Smi::FromInt(length_));
2361 return target_array;
2362 }
2363
2364 private:
2365 Handle<FixedArray> array_;
2366 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002367 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368};
2369
2370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002372const int kStringBuilderConcatHelperLengthBits = 11;
2373const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375template <typename schar>
2376static inline void StringBuilderConcatHelper(String*,
2377 schar*,
2378 FixedArray*,
2379 int);
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2382 StringBuilderSubstringLength;
2383typedef BitField<int,
2384 kStringBuilderConcatHelperLengthBits,
2385 kStringBuilderConcatHelperPositionBits>
2386 StringBuilderSubstringPosition;
2387
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388
2389class ReplacementStringBuilder {
2390 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002391 ReplacementStringBuilder(Heap* heap,
2392 Handle<String> subject,
2393 int estimated_part_count)
2394 : heap_(heap),
2395 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002398 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 // Require a non-zero initial size. Ensures that doubling the size to
2400 // extend the array will work.
2401 ASSERT(estimated_part_count > 0);
2402 }
2403
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2405 int from,
2406 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 ASSERT(from >= 0);
2408 int length = to - from;
2409 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 if (StringBuilderSubstringLength::is_valid(length) &&
2411 StringBuilderSubstringPosition::is_valid(from)) {
2412 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2413 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002414 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002416 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002417 builder->Add(Smi::FromInt(-length));
2418 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 }
2421
2422
2423 void EnsureCapacity(int elements) {
2424 array_builder_.EnsureCapacity(elements);
2425 }
2426
2427
2428 void AddSubjectSlice(int from, int to) {
2429 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002430 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 }
2432
2433
2434 void AddString(Handle<String> string) {
2435 int length = string->length();
2436 ASSERT(length > 0);
2437 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002438 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 is_ascii_ = false;
2440 }
2441 IncrementCharacterCount(length);
2442 }
2443
2444
2445 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002447 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
2449
2450 Handle<String> joined_string;
2451 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002452 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002454 char* char_buffer = seq->GetChars();
2455 StringBuilderConcatHelper(*subject_,
2456 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 *array_builder_.array(),
2458 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 } else {
2461 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 uc16* char_buffer = seq->GetChars();
2465 StringBuilderConcatHelper(*subject_,
2466 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002467 *array_builder_.array(),
2468 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002469 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471 return joined_string;
2472 }
2473
2474
2475 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002476 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 V8::FatalProcessOutOfMemory("String.replace result too large.");
2478 }
2479 character_count_ += by;
2480 }
2481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002484 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002485
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002487 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2488 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 }
2490
2491
ager@chromium.org04921a82011-06-27 13:21:41 +00002492 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2493 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
2496
2497 void AddElement(Object* element) {
2498 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002499 ASSERT(array_builder_.capacity() > array_builder_.length());
2500 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 }
2502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 int character_count_;
2507 bool is_ascii_;
2508};
2509
2510
2511class CompiledReplacement {
2512 public:
2513 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002514 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515
2516 void Compile(Handle<String> replacement,
2517 int capture_count,
2518 int subject_length);
2519
2520 void Apply(ReplacementStringBuilder* builder,
2521 int match_from,
2522 int match_to,
2523 Handle<JSArray> last_match_info);
2524
2525 // Number of distinct parts of the replacement pattern.
2526 int parts() {
2527 return parts_.length();
2528 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002529
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002530 bool simple_hint() {
2531 return simple_hint_;
2532 }
2533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 private:
2535 enum PartType {
2536 SUBJECT_PREFIX = 1,
2537 SUBJECT_SUFFIX,
2538 SUBJECT_CAPTURE,
2539 REPLACEMENT_SUBSTRING,
2540 REPLACEMENT_STRING,
2541
2542 NUMBER_OF_PART_TYPES
2543 };
2544
2545 struct ReplacementPart {
2546 static inline ReplacementPart SubjectMatch() {
2547 return ReplacementPart(SUBJECT_CAPTURE, 0);
2548 }
2549 static inline ReplacementPart SubjectCapture(int capture_index) {
2550 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2551 }
2552 static inline ReplacementPart SubjectPrefix() {
2553 return ReplacementPart(SUBJECT_PREFIX, 0);
2554 }
2555 static inline ReplacementPart SubjectSuffix(int subject_length) {
2556 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2557 }
2558 static inline ReplacementPart ReplacementString() {
2559 return ReplacementPart(REPLACEMENT_STRING, 0);
2560 }
2561 static inline ReplacementPart ReplacementSubString(int from, int to) {
2562 ASSERT(from >= 0);
2563 ASSERT(to > from);
2564 return ReplacementPart(-from, to);
2565 }
2566
2567 // If tag <= 0 then it is the negation of a start index of a substring of
2568 // the replacement pattern, otherwise it's a value from PartType.
2569 ReplacementPart(int tag, int data)
2570 : tag(tag), data(data) {
2571 // Must be non-positive or a PartType value.
2572 ASSERT(tag < NUMBER_OF_PART_TYPES);
2573 }
2574 // Either a value of PartType or a non-positive number that is
2575 // the negation of an index into the replacement string.
2576 int tag;
2577 // The data value's interpretation depends on the value of tag:
2578 // tag == SUBJECT_PREFIX ||
2579 // tag == SUBJECT_SUFFIX: data is unused.
2580 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2581 // tag == REPLACEMENT_SUBSTRING ||
2582 // tag == REPLACEMENT_STRING: data is index into array of substrings
2583 // of the replacement string.
2584 // tag <= 0: Temporary representation of the substring of the replacement
2585 // string ranging over -tag .. data.
2586 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2587 // substring objects.
2588 int data;
2589 };
2590
2591 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002592 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 Vector<Char> characters,
2594 int capture_count,
2595 int subject_length) {
2596 int length = characters.length();
2597 int last = 0;
2598 for (int i = 0; i < length; i++) {
2599 Char c = characters[i];
2600 if (c == '$') {
2601 int next_index = i + 1;
2602 if (next_index == length) { // No next character!
2603 break;
2604 }
2605 Char c2 = characters[next_index];
2606 switch (c2) {
2607 case '$':
2608 if (i > last) {
2609 // There is a substring before. Include the first "$".
2610 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2611 last = next_index + 1; // Continue after the second "$".
2612 } else {
2613 // Let the next substring start with the second "$".
2614 last = next_index;
2615 }
2616 i = next_index;
2617 break;
2618 case '`':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectPrefix());
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '\'':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '&':
2635 if (i > last) {
2636 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2637 }
2638 parts->Add(ReplacementPart::SubjectMatch());
2639 i = next_index;
2640 last = i + 1;
2641 break;
2642 case '0':
2643 case '1':
2644 case '2':
2645 case '3':
2646 case '4':
2647 case '5':
2648 case '6':
2649 case '7':
2650 case '8':
2651 case '9': {
2652 int capture_ref = c2 - '0';
2653 if (capture_ref > capture_count) {
2654 i = next_index;
2655 continue;
2656 }
2657 int second_digit_index = next_index + 1;
2658 if (second_digit_index < length) {
2659 // Peek ahead to see if we have two digits.
2660 Char c3 = characters[second_digit_index];
2661 if ('0' <= c3 && c3 <= '9') { // Double digits.
2662 int double_digit_ref = capture_ref * 10 + c3 - '0';
2663 if (double_digit_ref <= capture_count) {
2664 next_index = second_digit_index;
2665 capture_ref = double_digit_ref;
2666 }
2667 }
2668 }
2669 if (capture_ref > 0) {
2670 if (i > last) {
2671 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2672 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002673 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2675 last = next_index + 1;
2676 }
2677 i = next_index;
2678 break;
2679 }
2680 default:
2681 i = next_index;
2682 break;
2683 }
2684 }
2685 }
2686 if (length > last) {
2687 if (last == 0) {
2688 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002689 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002690 } else {
2691 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2692 }
2693 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002694 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 }
2696
2697 ZoneList<ReplacementPart> parts_;
2698 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002699 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700};
2701
2702
2703void CompiledReplacement::Compile(Handle<String> replacement,
2704 int capture_count,
2705 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002706 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 String::FlatContent content = replacement->GetFlatContent();
2709 ASSERT(content.IsFlat());
2710 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002711 simple_hint_ = ParseReplacementPattern(&parts_,
2712 content.ToAsciiVector(),
2713 capture_count,
2714 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 } else {
2716 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002717 simple_hint_ = ParseReplacementPattern(&parts_,
2718 content.ToUC16Vector(),
2719 capture_count,
2720 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002721 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002724 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int substring_index = 0;
2726 for (int i = 0, n = parts_.length(); i < n; i++) {
2727 int tag = parts_[i].tag;
2728 if (tag <= 0) { // A replacement string slice.
2729 int from = -tag;
2730 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 replacement_substrings_.Add(
2732 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002733 parts_[i].tag = REPLACEMENT_SUBSTRING;
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 } else if (tag == REPLACEMENT_STRING) {
2737 replacement_substrings_.Add(replacement);
2738 parts_[i].data = substring_index;
2739 substring_index++;
2740 }
2741 }
2742}
2743
2744
2745void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2746 int match_from,
2747 int match_to,
2748 Handle<JSArray> last_match_info) {
2749 for (int i = 0, n = parts_.length(); i < n; i++) {
2750 ReplacementPart part = parts_[i];
2751 switch (part.tag) {
2752 case SUBJECT_PREFIX:
2753 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2754 break;
2755 case SUBJECT_SUFFIX: {
2756 int subject_length = part.data;
2757 if (match_to < subject_length) {
2758 builder->AddSubjectSlice(match_to, subject_length);
2759 }
2760 break;
2761 }
2762 case SUBJECT_CAPTURE: {
2763 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002764 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2766 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2767 if (from >= 0 && to > from) {
2768 builder->AddSubjectSlice(from, to);
2769 }
2770 break;
2771 }
2772 case REPLACEMENT_SUBSTRING:
2773 case REPLACEMENT_STRING:
2774 builder->AddString(replacement_substrings_[part.data]);
2775 break;
2776 default:
2777 UNREACHABLE();
2778 }
2779 }
2780}
2781
2782
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002783void FindAsciiStringIndices(Vector<const char> subject,
2784 char pattern,
2785 ZoneList<int>* indices,
2786 unsigned int limit) {
2787 ASSERT(limit > 0);
2788 // Collect indices of pattern in subject using memchr.
2789 // Stop after finding at most limit values.
2790 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2791 const char* subject_end = subject_start + subject.length();
2792 const char* pos = subject_start;
2793 while (limit > 0) {
2794 pos = reinterpret_cast<const char*>(
2795 memchr(pos, pattern, subject_end - pos));
2796 if (pos == NULL) return;
2797 indices->Add(static_cast<int>(pos - subject_start));
2798 pos++;
2799 limit--;
2800 }
2801}
2802
2803
2804template <typename SubjectChar, typename PatternChar>
2805void FindStringIndices(Isolate* isolate,
2806 Vector<const SubjectChar> subject,
2807 Vector<const PatternChar> pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 ASSERT(limit > 0);
2811 // Collect indices of pattern in subject.
2812 // Stop after finding at most limit values.
2813 int pattern_length = pattern.length();
2814 int index = 0;
2815 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2816 while (limit > 0) {
2817 index = search.Search(subject, index);
2818 if (index < 0) return;
2819 indices->Add(index);
2820 index += pattern_length;
2821 limit--;
2822 }
2823}
2824
2825
2826void FindStringIndicesDispatch(Isolate* isolate,
2827 String* subject,
2828 String* pattern,
2829 ZoneList<int>* indices,
2830 unsigned int limit) {
2831 {
2832 AssertNoAllocation no_gc;
2833 String::FlatContent subject_content = subject->GetFlatContent();
2834 String::FlatContent pattern_content = pattern->GetFlatContent();
2835 ASSERT(subject_content.IsFlat());
2836 ASSERT(pattern_content.IsFlat());
2837 if (subject_content.IsAscii()) {
2838 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2839 if (pattern_content.IsAscii()) {
2840 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2841 if (pattern_vector.length() == 1) {
2842 FindAsciiStringIndices(subject_vector,
2843 pattern_vector[0],
2844 indices,
2845 limit);
2846 } else {
2847 FindStringIndices(isolate,
2848 subject_vector,
2849 pattern_vector,
2850 indices,
2851 limit);
2852 }
2853 } else {
2854 FindStringIndices(isolate,
2855 subject_vector,
2856 pattern_content.ToUC16Vector(),
2857 indices,
2858 limit);
2859 }
2860 } else {
2861 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002862 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToAsciiVector(),
2866 indices,
2867 limit);
2868 } else {
2869 FindStringIndices(isolate,
2870 subject_vector,
2871 pattern_content.ToUC16Vector(),
2872 indices,
2873 limit);
2874 }
2875 }
2876 }
2877}
2878
2879
2880template<typename ResultSeqString>
2881MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2882 Isolate* isolate,
2883 Handle<String> subject,
2884 Handle<JSRegExp> pattern_regexp,
2885 Handle<String> replacement) {
2886 ASSERT(subject->IsFlat());
2887 ASSERT(replacement->IsFlat());
2888
2889 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2890 ZoneList<int> indices(8);
2891 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2892 String* pattern =
2893 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2894 int subject_len = subject->length();
2895 int pattern_len = pattern->length();
2896 int replacement_len = replacement->length();
2897
2898 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2899
2900 int matches = indices.length();
2901 if (matches == 0) return *subject;
2902
2903 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2904 int subject_pos = 0;
2905 int result_pos = 0;
2906
2907 Handle<ResultSeqString> result;
2908 if (ResultSeqString::kHasAsciiEncoding) {
2909 result = Handle<ResultSeqString>::cast(
2910 isolate->factory()->NewRawAsciiString(result_len));
2911 } else {
2912 result = Handle<ResultSeqString>::cast(
2913 isolate->factory()->NewRawTwoByteString(result_len));
2914 }
2915
2916 for (int i = 0; i < matches; i++) {
2917 // Copy non-matched subject content.
2918 if (subject_pos < indices.at(i)) {
2919 String::WriteToFlat(*subject,
2920 result->GetChars() + result_pos,
2921 subject_pos,
2922 indices.at(i));
2923 result_pos += indices.at(i) - subject_pos;
2924 }
2925
2926 // Replace match.
2927 if (replacement_len > 0) {
2928 String::WriteToFlat(*replacement,
2929 result->GetChars() + result_pos,
2930 0,
2931 replacement_len);
2932 result_pos += replacement_len;
2933 }
2934
2935 subject_pos = indices.at(i) + pattern_len;
2936 }
2937 // Add remaining subject content at the end.
2938 if (subject_pos < subject_len) {
2939 String::WriteToFlat(*subject,
2940 result->GetChars() + result_pos,
2941 subject_pos,
2942 subject_len);
2943 }
2944 return *result;
2945}
2946
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947
lrn@chromium.org303ada72010-10-27 09:33:13 +00002948MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002950 String* subject,
2951 JSRegExp* regexp,
2952 String* replacement,
2953 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 ASSERT(subject->IsFlat());
2955 ASSERT(replacement->IsFlat());
2956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958
2959 int length = subject->length();
2960 Handle<String> subject_handle(subject);
2961 Handle<JSRegExp> regexp_handle(regexp);
2962 Handle<String> replacement_handle(replacement);
2963 Handle<JSArray> last_match_info_handle(last_match_info);
2964 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2965 subject_handle,
2966 0,
2967 last_match_info_handle);
2968 if (match.is_null()) {
2969 return Failure::Exception();
2970 }
2971 if (match->IsNull()) {
2972 return *subject_handle;
2973 }
2974
2975 int capture_count = regexp_handle->CaptureCount();
2976
2977 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002978 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 CompiledReplacement compiled_replacement;
2980 compiled_replacement.Compile(replacement_handle,
2981 capture_count,
2982 length);
2983
2984 bool is_global = regexp_handle->GetFlags().is_global();
2985
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002986 // Shortcut for simple non-regexp global replacements
2987 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002988 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002989 compiled_replacement.simple_hint()) {
2990 if (subject_handle->HasOnlyAsciiChars() &&
2991 replacement_handle->HasOnlyAsciiChars()) {
2992 return StringReplaceStringWithString<SeqAsciiString>(
2993 isolate, subject_handle, regexp_handle, replacement_handle);
2994 } else {
2995 return StringReplaceStringWithString<SeqTwoByteString>(
2996 isolate, subject_handle, regexp_handle, replacement_handle);
2997 }
2998 }
2999
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000 // Guessing the number of parts that the final result string is built
3001 // from. Global regexps can match any number of times, so we guess
3002 // conservatively.
3003 int expected_parts =
3004 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 ReplacementStringBuilder builder(isolate->heap(),
3006 subject_handle,
3007 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 // Index of end of last match.
3010 int prev = 0;
3011
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003012 // Number of parts added by compiled replacement plus preceeding
3013 // string and possibly suffix after last match. It is possible for
3014 // all components to use two elements when encoded as two smis.
3015 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 bool matched = true;
3017 do {
3018 ASSERT(last_match_info_handle->HasFastElements());
3019 // Increase the capacity of the builder before entering local handle-scope,
3020 // so its internal buffer can safely allocate a new handle if it grows.
3021 builder.EnsureCapacity(parts_added_per_loop);
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003024 int start, end;
3025 {
3026 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003027 FixedArray* match_info_array =
3028 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029
3030 ASSERT_EQ(capture_count * 2 + 2,
3031 RegExpImpl::GetLastCaptureCount(match_info_array));
3032 start = RegExpImpl::GetCapture(match_info_array, 0);
3033 end = RegExpImpl::GetCapture(match_info_array, 1);
3034 }
3035
3036 if (prev < start) {
3037 builder.AddSubjectSlice(prev, start);
3038 }
3039 compiled_replacement.Apply(&builder,
3040 start,
3041 end,
3042 last_match_info_handle);
3043 prev = end;
3044
3045 // Only continue checking for global regexps.
3046 if (!is_global) break;
3047
3048 // Continue from where the match ended, unless it was an empty match.
3049 int next = end;
3050 if (start == end) {
3051 next = end + 1;
3052 if (next > length) break;
3053 }
3054
3055 match = RegExpImpl::Exec(regexp_handle,
3056 subject_handle,
3057 next,
3058 last_match_info_handle);
3059 if (match.is_null()) {
3060 return Failure::Exception();
3061 }
3062 matched = !match->IsNull();
3063 } while (matched);
3064
3065 if (prev < length) {
3066 builder.AddSubjectSlice(prev, length);
3067 }
3068
3069 return *(builder.ToString());
3070}
3071
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003074MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003075 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003076 String* subject,
3077 JSRegExp* regexp,
3078 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003079 ASSERT(subject->IsFlat());
3080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082
3083 Handle<String> subject_handle(subject);
3084 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003085
3086 // Shortcut for simple non-regexp global replacements
3087 if (regexp_handle->GetFlags().is_global() &&
3088 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3089 Handle<String> empty_string_handle(HEAP->empty_string());
3090 if (subject_handle->HasOnlyAsciiChars()) {
3091 return StringReplaceStringWithString<SeqAsciiString>(
3092 isolate, subject_handle, regexp_handle, empty_string_handle);
3093 } else {
3094 return StringReplaceStringWithString<SeqTwoByteString>(
3095 isolate, subject_handle, regexp_handle, empty_string_handle);
3096 }
3097 }
3098
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 Handle<JSArray> last_match_info_handle(last_match_info);
3100 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3101 subject_handle,
3102 0,
3103 last_match_info_handle);
3104 if (match.is_null()) return Failure::Exception();
3105 if (match->IsNull()) return *subject_handle;
3106
3107 ASSERT(last_match_info_handle->HasFastElements());
3108
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 int start, end;
3110 {
3111 AssertNoAllocation match_info_array_is_not_in_a_handle;
3112 FixedArray* match_info_array =
3113 FixedArray::cast(last_match_info_handle->elements());
3114
3115 start = RegExpImpl::GetCapture(match_info_array, 0);
3116 end = RegExpImpl::GetCapture(match_info_array, 1);
3117 }
3118
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003119 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 int new_length = length - (end - start);
3121 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124 Handle<ResultSeqString> answer;
3125 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003126 answer = Handle<ResultSeqString>::cast(
3127 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003129 answer = Handle<ResultSeqString>::cast(
3130 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003131 }
3132
3133 // If the regexp isn't global, only match once.
3134 if (!regexp_handle->GetFlags().is_global()) {
3135 if (start > 0) {
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars(),
3138 0,
3139 start);
3140 }
3141 if (end < length) {
3142 String::WriteToFlat(*subject_handle,
3143 answer->GetChars() + start,
3144 end,
3145 length);
3146 }
3147 return *answer;
3148 }
3149
3150 int prev = 0; // Index of end of last match.
3151 int next = 0; // Start of next search (prev unless last match was empty).
3152 int position = 0;
3153
3154 do {
3155 if (prev < start) {
3156 // Add substring subject[prev;start] to answer string.
3157 String::WriteToFlat(*subject_handle,
3158 answer->GetChars() + position,
3159 prev,
3160 start);
3161 position += start - prev;
3162 }
3163 prev = end;
3164 next = end;
3165 // Continue from where the match ended, unless it was an empty match.
3166 if (start == end) {
3167 next++;
3168 if (next > length) break;
3169 }
3170 match = RegExpImpl::Exec(regexp_handle,
3171 subject_handle,
3172 next,
3173 last_match_info_handle);
3174 if (match.is_null()) return Failure::Exception();
3175 if (match->IsNull()) break;
3176
3177 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003178 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003179 {
3180 AssertNoAllocation match_info_array_is_not_in_a_handle;
3181 FixedArray* match_info_array =
3182 FixedArray::cast(last_match_info_handle->elements());
3183 start = RegExpImpl::GetCapture(match_info_array, 0);
3184 end = RegExpImpl::GetCapture(match_info_array, 1);
3185 }
3186 } while (true);
3187
3188 if (prev < length) {
3189 // Add substring subject[prev;length] to answer string.
3190 String::WriteToFlat(*subject_handle,
3191 answer->GetChars() + position,
3192 prev,
3193 length);
3194 position += length - prev;
3195 }
3196
3197 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003198 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003199 }
3200
3201 // Shorten string and fill
3202 int string_size = ResultSeqString::SizeFor(position);
3203 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3204 int delta = allocated_string_size - string_size;
3205
3206 answer->set_length(position);
3207 if (delta == 0) return *answer;
3208
3209 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003211 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003212 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003213 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003214
3215 return *answer;
3216}
3217
3218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003220 ASSERT(args.length() == 4);
3221
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003222 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003223 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224 Object* flat_subject;
3225 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3226 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3227 return maybe_flat_subject;
3228 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 }
3230 subject = String::cast(flat_subject);
3231 }
3232
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003233 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235 Object* flat_replacement;
3236 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3237 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3238 return maybe_flat_replacement;
3239 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 }
3241 replacement = String::cast(flat_replacement);
3242 }
3243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003244 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3245 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003246
3247 ASSERT(last_match_info->HasFastElements());
3248
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 if (replacement->length() == 0) {
3250 if (subject->HasOnlyAsciiChars()) {
3251 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003253 } else {
3254 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003256 }
3257 }
3258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003259 return StringReplaceRegExpWithString(isolate,
3260 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261 regexp,
3262 replacement,
3263 last_match_info);
3264}
3265
3266
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003267Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3268 Handle<String> subject,
3269 Handle<String> search,
3270 Handle<String> replace,
3271 bool* found,
3272 int recursion_limit) {
3273 if (recursion_limit == 0) return Handle<String>::null();
3274 if (subject->IsConsString()) {
3275 ConsString* cons = ConsString::cast(*subject);
3276 Handle<String> first = Handle<String>(cons->first());
3277 Handle<String> second = Handle<String>(cons->second());
3278 Handle<String> new_first =
3279 StringReplaceOneCharWithString(isolate,
3280 first,
3281 search,
3282 replace,
3283 found,
3284 recursion_limit - 1);
3285 if (*found) return isolate->factory()->NewConsString(new_first, second);
3286 if (new_first.is_null()) return new_first;
3287
3288 Handle<String> new_second =
3289 StringReplaceOneCharWithString(isolate,
3290 second,
3291 search,
3292 replace,
3293 found,
3294 recursion_limit - 1);
3295 if (*found) return isolate->factory()->NewConsString(first, new_second);
3296 if (new_second.is_null()) return new_second;
3297
3298 return subject;
3299 } else {
3300 int index = StringMatch(isolate, subject, search, 0);
3301 if (index == -1) return subject;
3302 *found = true;
3303 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3304 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3305 Handle<String> second =
3306 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3307 return isolate->factory()->NewConsString(cons1, second);
3308 }
3309}
3310
3311
3312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3313 ASSERT(args.length() == 3);
3314 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003315 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3316 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3317 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003318
3319 // If the cons string tree is too deep, we simply abort the recursion and
3320 // retry with a flattened subject string.
3321 const int kRecursionLimit = 0x1000;
3322 bool found = false;
3323 Handle<String> result =
3324 Runtime::StringReplaceOneCharWithString(isolate,
3325 subject,
3326 search,
3327 replace,
3328 &found,
3329 kRecursionLimit);
3330 if (!result.is_null()) return *result;
3331 return *Runtime::StringReplaceOneCharWithString(isolate,
3332 FlattenGetString(subject),
3333 search,
3334 replace,
3335 &found,
3336 kRecursionLimit);
3337}
3338
3339
ager@chromium.org7c537e22008-10-16 08:43:32 +00003340// Perform string match of pattern on subject, starting at start index.
3341// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003342// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343int Runtime::StringMatch(Isolate* isolate,
3344 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345 Handle<String> pat,
3346 int start_index) {
3347 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003348 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003350 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003351 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 if (start_index + pattern_length > subject_length) return -1;
3355
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003356 if (!sub->IsFlat()) FlattenString(sub);
3357 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003358
ager@chromium.org7c537e22008-10-16 08:43:32 +00003359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003360 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 String::FlatContent seq_sub = sub->GetFlatContent();
3362 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003363
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 if (seq_pat.IsAscii()) {
3366 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3367 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003369 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 pat_vector,
3371 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003372 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003377 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3379 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003381 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 pat_vector,
3383 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003386 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 pat_vector,
3388 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003389}
3390
3391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003392RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394 ASSERT(args.length() == 3);
3395
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003396 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3397 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003399 Object* index = args[2];
3400 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003401 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003402
ager@chromium.org870a0b62008-11-04 11:43:05 +00003403 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 int position =
3405 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003406 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407}
3408
3409
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411static int StringMatchBackwards(Vector<const schar> subject,
3412 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003414 int pattern_length = pattern.length();
3415 ASSERT(pattern_length >= 1);
3416 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417
3418 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 for (int i = 0; i < pattern_length; i++) {
3420 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421 if (c > String::kMaxAsciiCharCode) {
3422 return -1;
3423 }
3424 }
3425 }
3426
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003427 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003428 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 while (j < pattern_length) {
3432 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003433 break;
3434 }
3435 j++;
3436 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003437 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003438 return i;
3439 }
3440 }
3441 return -1;
3442}
3443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003445 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 ASSERT(args.length() == 3);
3447
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003448 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3449 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003453 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003456 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 if (start_index + pat_length > sub_length) {
3459 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 if (pat_length == 0) {
3463 return Smi::FromInt(start_index);
3464 }
3465
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003466 if (!sub->IsFlat()) FlattenString(sub);
3467 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003468
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003469 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3471
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 String::FlatContent sub_content = sub->GetFlatContent();
3473 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003474
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003475 if (pat_content.IsAscii()) {
3476 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3477 if (sub_content.IsAscii()) {
3478 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 pat_vector,
3480 start_index);
3481 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003482 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483 pat_vector,
3484 start_index);
3485 }
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3488 if (sub_content.IsAscii()) {
3489 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003490 pat_vector,
3491 start_index);
3492 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003493 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003494 pat_vector,
3495 start_index);
3496 }
3497 }
3498
3499 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500}
3501
3502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003503RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504 NoHandleAllocation ha;
3505 ASSERT(args.length() == 2);
3506
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003507 CONVERT_ARG_CHECKED(String, str1, 0);
3508 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509
3510 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003511 int str1_length = str1->length();
3512 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513
3514 // Decide trivial cases without flattening.
3515 if (str1_length == 0) {
3516 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3517 return Smi::FromInt(-str2_length);
3518 } else {
3519 if (str2_length == 0) return Smi::FromInt(str1_length);
3520 }
3521
3522 int end = str1_length < str2_length ? str1_length : str2_length;
3523
3524 // No need to flatten if we are going to find the answer on the first
3525 // character. At this point we know there is at least one character
3526 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003527 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 if (d != 0) return Smi::FromInt(d);
3529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003530 str1->TryFlatten();
3531 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 StringInputBuffer& buf1 =
3534 *isolate->runtime_state()->string_locale_compare_buf1();
3535 StringInputBuffer& buf2 =
3536 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 buf1.Reset(str1);
3539 buf2.Reset(str2);
3540
3541 for (int i = 0; i < end; i++) {
3542 uint16_t char1 = buf1.GetNext();
3543 uint16_t char2 = buf2.GetNext();
3544 if (char1 != char2) return Smi::FromInt(char1 - char2);
3545 }
3546
3547 return Smi::FromInt(str1_length - str2_length);
3548}
3549
3550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003551RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 NoHandleAllocation ha;
3553 ASSERT(args.length() == 3);
3554
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003555 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 int start, end;
3557 // We have a fast integer-only case here to avoid a conversion to double in
3558 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3560 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3561 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3562 start = from_number;
3563 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003564 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003565 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3566 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003567 start = FastD2I(from_number);
3568 end = FastD2I(to_number);
3569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 RUNTIME_ASSERT(end >= start);
3571 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003572 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003574 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575}
3576
3577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 ASSERT_EQ(3, args.length());
3580
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003581 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3582 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3583 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 HandleScope handles;
3585
3586 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3587
3588 if (match.is_null()) {
3589 return Failure::Exception();
3590 }
3591 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 }
3594 int length = subject->length();
3595
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003596 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003598 int start;
3599 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003601 {
3602 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003603 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003604 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3605 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3606 }
3607 offsets.Add(start);
3608 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 if (start == end) if (++end > length) break;
3610 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003611 if (match.is_null()) {
3612 return Failure::Exception();
3613 }
3614 } while (!match->IsNull());
3615 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003617 Handle<String> substring = isolate->factory()->
3618 NewSubString(subject, offsets.at(0), offsets.at(1));
3619 elements->set(0, *substring);
3620 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003621 int from = offsets.at(i * 2);
3622 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring = isolate->factory()->
3624 NewProperSubString(subject, from, to);
3625 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003628 result->set_length(Smi::FromInt(matches));
3629 return *result;
3630}
3631
3632
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633// Two smis before and after the match, for very long strings.
3634const int kMaxBuilderEntriesPerRegExpMatch = 5;
3635
3636
3637static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3638 Handle<JSArray> last_match_info,
3639 int match_start,
3640 int match_end) {
3641 // Fill last_match_info with a single capture.
3642 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, 2);
3646 RegExpImpl::SetLastInput(elements, *subject);
3647 RegExpImpl::SetLastSubject(elements, *subject);
3648 RegExpImpl::SetCapture(elements, 0, match_start);
3649 RegExpImpl::SetCapture(elements, 1, match_end);
3650}
3651
3652
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003653template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654static bool SearchStringMultiple(Isolate* isolate,
3655 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 Vector<const PatternChar> pattern,
3657 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 FixedArrayBuilder* builder,
3659 int* match_pos) {
3660 int pos = *match_pos;
3661 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 while (pos <= max_search_start) {
3666 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3667 *match_pos = pos;
3668 return false;
3669 }
3670 // Position of end of previous match.
3671 int match_end = pos + pattern_length;
3672 int new_pos = search.Search(subject, match_end);
3673 if (new_pos >= 0) {
3674 // A match.
3675 if (new_pos > match_end) {
3676 ReplacementStringBuilder::AddSubjectSlice(builder,
3677 match_end,
3678 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003680 pos = new_pos;
3681 builder->Add(pattern_string);
3682 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003684 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003686
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 if (pos < max_search_start) {
3688 ReplacementStringBuilder::AddSubjectSlice(builder,
3689 pos + pattern_length,
3690 subject_length);
3691 }
3692 *match_pos = pos;
3693 return true;
3694}
3695
3696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697static bool SearchStringMultiple(Isolate* isolate,
3698 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 Handle<String> pattern,
3700 Handle<JSArray> last_match_info,
3701 FixedArrayBuilder* builder) {
3702 ASSERT(subject->IsFlat());
3703 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003704
3705 // Treating as if a previous match was before first character.
3706 int match_pos = -pattern->length();
3707
3708 for (;;) { // Break when search complete.
3709 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3710 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 String::FlatContent subject_content = subject->GetFlatContent();
3712 String::FlatContent pattern_content = pattern->GetFlatContent();
3713 if (subject_content.IsAscii()) {
3714 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3715 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716 if (SearchStringMultiple(isolate,
3717 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003718 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003719 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 builder,
3721 &match_pos)) break;
3722 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 if (SearchStringMultiple(isolate,
3724 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003725 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003726 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003727 builder,
3728 &match_pos)) break;
3729 }
3730 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003731 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3732 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (SearchStringMultiple(isolate,
3734 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003735 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003736 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 builder,
3738 &match_pos)) break;
3739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 if (SearchStringMultiple(isolate,
3741 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003742 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003743 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003744 builder,
3745 &match_pos)) break;
3746 }
3747 }
3748 }
3749
3750 if (match_pos >= 0) {
3751 SetLastMatchInfoNoCaptures(subject,
3752 last_match_info,
3753 match_pos,
3754 match_pos + pattern->length());
3755 return true;
3756 }
3757 return false; // No matches at all.
3758}
3759
3760
3761static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003762 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003763 Handle<String> subject,
3764 Handle<JSRegExp> regexp,
3765 Handle<JSArray> last_match_array,
3766 FixedArrayBuilder* builder) {
3767 ASSERT(subject->IsFlat());
3768 int match_start = -1;
3769 int match_end = 0;
3770 int pos = 0;
3771 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3772 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3773
3774 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003775 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003776 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003777 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778
3779 for (;;) { // Break on failure, return on exception.
3780 RegExpImpl::IrregexpResult result =
3781 RegExpImpl::IrregexpExecOnce(regexp,
3782 subject,
3783 pos,
3784 register_vector);
3785 if (result == RegExpImpl::RE_SUCCESS) {
3786 match_start = register_vector[0];
3787 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3788 if (match_end < match_start) {
3789 ReplacementStringBuilder::AddSubjectSlice(builder,
3790 match_end,
3791 match_start);
3792 }
3793 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 if (!first) {
3796 builder->Add(*isolate->factory()->NewProperSubString(subject,
3797 match_start,
3798 match_end));
3799 } else {
3800 builder->Add(*isolate->factory()->NewSubString(subject,
3801 match_start,
3802 match_end));
3803 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003804 if (match_start != match_end) {
3805 pos = match_end;
3806 } else {
3807 pos = match_end + 1;
3808 if (pos > subject_length) break;
3809 }
3810 } else if (result == RegExpImpl::RE_FAILURE) {
3811 break;
3812 } else {
3813 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3814 return result;
3815 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003816 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 }
3818
3819 if (match_start >= 0) {
3820 if (match_end < subject_length) {
3821 ReplacementStringBuilder::AddSubjectSlice(builder,
3822 match_end,
3823 subject_length);
3824 }
3825 SetLastMatchInfoNoCaptures(subject,
3826 last_match_array,
3827 match_start,
3828 match_end);
3829 return RegExpImpl::RE_SUCCESS;
3830 } else {
3831 return RegExpImpl::RE_FAILURE; // No matches at all.
3832 }
3833}
3834
3835
3836static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 Handle<String> subject,
3839 Handle<JSRegExp> regexp,
3840 Handle<JSArray> last_match_array,
3841 FixedArrayBuilder* builder) {
3842
3843 ASSERT(subject->IsFlat());
3844 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3845 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3846
3847 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003848 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003849
3850 RegExpImpl::IrregexpResult result =
3851 RegExpImpl::IrregexpExecOnce(regexp,
3852 subject,
3853 0,
3854 register_vector);
3855
3856 int capture_count = regexp->CaptureCount();
3857 int subject_length = subject->length();
3858
3859 // Position to search from.
3860 int pos = 0;
3861 // End of previous match. Differs from pos if match was empty.
3862 int match_end = 0;
3863 if (result == RegExpImpl::RE_SUCCESS) {
3864 // Need to keep a copy of the previous match for creating last_match_info
3865 // at the end, so we have two vectors that we swap between.
3866 OffsetsVector registers2(required_registers);
3867 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003868 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869 do {
3870 int match_start = register_vector[0];
3871 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3872 if (match_end < match_start) {
3873 ReplacementStringBuilder::AddSubjectSlice(builder,
3874 match_end,
3875 match_start);
3876 }
3877 match_end = register_vector[1];
3878
3879 {
3880 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003881 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003882 // Arguments array to replace function is match, captures, index and
3883 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 Handle<FixedArray> elements =
3885 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003886 Handle<String> match;
3887 if (!first) {
3888 match = isolate->factory()->NewProperSubString(subject,
3889 match_start,
3890 match_end);
3891 } else {
3892 match = isolate->factory()->NewSubString(subject,
3893 match_start,
3894 match_end);
3895 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 for (int i = 1; i <= capture_count; i++) {
3898 int start = register_vector[i * 2];
3899 if (start >= 0) {
3900 int end = register_vector[i * 2 + 1];
3901 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003902 Handle<String> substring;
3903 if (!first) {
3904 substring = isolate->factory()->NewProperSubString(subject,
3905 start,
3906 end);
3907 } else {
3908 substring = isolate->factory()->NewSubString(subject, start, end);
3909 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 elements->set(i, *substring);
3911 } else {
3912 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 }
3916 elements->set(capture_count + 1, Smi::FromInt(match_start));
3917 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003918 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 // Swap register vectors, so the last successful match is in
3921 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003922 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 prev_register_vector = register_vector;
3924 register_vector = tmp;
3925
3926 if (match_end > match_start) {
3927 pos = match_end;
3928 } else {
3929 pos = match_end + 1;
3930 if (pos > subject_length) {
3931 break;
3932 }
3933 }
3934
3935 result = RegExpImpl::IrregexpExecOnce(regexp,
3936 subject,
3937 pos,
3938 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003939 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003940 } while (result == RegExpImpl::RE_SUCCESS);
3941
3942 if (result != RegExpImpl::RE_EXCEPTION) {
3943 // Finished matching, with at least one match.
3944 if (match_end < subject_length) {
3945 ReplacementStringBuilder::AddSubjectSlice(builder,
3946 match_end,
3947 subject_length);
3948 }
3949
3950 int last_match_capture_count = (capture_count + 1) * 2;
3951 int last_match_array_size =
3952 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3953 last_match_array->EnsureSize(last_match_array_size);
3954 AssertNoAllocation no_gc;
3955 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3956 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3957 RegExpImpl::SetLastSubject(elements, *subject);
3958 RegExpImpl::SetLastInput(elements, *subject);
3959 for (int i = 0; i < last_match_capture_count; i++) {
3960 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3961 }
3962 return RegExpImpl::RE_SUCCESS;
3963 }
3964 }
3965 // No matches at all, return failure or exception result directly.
3966 return result;
3967}
3968
3969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003970RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003973
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003974 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003975 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003976 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3977 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3978 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003979
3980 ASSERT(last_match_info->HasFastElements());
3981 ASSERT(regexp->GetFlags().is_global());
3982 Handle<FixedArray> result_elements;
3983 if (result_array->HasFastElements()) {
3984 result_elements =
3985 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003986 }
3987 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003989 }
3990 FixedArrayBuilder builder(result_elements);
3991
3992 if (regexp->TypeTag() == JSRegExp::ATOM) {
3993 Handle<String> pattern(
3994 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 if (SearchStringMultiple(isolate, subject, pattern,
3997 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 return *builder.ToJSArray(result_array);
3999 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 }
4002
4003 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4004
4005 RegExpImpl::IrregexpResult result;
4006 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 result = SearchRegExpNoCaptureMultiple(isolate,
4008 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004009 regexp,
4010 last_match_info,
4011 &builder);
4012 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 result = SearchRegExpMultiple(isolate,
4014 subject,
4015 regexp,
4016 last_match_info,
4017 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 }
4019 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004021 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4022 return Failure::Exception();
4023}
4024
4025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 NoHandleAllocation ha;
4028 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004030 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004033 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004035 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004036 // Character array used for conversion.
4037 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->
4039 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004040 }
4041 }
4042
4043 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004044 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
4048 if (isinf(value)) {
4049 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 MaybeObject* result =
4056 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 DeleteArray(str);
4058 return result;
4059}
4060
4061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 NoHandleAllocation ha;
4064 ASSERT(args.length() == 2);
4065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004066 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070 if (isinf(value)) {
4071 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004076 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 int f = FastD2I(f_number);
4078 RUNTIME_ASSERT(f >= 0);
4079 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 MaybeObject* res =
4081 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084}
4085
4086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 NoHandleAllocation ha;
4089 ASSERT(args.length() == 2);
4090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004091 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095 if (isinf(value)) {
4096 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004099 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004101 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 int f = FastD2I(f_number);
4103 RUNTIME_ASSERT(f >= -1 && f <= 20);
4104 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 MaybeObject* res =
4106 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109}
4110
4111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
4114 ASSERT(args.length() == 2);
4115
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004116 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004118 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 }
4120 if (isinf(value)) {
4121 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004122 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004126 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 int f = FastD2I(f_number);
4128 RUNTIME_ASSERT(f >= 1 && f <= 21);
4129 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 MaybeObject* res =
4131 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004133 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134}
4135
4136
4137// Returns a single character string where first character equals
4138// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004140 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004141 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004142 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004143 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146}
4147
4148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4150 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Handle [] indexing on Strings
4153 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 // Handle [] indexing on String objects
4159 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4161 Handle<Object> result =
4162 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4163 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004167 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169
4170 return object->GetElement(index);
4171}
4172
4173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4175 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004180 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 isolate->factory()->NewTypeError("non_object_property_load",
4183 HandleVector(args, 2));
4184 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
4186
4187 // Check if the given key is an array index.
4188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004189 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 bool has_pending_exception = false;
4199 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204
ager@chromium.org32912102009-01-16 10:38:43 +00004205 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 // the element if so.
4207 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004210 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 }
4212}
4213
4214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
4217 ASSERT(args.length() == 2);
4218
4219 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004220 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004222 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223}
4224
4225
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004226// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 NoHandleAllocation ha;
4229 ASSERT(args.length() == 2);
4230
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // itself.
4233 //
4234 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004235 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004236 // global proxy object never has properties. This is the case
4237 // because the global proxy object forwards everything to its hidden
4238 // prototype including local lookups.
4239 //
4240 // Additionally, we need to make sure that we do not cache results
4241 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004242 if (args[0]->IsJSObject()) {
4243 if (!args[0]->IsJSGlobalProxy() &&
4244 !args[0]->IsAccessCheckNeeded() &&
4245 args[1]->IsString()) {
4246 JSObject* receiver = JSObject::cast(args[0]);
4247 String* key = String::cast(args[1]);
4248 if (receiver->HasFastProperties()) {
4249 // Attempt to use lookup cache.
4250 Map* receiver_map = receiver->map();
4251 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4252 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4253 if (offset != -1) {
4254 Object* value = receiver->FastPropertyAt(offset);
4255 return value->IsTheHole()
4256 ? isolate->heap()->undefined_value()
4257 : value;
4258 }
4259 // Lookup cache miss. Perform lookup and update the cache if
4260 // appropriate.
4261 LookupResult result(isolate);
4262 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004263 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004264 int offset = result.GetFieldIndex();
4265 keyed_lookup_cache->Update(receiver_map, key, offset);
4266 return receiver->FastPropertyAt(offset);
4267 }
4268 } else {
4269 // Attempt dictionary lookup.
4270 StringDictionary* dictionary = receiver->property_dictionary();
4271 int entry = dictionary->FindEntry(key);
4272 if ((entry != StringDictionary::kNotFound) &&
4273 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4274 Object* value = dictionary->ValueAt(entry);
4275 if (!receiver->IsGlobalObject()) return value;
4276 value = JSGlobalPropertyCell::cast(value)->value();
4277 if (!value->IsTheHole()) return value;
4278 // If value is the hole do the general lookup.
4279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004280 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004281 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4282 // JSObject without a string key. If the key is a Smi, check for a
4283 // definite out-of-bounds access to elements, which is a strong indicator
4284 // that subsequent accesses will also call the runtime. Proactively
4285 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4286 // doubles for those future calls in the case that the elements would
4287 // become FAST_DOUBLE_ELEMENTS.
4288 Handle<JSObject> js_object(args.at<JSObject>(0));
4289 ElementsKind elements_kind = js_object->GetElementsKind();
4290 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4291 elements_kind == FAST_DOUBLE_ELEMENTS) {
4292 FixedArrayBase* elements = js_object->elements();
4293 if (args.at<Smi>(1)->value() >= elements->length()) {
4294 MaybeObject* maybe_object = TransitionElements(js_object,
4295 FAST_ELEMENTS,
4296 isolate);
4297 if (maybe_object->IsFailure()) return maybe_object;
4298 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004299 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004300 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004301 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4302 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004303 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004304 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004305 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004306 if (index >= 0 && index < str->length()) {
4307 Handle<Object> result = GetCharAt(str, index);
4308 return *result;
4309 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004311
4312 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 return Runtime::GetObjectProperty(isolate,
4314 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004315 args.at<Object>(1));
4316}
4317
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004318// Implements part of 8.12.9 DefineOwnProperty.
4319// There are 3 cases that lead here:
4320// Step 4b - define a new accessor property.
4321// Steps 9c & 12 - replace an existing data property with an accessor property.
4322// Step 12 - update an existing accessor property with an accessor or generic
4323// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004324RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004327 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4328 CONVERT_ARG_CHECKED(String, name, 1);
4329 CONVERT_SMI_ARG_CHECKED(flag_setter, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004330 Object* fun = args[3];
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004331 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004332
ager@chromium.org5c838252010-02-19 08:53:10 +00004333 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004334 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004335
4336 RUNTIME_ASSERT(!obj->IsNull());
4337 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004338 return obj->DefineAccessor(name, flag_setter == 0, fun, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004339}
4340
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004341// Implements part of 8.12.9 DefineOwnProperty.
4342// There are 3 cases that lead here:
4343// Step 4a - define a new data property.
4344// Steps 9b & 12 - replace an existing accessor property with a data property.
4345// Step 12 - update an existing data property with a data or generic
4346// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004347RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004348 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004349 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004350 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4351 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004352 Handle<Object> obj_value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004353 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004354
ager@chromium.org5c838252010-02-19 08:53:10 +00004355 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004356 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4357
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004358 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004359 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004360
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004361 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004362 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004363 Object* callback = result.GetCallbackObject();
4364 // To be compatible with Safari we do not change the value on API objects
4365 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4366 // the value.
4367 if (callback->IsAccessorInfo()) {
4368 return isolate->heap()->undefined_value();
4369 }
4370 // Avoid redefining foreign callback as data property, just use the stored
4371 // setter to update the value instead.
4372 // TODO(mstarzinger): So far this only works if property attributes don't
4373 // change, this should be fixed once we cleanup the underlying code.
4374 if (callback->IsForeign() && result.GetAttributes() == attr) {
4375 return js_object->SetPropertyWithCallback(callback,
4376 *name,
4377 *obj_value,
4378 result.holder(),
4379 kStrictMode);
4380 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004381 }
4382
ager@chromium.org5c838252010-02-19 08:53:10 +00004383 // Take special care when attributes are different and there is already
4384 // a property. For simplicity we normalize the property which enables us
4385 // to not worry about changing the instance_descriptor and creating a new
4386 // map. The current version of SetObjectProperty does not handle attributes
4387 // correctly in the case where a property is a field and is reset with
4388 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004389 if (result.IsProperty() &&
4390 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004391 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004392 if (js_object->IsJSGlobalProxy()) {
4393 // Since the result is a property, the prototype will exist so
4394 // we don't have to check for null.
4395 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004396 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004397 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004398 // Use IgnoreAttributes version since a readonly property may be
4399 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004400 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4401 *obj_value,
4402 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004403 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return Runtime::ForceSetObjectProperty(isolate,
4406 js_object,
4407 name,
4408 obj_value,
4409 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004410}
4411
4412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4414 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004415 Handle<Object> key,
4416 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004417 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004418 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004419 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004420 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004423 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 isolate->factory()->NewTypeError("non_object_property_store",
4426 HandleVector(args, 2));
4427 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004428 }
4429
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004430 if (object->IsJSProxy()) {
4431 bool has_pending_exception = false;
4432 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4433 if (has_pending_exception) return Failure::Exception();
4434 return JSProxy::cast(*object)->SetProperty(
4435 String::cast(*name), *value, attr, strict_mode);
4436 }
4437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 // If the object isn't a JavaScript object, we ignore the store.
4439 if (!object->IsJSObject()) return *value;
4440
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004441 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4442
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 // Check if the given key is an array index.
4444 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004445 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4447 // of a string using [] notation. We need to support this too in
4448 // JavaScript.
4449 // In the case of a String object we just need to redirect the assignment to
4450 // the underlying string if the index is in range. Since the underlying
4451 // string does nothing with the assignment then we can ignore such
4452 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004453 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004457 Handle<Object> result = JSObject::SetElement(
4458 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004459 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 return *value;
4461 }
4462
4463 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464 Handle<Object> result;
4465 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004466 result = JSObject::SetElement(
4467 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004469 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004470 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004471 result = JSReceiver::SetProperty(
4472 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004474 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 return *value;
4476 }
4477
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 bool has_pending_exception = false;
4480 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4481 if (has_pending_exception) return Failure::Exception();
4482 Handle<String> name = Handle<String>::cast(converted);
4483
4484 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004485 return js_object->SetElement(
4486 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004488 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 }
4490}
4491
4492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4494 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004495 Handle<Object> key,
4496 Handle<Object> value,
4497 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004499
4500 // Check if the given key is an array index.
4501 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004502 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004503 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4504 // of a string using [] notation. We need to support this too in
4505 // JavaScript.
4506 // In the case of a String object we just need to redirect the assignment to
4507 // the underlying string if the index is in range. Since the underlying
4508 // string does nothing with the assignment then we can ignore such
4509 // assignments.
4510 if (js_object->IsStringObjectWithCharacterAt(index)) {
4511 return *value;
4512 }
4513
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004514 return js_object->SetElement(
4515 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516 }
4517
4518 if (key->IsString()) {
4519 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004520 return js_object->SetElement(
4521 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004522 } else {
4523 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004524 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004525 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4526 *value,
4527 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004528 }
4529 }
4530
4531 // Call-back into JavaScript to convert the key to a string.
4532 bool has_pending_exception = false;
4533 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4534 if (has_pending_exception) return Failure::Exception();
4535 Handle<String> name = Handle<String>::cast(converted);
4536
4537 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004538 return js_object->SetElement(
4539 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004540 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004541 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004542 }
4543}
4544
4545
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004547 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004548 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004550
4551 // Check if the given key is an array index.
4552 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004553 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004554 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4555 // characters of a string using [] notation. In the case of a
4556 // String object we just need to redirect the deletion to the
4557 // underlying string if the index is in range. Since the
4558 // underlying string does nothing with the deletion, we can ignore
4559 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004560 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004561 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004562 }
4563
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004564 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004565 }
4566
4567 Handle<String> key_string;
4568 if (key->IsString()) {
4569 key_string = Handle<String>::cast(key);
4570 } else {
4571 // Call-back into JavaScript to convert the key to a string.
4572 bool has_pending_exception = false;
4573 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4574 if (has_pending_exception) return Failure::Exception();
4575 key_string = Handle<String>::cast(converted);
4576 }
4577
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004578 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004579 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004580}
4581
4582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004583RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004585 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586
4587 Handle<Object> object = args.at<Object>(0);
4588 Handle<Object> key = args.at<Object>(1);
4589 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004590 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004591 RUNTIME_ASSERT(
4592 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004594 PropertyAttributes attributes =
4595 static_cast<PropertyAttributes>(unchecked_attributes);
4596
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004597 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004599 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004600 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 return Runtime::SetObjectProperty(isolate,
4604 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004605 key,
4606 value,
4607 attributes,
4608 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609}
4610
4611
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004612RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4613 NoHandleAllocation ha;
4614 RUNTIME_ASSERT(args.length() == 1);
4615 Handle<Object> object = args.at<Object>(0);
4616 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4617}
4618
4619
4620RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4621 NoHandleAllocation ha;
4622 RUNTIME_ASSERT(args.length() == 1);
4623 Handle<Object> object = args.at<Object>(0);
4624 return TransitionElements(object, FAST_ELEMENTS, isolate);
4625}
4626
4627
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004628// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004629// This is used to decide if we should transform null and undefined
4630// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004631RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004632 NoHandleAllocation ha;
4633 RUNTIME_ASSERT(args.length() == 1);
4634
4635 Handle<Object> object = args.at<Object>(0);
4636
4637 if (object->IsJSFunction()) {
4638 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004639 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004640 }
4641 return isolate->heap()->undefined_value();
4642}
4643
4644
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004645RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4646 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004647 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004648 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4649 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004650 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004651 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4652 HandleScope scope;
4653
4654 Object* raw_boilerplate_object = literals->get(literal_index);
4655 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4656#if DEBUG
4657 ElementsKind elements_kind = object->GetElementsKind();
4658#endif
4659 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4660 // Smis should never trigger transitions.
4661 ASSERT(!value->IsSmi());
4662
4663 if (value->IsNumber()) {
4664 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004665 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4666 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004667 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4668 FixedDoubleArray* double_array =
4669 FixedDoubleArray::cast(object->elements());
4670 HeapNumber* number = HeapNumber::cast(*value);
4671 double_array->set(store_index, number->Number());
4672 } else {
4673 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4674 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004675 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4676 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004677 FixedArray* object_array =
4678 FixedArray::cast(object->elements());
4679 object_array->set(store_index, *value);
4680 }
4681 return *object;
4682}
4683
4684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685// Set a local property, even if it is READ_ONLY. If the property does not
4686// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004687RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004689 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004690 CONVERT_ARG_CHECKED(JSObject, object, 0);
4691 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004692 // Compute attributes.
4693 PropertyAttributes attributes = NONE;
4694 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004695 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004696 // Only attribute bits should be set.
4697 RUNTIME_ASSERT(
4698 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4699 attributes = static_cast<PropertyAttributes>(unchecked_value);
4700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004702 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004703 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704}
4705
4706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004707RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004709 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004711 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4712 CONVERT_ARG_CHECKED(String, key, 1);
4713 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004714 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004715 ? JSReceiver::STRICT_DELETION
4716 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717}
4718
4719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004720static Object* HasLocalPropertyImplementation(Isolate* isolate,
4721 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004722 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004724 // Handle hidden prototypes. If there's a hidden prototype above this thing
4725 // then we have to check it for properties, because they are supposed to
4726 // look like they are on this object.
4727 Handle<Object> proto(object->GetPrototype());
4728 if (proto->IsJSObject() &&
4729 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 return HasLocalPropertyImplementation(isolate,
4731 Handle<JSObject>::cast(proto),
4732 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004733 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004734 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004735}
4736
4737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004738RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 NoHandleAllocation ha;
4740 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004741 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004743 uint32_t index;
4744 const bool key_is_array_index = key->AsArrayIndex(&index);
4745
ager@chromium.org9085a012009-05-11 19:22:57 +00004746 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004748 if (obj->IsJSObject()) {
4749 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004750 // Fast case: either the key is a real named property or it is not
4751 // an array index and there are no interceptors or hidden
4752 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004753 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004754 Map* map = object->map();
4755 if (!key_is_array_index &&
4756 !map->has_named_interceptor() &&
4757 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4758 return isolate->heap()->false_value();
4759 }
4760 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 HandleScope scope(isolate);
4762 return HasLocalPropertyImplementation(isolate,
4763 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004764 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004765 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004767 String* string = String::cast(obj);
4768 if (index < static_cast<uint32_t>(string->length())) {
4769 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 }
4771 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004772 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773}
4774
4775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004776RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 NoHandleAllocation na;
4778 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004779 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4780 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004782 bool result = receiver->HasProperty(key);
4783 if (isolate->has_pending_exception()) return Failure::Exception();
4784 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785}
4786
4787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004788RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789 NoHandleAllocation na;
4790 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004791 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4792 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004794 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004795 if (isolate->has_pending_exception()) return Failure::Exception();
4796 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797}
4798
4799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 NoHandleAllocation ha;
4802 ASSERT(args.length() == 2);
4803
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004804 CONVERT_ARG_CHECKED(JSObject, object, 0);
4805 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806
4807 uint32_t index;
4808 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004809 JSObject::LocalElementType type = object->HasLocalElement(index);
4810 switch (type) {
4811 case JSObject::UNDEFINED_ELEMENT:
4812 case JSObject::STRING_CHARACTER_ELEMENT:
4813 return isolate->heap()->false_value();
4814 case JSObject::INTERCEPTED_ELEMENT:
4815 case JSObject::FAST_ELEMENT:
4816 return isolate->heap()->true_value();
4817 case JSObject::DICTIONARY_ELEMENT: {
4818 if (object->IsJSGlobalProxy()) {
4819 Object* proto = object->GetPrototype();
4820 if (proto->IsNull()) {
4821 return isolate->heap()->false_value();
4822 }
4823 ASSERT(proto->IsJSGlobalObject());
4824 object = JSObject::cast(proto);
4825 }
4826 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004827 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 if (elements->map() ==
4829 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004830 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004831 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004832 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004833 }
4834 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004835 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004836 PropertyDetails details = dictionary->DetailsAt(entry);
4837 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4838 }
4839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840 }
4841
ager@chromium.org870a0b62008-11-04 11:43:05 +00004842 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004843 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844}
4845
4846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004847RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004850 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004851 bool threw = false;
4852 Handle<JSArray> result = GetKeysFor(object, &threw);
4853 if (threw) return Failure::Exception();
4854 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855}
4856
4857
4858// Returns either a FixedArray as Runtime_GetPropertyNames,
4859// or, if the given object has an enum cache that contains
4860// all enumerable properties of the object and its prototypes
4861// have none, the map of the object. This is used to speed up
4862// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004863RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 ASSERT(args.length() == 1);
4865
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004866 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867
4868 if (raw_object->IsSimpleEnum()) return raw_object->map();
4869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004870 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004871 Handle<JSReceiver> object(raw_object);
4872 bool threw = false;
4873 Handle<FixedArray> content =
4874 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4875 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876
4877 // Test again, since cache may have been built by preceding call.
4878 if (object->IsSimpleEnum()) return object->map();
4879
4880 return *content;
4881}
4882
4883
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004884// Find the length of the prototype chain that is to to handled as one. If a
4885// prototype object is hidden it is to be viewed as part of the the object it
4886// is prototype for.
4887static int LocalPrototypeChainLength(JSObject* obj) {
4888 int count = 1;
4889 Object* proto = obj->GetPrototype();
4890 while (proto->IsJSObject() &&
4891 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4892 count++;
4893 proto = JSObject::cast(proto)->GetPrototype();
4894 }
4895 return count;
4896}
4897
4898
4899// Return the names of the local named properties.
4900// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004901RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004902 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004903 ASSERT(args.length() == 1);
4904 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004905 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004907 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004908
4909 // Skip the global proxy as it has no properties and always delegates to the
4910 // real global object.
4911 if (obj->IsJSGlobalProxy()) {
4912 // Only collect names if access is permitted.
4913 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004914 !isolate->MayNamedAccess(*obj,
4915 isolate->heap()->undefined_value(),
4916 v8::ACCESS_KEYS)) {
4917 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4918 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004919 }
4920 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4921 }
4922
4923 // Find the number of objects making up this.
4924 int length = LocalPrototypeChainLength(*obj);
4925
4926 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004927 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004928 int total_property_count = 0;
4929 Handle<JSObject> jsproto = obj;
4930 for (int i = 0; i < length; i++) {
4931 // Only collect names if access is permitted.
4932 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004933 !isolate->MayNamedAccess(*jsproto,
4934 isolate->heap()->undefined_value(),
4935 v8::ACCESS_KEYS)) {
4936 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4937 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004938 }
4939 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004940 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004941 local_property_count[i] = n;
4942 total_property_count += n;
4943 if (i < length - 1) {
4944 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4945 }
4946 }
4947
4948 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 Handle<FixedArray> names =
4950 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004951
4952 // Get the property names.
4953 jsproto = obj;
4954 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004955 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004956 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004957 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4958 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004959 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004960 proto_with_hidden_properties++;
4961 }
4962 if (i < length - 1) {
4963 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4964 }
4965 }
4966
4967 // Filter out name of hidden propeties object.
4968 if (proto_with_hidden_properties > 0) {
4969 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004971 names->length() - proto_with_hidden_properties);
4972 int dest_pos = 0;
4973 for (int i = 0; i < total_property_count; i++) {
4974 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976 continue;
4977 }
4978 names->set(dest_pos++, name);
4979 }
4980 }
4981
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004982 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004983}
4984
4985
4986// Return the names of the local indexed properties.
4987// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004988RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004990 ASSERT(args.length() == 1);
4991 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004994 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004995
4996 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004997 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004998 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000}
5001
5002
5003// Return information on whether an object has a named or indexed interceptor.
5004// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007 ASSERT(args.length() == 1);
5008 if (!args[0]->IsJSObject()) {
5009 return Smi::FromInt(0);
5010 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005011 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005012
5013 int result = 0;
5014 if (obj->HasNamedInterceptor()) result |= 2;
5015 if (obj->HasIndexedInterceptor()) result |= 1;
5016
5017 return Smi::FromInt(result);
5018}
5019
5020
5021// Return property names from named interceptor.
5022// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005023RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005026 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027
5028 if (obj->HasNamedInterceptor()) {
5029 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5030 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5031 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005033}
5034
5035
5036// Return element names from indexed interceptor.
5037// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005038RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005040 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005041 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042
5043 if (obj->HasIndexedInterceptor()) {
5044 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5045 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5046 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005048}
5049
5050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005052 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005053 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005055 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005056
5057 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005058 // Do access checks before going to the global object.
5059 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005061 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5063 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005064 }
5065
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005066 Handle<Object> proto(object->GetPrototype());
5067 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005069 object = Handle<JSObject>::cast(proto);
5070 }
5071
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005072 bool threw = false;
5073 Handle<FixedArray> contents =
5074 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5075 if (threw) return Failure::Exception();
5076
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005077 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5078 // property array and since the result is mutable we have to create
5079 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005080 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005082 for (int i = 0; i < length; i++) {
5083 Object* entry = contents->get(i);
5084 if (entry->IsString()) {
5085 copy->set(i, entry);
5086 } else {
5087 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 HandleScope scope(isolate);
5089 Handle<Object> entry_handle(entry, isolate);
5090 Handle<Object> entry_str =
5091 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005092 copy->set(i, *entry_str);
5093 }
5094 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005095 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005096}
5097
5098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005099RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005100 NoHandleAllocation ha;
5101 ASSERT(args.length() == 1);
5102
5103 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005104 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005105 it.AdvanceToArgumentsFrame();
5106 JavaScriptFrame* frame = it.frame();
5107
5108 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005109 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005110
5111 // Try to convert the key to an index. If successful and within
5112 // index return the the argument from the frame.
5113 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005114 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005115 return frame->GetParameter(index);
5116 }
5117
5118 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005119 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005120 bool exception = false;
5121 Handle<Object> converted =
5122 Execution::ToString(args.at<Object>(0), &exception);
5123 if (exception) return Failure::Exception();
5124 Handle<String> key = Handle<String>::cast(converted);
5125
5126 // Try to convert the string key into an array index.
5127 if (key->AsArrayIndex(&index)) {
5128 if (index < n) {
5129 return frame->GetParameter(index);
5130 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005131 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132 }
5133 }
5134
5135 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005136 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5137 if (key->Equals(isolate->heap()->callee_symbol())) {
5138 Object* function = frame->function();
5139 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005140 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return isolate->Throw(*isolate->factory()->NewTypeError(
5142 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5143 }
5144 return function;
5145 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146
5147 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149}
5150
5151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005152RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005153 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005154 Object* object = args[0];
5155 return (object->IsJSObject() && !object->IsGlobalObject())
5156 ? JSObject::cast(object)->TransformToFastProperties(0)
5157 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005158}
5159
5160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005161RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005162 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005163 Object* obj = args[0];
5164 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5165 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5166 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005167}
5168
5169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005170RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171 NoHandleAllocation ha;
5172 ASSERT(args.length() == 1);
5173
5174 return args[0]->ToBoolean();
5175}
5176
5177
5178// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5179// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005180RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 NoHandleAllocation ha;
5182
5183 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185 HeapObject* heap_obj = HeapObject::cast(obj);
5186
5187 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 if (heap_obj->map()->is_undetectable()) {
5189 return isolate->heap()->undefined_symbol();
5190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191
5192 InstanceType instance_type = heap_obj->map()->instance_type();
5193 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 }
5196
5197 switch (instance_type) {
5198 case ODDBALL_TYPE:
5199 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 }
5202 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005203 return FLAG_harmony_typeof
5204 ? isolate->heap()->null_symbol()
5205 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 }
5207 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005209 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005210 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 default:
5213 // For any kind of object not handled above, the spec rule for
5214 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 }
5217}
5218
5219
lrn@chromium.org25156de2010-04-06 13:10:27 +00005220static bool AreDigits(const char*s, int from, int to) {
5221 for (int i = from; i < to; i++) {
5222 if (s[i] < '0' || s[i] > '9') return false;
5223 }
5224
5225 return true;
5226}
5227
5228
5229static int ParseDecimalInteger(const char*s, int from, int to) {
5230 ASSERT(to - from < 10); // Overflow is not possible.
5231 ASSERT(from < to);
5232 int d = s[from] - '0';
5233
5234 for (int i = from + 1; i < to; i++) {
5235 d = 10 * d + (s[i] - '0');
5236 }
5237
5238 return d;
5239}
5240
5241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005242RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 NoHandleAllocation ha;
5244 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005245 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005246 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005247
5248 // Fast case: short integer or some sorts of junk values.
5249 int len = subject->length();
5250 if (subject->IsSeqAsciiString()) {
5251 if (len == 0) return Smi::FromInt(0);
5252
5253 char const* data = SeqAsciiString::cast(subject)->GetChars();
5254 bool minus = (data[0] == '-');
5255 int start_pos = (minus ? 1 : 0);
5256
5257 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005259 } else if (data[start_pos] > '9') {
5260 // Fast check for a junk value. A valid string may start from a
5261 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5262 // the 'I' character ('Infinity'). All of that have codes not greater than
5263 // '9' except 'I'.
5264 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005266 }
5267 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5268 // The maximal/minimal smi has 10 digits. If the string has less digits we
5269 // know it will fit into the smi-data type.
5270 int d = ParseDecimalInteger(data, start_pos, len);
5271 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005273 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005274 } else if (!subject->HasHashCode() &&
5275 len <= String::kMaxArrayIndexSize &&
5276 (len == 1 || data[0] != '0')) {
5277 // String hash is not calculated yet but all the data are present.
5278 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005279 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005280#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005281 subject->Hash(); // Force hash calculation.
5282 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5283 static_cast<int>(hash));
5284#endif
5285 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005286 }
5287 return Smi::FromInt(d);
5288 }
5289 }
5290
5291 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005292 return isolate->heap()->NumberFromDouble(
5293 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005294}
5295
5296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005297RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005298 NoHandleAllocation ha;
5299 ASSERT(args.length() == 1);
5300
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005301 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005302 int length = Smi::cast(codes->length())->value();
5303
5304 // Check if the string can be ASCII.
5305 int i;
5306 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307 Object* element;
5308 { MaybeObject* maybe_element = codes->GetElement(i);
5309 // We probably can't get an exception here, but just in order to enforce
5310 // the checking of inputs in the runtime calls we check here.
5311 if (!maybe_element->ToObject(&element)) return maybe_element;
5312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5314 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5315 break;
5316 }
5317
lrn@chromium.org303ada72010-10-27 09:33:13 +00005318 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005321 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005322 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 }
5324
lrn@chromium.org303ada72010-10-27 09:33:13 +00005325 Object* object = NULL;
5326 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 String* result = String::cast(object);
5328 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005329 Object* element;
5330 { MaybeObject* maybe_element = codes->GetElement(i);
5331 if (!maybe_element->ToObject(&element)) return maybe_element;
5332 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005334 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005335 }
5336 return result;
5337}
5338
5339
5340// kNotEscaped is generated by the following:
5341//
5342// #!/bin/perl
5343// for (my $i = 0; $i < 256; $i++) {
5344// print "\n" if $i % 16 == 0;
5345// my $c = chr($i);
5346// my $escaped = 1;
5347// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5348// print $escaped ? "0, " : "1, ";
5349// }
5350
5351
5352static bool IsNotEscaped(uint16_t character) {
5353 // Only for 8 bit characters, the rest are always escaped (in a different way)
5354 ASSERT(character < 256);
5355 static const char kNotEscaped[256] = {
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5362 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5363 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5372 };
5373 return kNotEscaped[character] != 0;
5374}
5375
5376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005377RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 const char hex_chars[] = "0123456789ABCDEF";
5379 NoHandleAllocation ha;
5380 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005381 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005383 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384
5385 int escaped_length = 0;
5386 int length = source->length();
5387 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005388 Access<StringInputBuffer> buffer(
5389 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 buffer->Reset(source);
5391 while (buffer->has_more()) {
5392 uint16_t character = buffer->GetNext();
5393 if (character >= 256) {
5394 escaped_length += 6;
5395 } else if (IsNotEscaped(character)) {
5396 escaped_length++;
5397 } else {
5398 escaped_length += 3;
5399 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005400 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005401 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005402 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005403 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404 return Failure::OutOfMemoryException();
5405 }
5406 }
5407 }
5408 // No length change implies no change. Return original string if no change.
5409 if (escaped_length == length) {
5410 return source;
5411 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005412 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 { MaybeObject* maybe_o =
5414 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005415 if (!maybe_o->ToObject(&o)) return maybe_o;
5416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417 String* destination = String::cast(o);
5418 int dest_position = 0;
5419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 Access<StringInputBuffer> buffer(
5421 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005422 buffer->Rewind();
5423 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005424 uint16_t chr = buffer->GetNext();
5425 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 destination->Set(dest_position, '%');
5427 destination->Set(dest_position+1, 'u');
5428 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5429 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5430 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5431 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005433 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005434 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 dest_position++;
5436 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005437 destination->Set(dest_position, '%');
5438 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5439 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005440 dest_position += 3;
5441 }
5442 }
5443 return destination;
5444}
5445
5446
5447static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5448 static const signed char kHexValue['g'] = {
5449 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5450 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5451 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5452 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5453 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5454 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5455 -1, 10, 11, 12, 13, 14, 15 };
5456
5457 if (character1 > 'f') return -1;
5458 int hi = kHexValue[character1];
5459 if (hi == -1) return -1;
5460 if (character2 > 'f') return -1;
5461 int lo = kHexValue[character2];
5462 if (lo == -1) return -1;
5463 return (hi << 4) + lo;
5464}
5465
5466
ager@chromium.org870a0b62008-11-04 11:43:05 +00005467static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005468 int i,
5469 int length,
5470 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005471 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005472 int32_t hi = 0;
5473 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 if (character == '%' &&
5475 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 source->Get(i + 1) == 'u' &&
5477 (hi = TwoDigitHex(source->Get(i + 2),
5478 source->Get(i + 3))) != -1 &&
5479 (lo = TwoDigitHex(source->Get(i + 4),
5480 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 *step = 6;
5482 return (hi << 8) + lo;
5483 } else if (character == '%' &&
5484 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005485 (lo = TwoDigitHex(source->Get(i + 1),
5486 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487 *step = 3;
5488 return lo;
5489 } else {
5490 *step = 1;
5491 return character;
5492 }
5493}
5494
5495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005496RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 NoHandleAllocation ha;
5498 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005499 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005500
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005501 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502
5503 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005504 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505
5506 int unescaped_length = 0;
5507 for (int i = 0; i < length; unescaped_length++) {
5508 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512 i += step;
5513 }
5514
5515 // No length change implies no change. Return original string if no change.
5516 if (unescaped_length == length)
5517 return source;
5518
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005520 { MaybeObject* maybe_o =
5521 ascii ?
5522 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5523 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005524 if (!maybe_o->ToObject(&o)) return maybe_o;
5525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526 String* destination = String::cast(o);
5527
5528 int dest_position = 0;
5529 for (int i = 0; i < length; dest_position++) {
5530 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005531 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 i += step;
5533 }
5534 return destination;
5535}
5536
5537
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005538static const unsigned int kQuoteTableLength = 128u;
5539
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005540static const int kJsonQuotesCharactersPerEntry = 8;
5541static const char* const JsonQuotes =
5542 "\\u0000 \\u0001 \\u0002 \\u0003 "
5543 "\\u0004 \\u0005 \\u0006 \\u0007 "
5544 "\\b \\t \\n \\u000b "
5545 "\\f \\r \\u000e \\u000f "
5546 "\\u0010 \\u0011 \\u0012 \\u0013 "
5547 "\\u0014 \\u0015 \\u0016 \\u0017 "
5548 "\\u0018 \\u0019 \\u001a \\u001b "
5549 "\\u001c \\u001d \\u001e \\u001f "
5550 " ! \\\" # "
5551 "$ % & ' "
5552 "( ) * + "
5553 ", - . / "
5554 "0 1 2 3 "
5555 "4 5 6 7 "
5556 "8 9 : ; "
5557 "< = > ? "
5558 "@ A B C "
5559 "D E F G "
5560 "H I J K "
5561 "L M N O "
5562 "P Q R S "
5563 "T U V W "
5564 "X Y Z [ "
5565 "\\\\ ] ^ _ "
5566 "` a b c "
5567 "d e f g "
5568 "h i j k "
5569 "l m n o "
5570 "p q r s "
5571 "t u v w "
5572 "x y z { "
5573 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005574
5575
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005576// For a string that is less than 32k characters it should always be
5577// possible to allocate it in new space.
5578static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5579
5580
5581// Doing JSON quoting cannot make the string more than this many times larger.
5582static const int kJsonQuoteWorstCaseBlowup = 6;
5583
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005584static const int kSpaceForQuotesAndComma = 3;
5585static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005586
5587// Covers the entire ASCII range (all other characters are unchanged by JSON
5588// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005589static const byte JsonQuoteLengths[kQuoteTableLength] = {
5590 6, 6, 6, 6, 6, 6, 6, 6,
5591 2, 2, 2, 6, 2, 2, 6, 6,
5592 6, 6, 6, 6, 6, 6, 6, 6,
5593 6, 6, 6, 6, 6, 6, 6, 6,
5594 1, 1, 2, 1, 1, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597 1, 1, 1, 1, 1, 1, 1, 1,
5598 1, 1, 1, 1, 1, 1, 1, 1,
5599 1, 1, 1, 1, 1, 1, 1, 1,
5600 1, 1, 1, 1, 1, 1, 1, 1,
5601 1, 1, 1, 1, 2, 1, 1, 1,
5602 1, 1, 1, 1, 1, 1, 1, 1,
5603 1, 1, 1, 1, 1, 1, 1, 1,
5604 1, 1, 1, 1, 1, 1, 1, 1,
5605 1, 1, 1, 1, 1, 1, 1, 1,
5606};
5607
5608
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005609template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005610MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005611
5612
5613template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005614MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5615 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005616}
5617
5618
5619template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005620MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5621 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005622}
5623
5624
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005625template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5627 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005629 const Char* read_cursor = characters.start();
5630 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005631 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005632 int quoted_length = kSpaceForQuotes;
5633 while (read_cursor < end) {
5634 Char c = *(read_cursor++);
5635 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5636 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005638 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639 }
5640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005641 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5642 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005643 Object* new_object;
5644 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 return new_alloc;
5646 }
5647 StringType* new_string = StringType::cast(new_object);
5648
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005649 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005650 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005651 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005652 *(write_cursor++) = '"';
5653
5654 read_cursor = characters.start();
5655 while (read_cursor < end) {
5656 Char c = *(read_cursor++);
5657 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5658 *(write_cursor++) = c;
5659 } else {
5660 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5661 const char* replacement = JsonQuotes +
5662 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5663 for (int i = 0; i < len; i++) {
5664 *write_cursor++ = *replacement++;
5665 }
5666 }
5667 }
5668 *(write_cursor++) = '"';
5669 return new_string;
5670}
5671
5672
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005673template <typename SinkChar, typename SourceChar>
5674static inline SinkChar* WriteQuoteJsonString(
5675 Isolate* isolate,
5676 SinkChar* write_cursor,
5677 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005678 // SinkChar is only char if SourceChar is guaranteed to be char.
5679 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005680 const SourceChar* read_cursor = characters.start();
5681 const SourceChar* end = read_cursor + characters.length();
5682 *(write_cursor++) = '"';
5683 while (read_cursor < end) {
5684 SourceChar c = *(read_cursor++);
5685 if (sizeof(SourceChar) > 1u &&
5686 static_cast<unsigned>(c) >= kQuoteTableLength) {
5687 *(write_cursor++) = static_cast<SinkChar>(c);
5688 } else {
5689 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5690 const char* replacement = JsonQuotes +
5691 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5692 write_cursor[0] = replacement[0];
5693 if (len > 1) {
5694 write_cursor[1] = replacement[1];
5695 if (len > 2) {
5696 ASSERT(len == 6);
5697 write_cursor[2] = replacement[2];
5698 write_cursor[3] = replacement[3];
5699 write_cursor[4] = replacement[4];
5700 write_cursor[5] = replacement[5];
5701 }
5702 }
5703 write_cursor += len;
5704 }
5705 }
5706 *(write_cursor++) = '"';
5707 return write_cursor;
5708}
5709
5710
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005711template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005712static MaybeObject* QuoteJsonString(Isolate* isolate,
5713 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005714 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005715 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005716 int worst_case_length =
5717 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005718 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005719 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005720 }
5721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5723 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005724 Object* new_object;
5725 if (!new_alloc->ToObject(&new_object)) {
5726 return new_alloc;
5727 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005728 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005729 // Even if our string is small enough to fit in new space we still have to
5730 // handle it being allocated in old space as may happen in the third
5731 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5732 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005734 }
5735 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005737
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005738 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005739 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005740 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005741 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5742 write_cursor,
5743 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005744 int final_length = static_cast<int>(
5745 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005746 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005747 isolate->heap()->new_space()->
5748 template ShrinkStringAtAllocationBoundary<StringType>(
5749 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005750 return new_string;
5751}
5752
5753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005754RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005756 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005757 if (!str->IsFlat()) {
5758 MaybeObject* try_flatten = str->TryFlatten();
5759 Object* flat;
5760 if (!try_flatten->ToObject(&flat)) {
5761 return try_flatten;
5762 }
5763 str = String::cast(flat);
5764 ASSERT(str->IsFlat());
5765 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005766 String::FlatContent flat = str->GetFlatContent();
5767 ASSERT(flat.IsFlat());
5768 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005770 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005771 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005773 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005774 }
5775}
5776
5777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005778RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005779 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005780 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005781 if (!str->IsFlat()) {
5782 MaybeObject* try_flatten = str->TryFlatten();
5783 Object* flat;
5784 if (!try_flatten->ToObject(&flat)) {
5785 return try_flatten;
5786 }
5787 str = String::cast(flat);
5788 ASSERT(str->IsFlat());
5789 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005790 String::FlatContent flat = str->GetFlatContent();
5791 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005793 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005795 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005796 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005797 }
5798}
5799
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005800
5801template <typename Char, typename StringType>
5802static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5803 FixedArray* array,
5804 int worst_case_length) {
5805 int length = array->length();
5806
5807 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5808 worst_case_length);
5809 Object* new_object;
5810 if (!new_alloc->ToObject(&new_object)) {
5811 return new_alloc;
5812 }
5813 if (!isolate->heap()->new_space()->Contains(new_object)) {
5814 // Even if our string is small enough to fit in new space we still have to
5815 // handle it being allocated in old space as may happen in the third
5816 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5817 // CEntryStub::GenerateCore.
5818 return isolate->heap()->undefined_value();
5819 }
5820 AssertNoAllocation no_gc;
5821 StringType* new_string = StringType::cast(new_object);
5822 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5823
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005824 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005825 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005826 *(write_cursor++) = '[';
5827 for (int i = 0; i < length; i++) {
5828 if (i != 0) *(write_cursor++) = ',';
5829 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 String::FlatContent content = str->GetFlatContent();
5831 ASSERT(content.IsFlat());
5832 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005833 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5834 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005835 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005836 } else {
5837 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5838 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005839 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005840 }
5841 }
5842 *(write_cursor++) = ']';
5843
5844 int final_length = static_cast<int>(
5845 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005846 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005847 isolate->heap()->new_space()->
5848 template ShrinkStringAtAllocationBoundary<StringType>(
5849 new_string, final_length);
5850 return new_string;
5851}
5852
5853
5854RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5855 NoHandleAllocation ha;
5856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005857 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005858
5859 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5860 FixedArray* elements = FixedArray::cast(array->elements());
5861 int n = elements->length();
5862 bool ascii = true;
5863 int total_length = 0;
5864
5865 for (int i = 0; i < n; i++) {
5866 Object* elt = elements->get(i);
5867 if (!elt->IsString()) return isolate->heap()->undefined_value();
5868 String* element = String::cast(elt);
5869 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5870 total_length += element->length();
5871 if (ascii && element->IsTwoByteRepresentation()) {
5872 ascii = false;
5873 }
5874 }
5875
5876 int worst_case_length =
5877 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5878 + total_length * kJsonQuoteWorstCaseBlowup;
5879
5880 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5881 return isolate->heap()->undefined_value();
5882 }
5883
5884 if (ascii) {
5885 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5886 elements,
5887 worst_case_length);
5888 } else {
5889 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5890 elements,
5891 worst_case_length);
5892 }
5893}
5894
5895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005896RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897 NoHandleAllocation ha;
5898
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005899 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005900 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005902 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903
lrn@chromium.org25156de2010-04-06 13:10:27 +00005904 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005905 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005906 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005907}
5908
5909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005910RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005912 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913
5914 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005915 double value = StringToDouble(isolate->unicode_cache(),
5916 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917
5918 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920}
5921
5922
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005923template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005924MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005925 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005926 String* s,
5927 int length,
5928 int input_string_length,
5929 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005930 // We try this twice, once with the assumption that the result is no longer
5931 // than the input and, if that assumption breaks, again with the exact
5932 // length. This may not be pretty, but it is nicer than what was here before
5933 // and I hereby claim my vaffel-is.
5934 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935 // Allocate the resulting string.
5936 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005937 // NOTE: This assumes that the upper/lower case of an ASCII
5938 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 // might break in the future if we implement more context and locale
5940 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941 Object* o;
5942 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005943 ? isolate->heap()->AllocateRawAsciiString(length)
5944 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005945 if (!maybe_o->ToObject(&o)) return maybe_o;
5946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947 String* result = String::cast(o);
5948 bool has_changed_character = false;
5949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 // Convert all characters to upper case, assuming that they will fit
5951 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005952 Access<StringInputBuffer> buffer(
5953 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005955 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 // We can assume that the string is not empty
5957 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005959 bool has_next = buffer->has_more();
5960 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 int char_length = mapping->get(current, next, chars);
5962 if (char_length == 0) {
5963 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005964 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965 i++;
5966 } else if (char_length == 1) {
5967 // Common case: converting the letter resulted in one character.
5968 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005969 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 has_changed_character = true;
5971 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005972 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 // We've assumed that the result would be as long as the
5974 // input but here is a character that converts to several
5975 // characters. No matter, we calculate the exact length
5976 // of the result and try the whole thing again.
5977 //
5978 // Note that this leaves room for optimization. We could just
5979 // memcpy what we already have to the result string. Also,
5980 // the result string is the last object allocated we could
5981 // "realloc" it and probably, in the vast majority of cases,
5982 // extend the existing string to be able to hold the full
5983 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005984 int next_length = 0;
5985 if (has_next) {
5986 next_length = mapping->get(next, 0, chars);
5987 if (next_length == 0) next_length = 1;
5988 }
5989 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 while (buffer->has_more()) {
5991 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005992 // NOTE: we use 0 as the next character here because, while
5993 // the next character may affect what a character converts to,
5994 // it does not in any case affect the length of what it convert
5995 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996 int char_length = mapping->get(current, 0, chars);
5997 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005998 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005999 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006001 return Failure::OutOfMemoryException();
6002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006004 // Try again with the real length.
6005 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006 } else {
6007 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006008 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009 i++;
6010 }
6011 has_changed_character = true;
6012 }
6013 current = next;
6014 }
6015 if (has_changed_character) {
6016 return result;
6017 } else {
6018 // If we didn't actually change anything in doing the conversion
6019 // we simple return the result and let the converted string
6020 // become garbage; there is no reason to keep two identical strings
6021 // alive.
6022 return s;
6023 }
6024}
6025
6026
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006027namespace {
6028
lrn@chromium.org303ada72010-10-27 09:33:13 +00006029static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6030
6031
6032// Given a word and two range boundaries returns a word with high bit
6033// set in every byte iff the corresponding input byte was strictly in
6034// the range (m, n). All the other bits in the result are cleared.
6035// This function is only useful when it can be inlined and the
6036// boundaries are statically known.
6037// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006038// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006039static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006040 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006041 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6042 // Use strict inequalities since in edge cases the function could be
6043 // further simplified.
6044 ASSERT(0 < m && m < n && n < 0x7F);
6045 // Has high bit set in every w byte less than n.
6046 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6047 // Has high bit set in every w byte greater than m.
6048 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6049 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6050}
6051
6052
6053enum AsciiCaseConversion {
6054 ASCII_TO_LOWER,
6055 ASCII_TO_UPPER
6056};
6057
6058
6059template <AsciiCaseConversion dir>
6060struct FastAsciiConverter {
6061 static bool Convert(char* dst, char* src, int length) {
6062#ifdef DEBUG
6063 char* saved_dst = dst;
6064 char* saved_src = src;
6065#endif
6066 // We rely on the distance between upper and lower case letters
6067 // being a known power of 2.
6068 ASSERT('a' - 'A' == (1 << 5));
6069 // Boundaries for the range of input characters than require conversion.
6070 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6071 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6072 bool changed = false;
6073 char* const limit = src + length;
6074#ifdef V8_HOST_CAN_READ_UNALIGNED
6075 // Process the prefix of the input that requires no conversion one
6076 // (machine) word at a time.
6077 while (src <= limit - sizeof(uintptr_t)) {
6078 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6079 if (AsciiRangeMask(w, lo, hi) != 0) {
6080 changed = true;
6081 break;
6082 }
6083 *reinterpret_cast<uintptr_t*>(dst) = w;
6084 src += sizeof(uintptr_t);
6085 dst += sizeof(uintptr_t);
6086 }
6087 // Process the remainder of the input performing conversion when
6088 // required one word at a time.
6089 while (src <= limit - sizeof(uintptr_t)) {
6090 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6091 uintptr_t m = AsciiRangeMask(w, lo, hi);
6092 // The mask has high (7th) bit set in every byte that needs
6093 // conversion and we know that the distance between cases is
6094 // 1 << 5.
6095 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6096 src += sizeof(uintptr_t);
6097 dst += sizeof(uintptr_t);
6098 }
6099#endif
6100 // Process the last few bytes of the input (or the whole input if
6101 // unaligned access is not supported).
6102 while (src < limit) {
6103 char c = *src;
6104 if (lo < c && c < hi) {
6105 c ^= (1 << 5);
6106 changed = true;
6107 }
6108 *dst = c;
6109 ++src;
6110 ++dst;
6111 }
6112#ifdef DEBUG
6113 CheckConvert(saved_dst, saved_src, length, changed);
6114#endif
6115 return changed;
6116 }
6117
6118#ifdef DEBUG
6119 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6120 bool expected_changed = false;
6121 for (int i = 0; i < length; i++) {
6122 if (dst[i] == src[i]) continue;
6123 expected_changed = true;
6124 if (dir == ASCII_TO_LOWER) {
6125 ASSERT('A' <= src[i] && src[i] <= 'Z');
6126 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6127 } else {
6128 ASSERT(dir == ASCII_TO_UPPER);
6129 ASSERT('a' <= src[i] && src[i] <= 'z');
6130 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6131 }
6132 }
6133 ASSERT(expected_changed == changed);
6134 }
6135#endif
6136};
6137
6138
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006139struct ToLowerTraits {
6140 typedef unibrow::ToLowercase UnibrowConverter;
6141
lrn@chromium.org303ada72010-10-27 09:33:13 +00006142 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006143};
6144
6145
6146struct ToUpperTraits {
6147 typedef unibrow::ToUppercase UnibrowConverter;
6148
lrn@chromium.org303ada72010-10-27 09:33:13 +00006149 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006150};
6151
6152} // namespace
6153
6154
6155template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006156MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006158 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006159 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006160 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006161 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006162 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006163
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006165 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006166 if (length == 0) return s;
6167
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006168 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006169 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006170 // NOTE: This assumes that the upper/lower case of an ASCII
6171 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006172 // might break in the future if we implement more context and locale
6173 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006174 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006175 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006176 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177 if (!maybe_o->ToObject(&o)) return maybe_o;
6178 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006179 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006181 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006182 return has_changed_character ? result : s;
6183 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006184
lrn@chromium.org303ada72010-10-27 09:33:13 +00006185 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006186 { MaybeObject* maybe_answer =
6187 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006188 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6189 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006190 if (answer->IsSmi()) {
6191 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 ConvertCaseHelper(isolate,
6194 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006195 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6196 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006197 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006198 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006199}
6200
6201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006202RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006203 return ConvertCase<ToLowerTraits>(
6204 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006205}
6206
6207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006208RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006209 return ConvertCase<ToUpperTraits>(
6210 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006211}
6212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006213
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006214static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006215 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006216}
6217
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006220 NoHandleAllocation ha;
6221 ASSERT(args.length() == 3);
6222
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006223 CONVERT_ARG_CHECKED(String, s, 0);
6224 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6225 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006226
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006227 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006228 int length = s->length();
6229
6230 int left = 0;
6231 if (trimLeft) {
6232 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6233 left++;
6234 }
6235 }
6236
6237 int right = length;
6238 if (trimRight) {
6239 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6240 right--;
6241 }
6242 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006243 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006244}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006247RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006248 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006249 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006250 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6251 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006252 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6253
6254 int subject_length = subject->length();
6255 int pattern_length = pattern->length();
6256 RUNTIME_ASSERT(pattern_length > 0);
6257
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006258 if (limit == 0xffffffffu) {
6259 Handle<Object> cached_answer(StringSplitCache::Lookup(
6260 isolate->heap()->string_split_cache(),
6261 *subject,
6262 *pattern));
6263 if (*cached_answer != Smi::FromInt(0)) {
6264 Handle<JSArray> result =
6265 isolate->factory()->NewJSArrayWithElements(
6266 Handle<FixedArray>::cast(cached_answer));
6267 return *result;
6268 }
6269 }
6270
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006271 // The limit can be very large (0xffffffffu), but since the pattern
6272 // isn't empty, we can never create more parts than ~half the length
6273 // of the subject.
6274
6275 if (!subject->IsFlat()) FlattenString(subject);
6276
6277 static const int kMaxInitialListCapacity = 16;
6278
danno@chromium.org40cb8782011-05-25 07:58:50 +00006279 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006280
6281 // Find (up to limit) indices of separator and end-of-string in subject
6282 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6283 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006284 if (!pattern->IsFlat()) FlattenString(pattern);
6285
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006286 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006287
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006288 if (static_cast<uint32_t>(indices.length()) < limit) {
6289 indices.Add(subject_length);
6290 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006291
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006292 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006293
6294 // Create JSArray of substrings separated by separator.
6295 int part_count = indices.length();
6296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006297 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006298 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006299 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006300 result->set_length(Smi::FromInt(part_count));
6301
6302 ASSERT(result->HasFastElements());
6303
6304 if (part_count == 1 && indices.at(0) == subject_length) {
6305 FixedArray::cast(result->elements())->set(0, *subject);
6306 return *result;
6307 }
6308
6309 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6310 int part_start = 0;
6311 for (int i = 0; i < part_count; i++) {
6312 HandleScope local_loop_handle;
6313 int part_end = indices.at(i);
6314 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006315 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006316 elements->set(i, *substring);
6317 part_start = part_end + pattern_length;
6318 }
6319
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006320 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006321 if (result->HasFastElements()) {
6322 StringSplitCache::Enter(isolate->heap(),
6323 isolate->heap()->string_split_cache(),
6324 *subject,
6325 *pattern,
6326 *elements);
6327 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006328 }
6329
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006330 return *result;
6331}
6332
6333
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006334// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006335// one-char strings in the cache. Gives up on the first char that is
6336// not in the cache and fills the remainder with smi zeros. Returns
6337// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006338static int CopyCachedAsciiCharsToArray(Heap* heap,
6339 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006340 FixedArray* elements,
6341 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006342 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343 FixedArray* ascii_cache = heap->single_character_string_cache();
6344 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006345 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006346 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006347 for (i = 0; i < length; ++i) {
6348 Object* value = ascii_cache->get(chars[i]);
6349 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006350 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006351 }
6352 if (i < length) {
6353 ASSERT(Smi::FromInt(0) == 0);
6354 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6355 }
6356#ifdef DEBUG
6357 for (int j = 0; j < length; ++j) {
6358 Object* element = elements->get(j);
6359 ASSERT(element == Smi::FromInt(0) ||
6360 (element->IsString() && String::cast(element)->LooksValid()));
6361 }
6362#endif
6363 return i;
6364}
6365
6366
6367// Converts a String to JSArray.
6368// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006369RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006370 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006371 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006372 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006373 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006374
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006375 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006376 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006377
6378 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006379 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006380 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006381 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006382 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006383 { MaybeObject* maybe_obj =
6384 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006385 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006387 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006388 String::FlatContent content = s->GetFlatContent();
6389 if (content.IsAscii()) {
6390 Vector<const char> chars = content.ToAsciiVector();
6391 // Note, this will initialize all elements (not only the prefix)
6392 // to prevent GC from seeing partially initialized array.
6393 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6394 chars.start(),
6395 *elements,
6396 length);
6397 } else {
6398 MemsetPointer(elements->data_start(),
6399 isolate->heap()->undefined_value(),
6400 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 }
6402 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006403 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006404 }
6405 for (int i = position; i < length; ++i) {
6406 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6407 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408 }
6409
6410#ifdef DEBUG
6411 for (int i = 0; i < length; ++i) {
6412 ASSERT(String::cast(elements->get(i))->length() == 1);
6413 }
6414#endif
6415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006417}
6418
6419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006420RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006421 NoHandleAllocation ha;
6422 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006423 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006424 return value->ToObject();
6425}
6426
6427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006429 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006431 return char_length == 0;
6432}
6433
6434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006435RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436 NoHandleAllocation ha;
6437 ASSERT(args.length() == 1);
6438
6439 Object* number = args[0];
6440 RUNTIME_ASSERT(number->IsNumber());
6441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443}
6444
6445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006446RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006447 NoHandleAllocation ha;
6448 ASSERT(args.length() == 1);
6449
6450 Object* number = args[0];
6451 RUNTIME_ASSERT(number->IsNumber());
6452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006454}
6455
6456
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006457RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006458 NoHandleAllocation ha;
6459 ASSERT(args.length() == 1);
6460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006461 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006462
6463 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6464 if (number > 0 && number <= Smi::kMaxValue) {
6465 return Smi::FromInt(static_cast<int>(number));
6466 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468}
6469
6470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006471RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006472 NoHandleAllocation ha;
6473 ASSERT(args.length() == 1);
6474
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006475 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006476
6477 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6478 if (number > 0 && number <= Smi::kMaxValue) {
6479 return Smi::FromInt(static_cast<int>(number));
6480 }
6481
6482 double double_value = DoubleToInteger(number);
6483 // Map both -0 and +0 to +0.
6484 if (double_value == 0) double_value = 0;
6485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006486 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006487}
6488
6489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006490RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491 NoHandleAllocation ha;
6492 ASSERT(args.length() == 1);
6493
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006494 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006495 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496}
6497
6498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006499RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500 NoHandleAllocation ha;
6501 ASSERT(args.length() == 1);
6502
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006503 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006504
6505 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6506 if (number > 0 && number <= Smi::kMaxValue) {
6507 return Smi::FromInt(static_cast<int>(number));
6508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006510}
6511
6512
ager@chromium.org870a0b62008-11-04 11:43:05 +00006513// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6514// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006515RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006516 NoHandleAllocation ha;
6517 ASSERT(args.length() == 1);
6518
6519 Object* obj = args[0];
6520 if (obj->IsSmi()) {
6521 return obj;
6522 }
6523 if (obj->IsHeapNumber()) {
6524 double value = HeapNumber::cast(obj)->value();
6525 int int_value = FastD2I(value);
6526 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6527 return Smi::FromInt(int_value);
6528 }
6529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006531}
6532
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006534RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006535 NoHandleAllocation ha;
6536 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006537 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006538}
6539
6540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006541RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542 NoHandleAllocation ha;
6543 ASSERT(args.length() == 2);
6544
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006545 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6546 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006547 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548}
6549
6550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006551RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 2);
6554
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006555 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6556 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006557 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558}
6559
6560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006561RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562 NoHandleAllocation ha;
6563 ASSERT(args.length() == 2);
6564
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006565 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6566 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568}
6569
6570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 NoHandleAllocation ha;
6573 ASSERT(args.length() == 1);
6574
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006575 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577}
6578
6579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006580RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006581 NoHandleAllocation ha;
6582 ASSERT(args.length() == 0);
6583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006585}
6586
6587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 2);
6591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6593 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595}
6596
6597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 NoHandleAllocation ha;
6600 ASSERT(args.length() == 2);
6601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6603 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604
ager@chromium.org3811b432009-10-28 14:53:37 +00006605 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006606 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006608}
6609
6610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006611RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 NoHandleAllocation ha;
6613 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006614 CONVERT_ARG_CHECKED(String, str1, 0);
6615 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006616 isolate->counters()->string_add_runtime()->Increment();
6617 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618}
6619
6620
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006621template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006622static inline void StringBuilderConcatHelper(String* special,
6623 sinkchar* sink,
6624 FixedArray* fixed_array,
6625 int array_length) {
6626 int position = 0;
6627 for (int i = 0; i < array_length; i++) {
6628 Object* element = fixed_array->get(i);
6629 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006630 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006631 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006632 int pos;
6633 int len;
6634 if (encoded_slice > 0) {
6635 // Position and length encoded in one smi.
6636 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6637 len = StringBuilderSubstringLength::decode(encoded_slice);
6638 } else {
6639 // Position and length encoded in two smis.
6640 Object* obj = fixed_array->get(++i);
6641 ASSERT(obj->IsSmi());
6642 pos = Smi::cast(obj)->value();
6643 len = -encoded_slice;
6644 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006645 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006646 sink + position,
6647 pos,
6648 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006649 position += len;
6650 } else {
6651 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006652 int element_length = string->length();
6653 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006654 position += element_length;
6655 }
6656 }
6657}
6658
6659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006662 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006663 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006664 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006665 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006666 return Failure::OutOfMemoryException();
6667 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006668 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006669 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006670
6671 // This assumption is used by the slice encoding in one or two smis.
6672 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6673
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006674 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006675 if (maybe_result->IsFailure()) return maybe_result;
6676
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006677 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 }
6681 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006682 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006684 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685
6686 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006687 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 } else if (array_length == 1) {
6689 Object* first = fixed_array->get(0);
6690 if (first->IsString()) return first;
6691 }
6692
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006693 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694 int position = 0;
6695 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006696 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 Object* elt = fixed_array->get(i);
6698 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006699 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006700 int smi_value = Smi::cast(elt)->value();
6701 int pos;
6702 int len;
6703 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006705 pos = StringBuilderSubstringPosition::decode(smi_value);
6706 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006707 } else {
6708 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006709 len = -smi_value;
6710 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006711 i++;
6712 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006714 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006715 Object* next_smi = fixed_array->get(i);
6716 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006717 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006718 }
6719 pos = Smi::cast(next_smi)->value();
6720 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006722 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006724 ASSERT(pos >= 0);
6725 ASSERT(len >= 0);
6726 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006728 }
6729 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 } else if (elt->IsString()) {
6731 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006732 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006733 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006734 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006740 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006741 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006742 return Failure::OutOfMemoryException();
6743 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006744 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 }
6746
6747 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 { MaybeObject* maybe_object =
6752 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006753 if (!maybe_object->ToObject(&object)) return maybe_object;
6754 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006755 SeqAsciiString* answer = SeqAsciiString::cast(object);
6756 StringBuilderConcatHelper(special,
6757 answer->GetChars(),
6758 fixed_array,
6759 array_length);
6760 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006762 { MaybeObject* maybe_object =
6763 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006764 if (!maybe_object->ToObject(&object)) return maybe_object;
6765 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006766 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6767 StringBuilderConcatHelper(special,
6768 answer->GetChars(),
6769 fixed_array,
6770 array_length);
6771 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773}
6774
6775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006776RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006777 NoHandleAllocation ha;
6778 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006779 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006780 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006782 return Failure::OutOfMemoryException();
6783 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006784 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006785 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006786
6787 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006789 }
6790 FixedArray* fixed_array = FixedArray::cast(array->elements());
6791 if (fixed_array->length() < array_length) {
6792 array_length = fixed_array->length();
6793 }
6794
6795 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006796 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006797 } else if (array_length == 1) {
6798 Object* first = fixed_array->get(0);
6799 if (first->IsString()) return first;
6800 }
6801
6802 int separator_length = separator->length();
6803 int max_nof_separators =
6804 (String::kMaxLength + separator_length - 1) / separator_length;
6805 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 return Failure::OutOfMemoryException();
6808 }
6809 int length = (array_length - 1) * separator_length;
6810 for (int i = 0; i < array_length; i++) {
6811 Object* element_obj = fixed_array->get(i);
6812 if (!element_obj->IsString()) {
6813 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006815 }
6816 String* element = String::cast(element_obj);
6817 int increment = element->length();
6818 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006820 return Failure::OutOfMemoryException();
6821 }
6822 length += increment;
6823 }
6824
6825 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006826 { MaybeObject* maybe_object =
6827 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006828 if (!maybe_object->ToObject(&object)) return maybe_object;
6829 }
6830 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6831
6832 uc16* sink = answer->GetChars();
6833#ifdef DEBUG
6834 uc16* end = sink + length;
6835#endif
6836
6837 String* first = String::cast(fixed_array->get(0));
6838 int first_length = first->length();
6839 String::WriteToFlat(first, sink, 0, first_length);
6840 sink += first_length;
6841
6842 for (int i = 1; i < array_length; i++) {
6843 ASSERT(sink + separator_length <= end);
6844 String::WriteToFlat(separator, sink, 0, separator_length);
6845 sink += separator_length;
6846
6847 String* element = String::cast(fixed_array->get(i));
6848 int element_length = element->length();
6849 ASSERT(sink + element_length <= end);
6850 String::WriteToFlat(element, sink, 0, element_length);
6851 sink += element_length;
6852 }
6853 ASSERT(sink == end);
6854
6855 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6856 return answer;
6857}
6858
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006859template <typename Char>
6860static void JoinSparseArrayWithSeparator(FixedArray* elements,
6861 int elements_length,
6862 uint32_t array_length,
6863 String* separator,
6864 Vector<Char> buffer) {
6865 int previous_separator_position = 0;
6866 int separator_length = separator->length();
6867 int cursor = 0;
6868 for (int i = 0; i < elements_length; i += 2) {
6869 int position = NumberToInt32(elements->get(i));
6870 String* string = String::cast(elements->get(i + 1));
6871 int string_length = string->length();
6872 if (string->length() > 0) {
6873 while (previous_separator_position < position) {
6874 String::WriteToFlat<Char>(separator, &buffer[cursor],
6875 0, separator_length);
6876 cursor += separator_length;
6877 previous_separator_position++;
6878 }
6879 String::WriteToFlat<Char>(string, &buffer[cursor],
6880 0, string_length);
6881 cursor += string->length();
6882 }
6883 }
6884 if (separator_length > 0) {
6885 // Array length must be representable as a signed 32-bit number,
6886 // otherwise the total string length would have been too large.
6887 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6888 int last_array_index = static_cast<int>(array_length - 1);
6889 while (previous_separator_position < last_array_index) {
6890 String::WriteToFlat<Char>(separator, &buffer[cursor],
6891 0, separator_length);
6892 cursor += separator_length;
6893 previous_separator_position++;
6894 }
6895 }
6896 ASSERT(cursor <= buffer.length());
6897}
6898
6899
6900RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6901 NoHandleAllocation ha;
6902 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006903 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006904 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6905 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006906 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006907 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006908 // elements_array is fast-mode JSarray of alternating positions
6909 // (increasing order) and strings.
6910 // array_length is length of original array (used to add separators);
6911 // separator is string to put between elements. Assumed to be non-empty.
6912
6913 // Find total length of join result.
6914 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006915 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006916 int max_string_length;
6917 if (is_ascii) {
6918 max_string_length = SeqAsciiString::kMaxLength;
6919 } else {
6920 max_string_length = SeqTwoByteString::kMaxLength;
6921 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006922 bool overflow = false;
6923 CONVERT_NUMBER_CHECKED(int, elements_length,
6924 Int32, elements_array->length());
6925 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6926 FixedArray* elements = FixedArray::cast(elements_array->elements());
6927 for (int i = 0; i < elements_length; i += 2) {
6928 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006929 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6930 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006931 int length = string->length();
6932 if (is_ascii && !string->IsAsciiRepresentation()) {
6933 is_ascii = false;
6934 max_string_length = SeqTwoByteString::kMaxLength;
6935 }
6936 if (length > max_string_length ||
6937 max_string_length - length < string_length) {
6938 overflow = true;
6939 break;
6940 }
6941 string_length += length;
6942 }
6943 int separator_length = separator->length();
6944 if (!overflow && separator_length > 0) {
6945 if (array_length <= 0x7fffffffu) {
6946 int separator_count = static_cast<int>(array_length) - 1;
6947 int remaining_length = max_string_length - string_length;
6948 if ((remaining_length / separator_length) >= separator_count) {
6949 string_length += separator_length * (array_length - 1);
6950 } else {
6951 // Not room for the separators within the maximal string length.
6952 overflow = true;
6953 }
6954 } else {
6955 // Nonempty separator and at least 2^31-1 separators necessary
6956 // means that the string is too large to create.
6957 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6958 overflow = true;
6959 }
6960 }
6961 if (overflow) {
6962 // Throw OutOfMemory exception for creating too large a string.
6963 V8::FatalProcessOutOfMemory("Array join result too large.");
6964 }
6965
6966 if (is_ascii) {
6967 MaybeObject* result_allocation =
6968 isolate->heap()->AllocateRawAsciiString(string_length);
6969 if (result_allocation->IsFailure()) return result_allocation;
6970 SeqAsciiString* result_string =
6971 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6972 JoinSparseArrayWithSeparator<char>(elements,
6973 elements_length,
6974 array_length,
6975 separator,
6976 Vector<char>(result_string->GetChars(),
6977 string_length));
6978 return result_string;
6979 } else {
6980 MaybeObject* result_allocation =
6981 isolate->heap()->AllocateRawTwoByteString(string_length);
6982 if (result_allocation->IsFailure()) return result_allocation;
6983 SeqTwoByteString* result_string =
6984 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6985 JoinSparseArrayWithSeparator<uc16>(elements,
6986 elements_length,
6987 array_length,
6988 separator,
6989 Vector<uc16>(result_string->GetChars(),
6990 string_length));
6991 return result_string;
6992 }
6993}
6994
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006996RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997 NoHandleAllocation ha;
6998 ASSERT(args.length() == 2);
6999
7000 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7001 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007002 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003}
7004
7005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007006RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 NoHandleAllocation ha;
7008 ASSERT(args.length() == 2);
7009
7010 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7011 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007012 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007013}
7014
7015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007016RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017 NoHandleAllocation ha;
7018 ASSERT(args.length() == 2);
7019
7020 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7021 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 NoHandleAllocation ha;
7028 ASSERT(args.length() == 1);
7029
7030 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032}
7033
7034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 NoHandleAllocation ha;
7037 ASSERT(args.length() == 2);
7038
7039 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7040 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007041 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042}
7043
7044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007045RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 2);
7048
7049 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7050 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052}
7053
7054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007055RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056 NoHandleAllocation ha;
7057 ASSERT(args.length() == 2);
7058
7059 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7060 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007061 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062}
7063
7064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007065RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 NoHandleAllocation ha;
7067 ASSERT(args.length() == 2);
7068
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007069 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7070 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7072 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7073 if (x == y) return Smi::FromInt(EQUAL);
7074 Object* result;
7075 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7076 result = Smi::FromInt(EQUAL);
7077 } else {
7078 result = Smi::FromInt(NOT_EQUAL);
7079 }
7080 return result;
7081}
7082
7083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007084RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007085 NoHandleAllocation ha;
7086 ASSERT(args.length() == 2);
7087
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007088 CONVERT_ARG_CHECKED(String, x, 0);
7089 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007091 bool not_equal = !x->Equals(y);
7092 // This is slightly convoluted because the value that signifies
7093 // equality is 0 and inequality is 1 so we have to negate the result
7094 // from String::Equals.
7095 ASSERT(not_equal == 0 || not_equal == 1);
7096 STATIC_CHECK(EQUAL == 0);
7097 STATIC_CHECK(NOT_EQUAL == 1);
7098 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 3);
7105
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007106 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7107 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108 if (isnan(x) || isnan(y)) return args[2];
7109 if (x == y) return Smi::FromInt(EQUAL);
7110 if (isless(x, y)) return Smi::FromInt(LESS);
7111 return Smi::FromInt(GREATER);
7112}
7113
7114
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007115// Compare two Smis as if they were converted to strings and then
7116// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007117RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007118 NoHandleAllocation ha;
7119 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007120 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7121 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007122
7123 // If the integers are equal so are the string representations.
7124 if (x_value == y_value) return Smi::FromInt(EQUAL);
7125
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007126 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007127 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007128 if (x_value == 0 || y_value == 0)
7129 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007130
ager@chromium.org32912102009-01-16 10:38:43 +00007131 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007132 // smallest because the char code of '-' is less than the char code
7133 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007134
7135 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7136 // architectures using 32-bit Smis.
7137 uint32_t x_scaled = x_value;
7138 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007139 if (x_value < 0 || y_value < 0) {
7140 if (y_value >= 0) return Smi::FromInt(LESS);
7141 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007142 x_scaled = -x_value;
7143 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007144 }
7145
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 static const uint32_t kPowersOf10[] = {
7147 1, 10, 100, 1000, 10*1000, 100*1000,
7148 1000*1000, 10*1000*1000, 100*1000*1000,
7149 1000*1000*1000
7150 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007152 // If the integers have the same number of decimal digits they can be
7153 // compared directly as the numeric order is the same as the
7154 // lexicographic order. If one integer has fewer digits, it is scaled
7155 // by some power of 10 to have the same number of digits as the longer
7156 // integer. If the scaled integers are equal it means the shorter
7157 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007158
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007159 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7160 int x_log2 = IntegerLog2(x_scaled);
7161 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7162 x_log10 -= x_scaled < kPowersOf10[x_log10];
7163
7164 int y_log2 = IntegerLog2(y_scaled);
7165 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7166 y_log10 -= y_scaled < kPowersOf10[y_log10];
7167
7168 int tie = EQUAL;
7169
7170 if (x_log10 < y_log10) {
7171 // X has fewer digits. We would like to simply scale up X but that
7172 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7173 // be scaled up to 9_000_000_000. So we scale up by the next
7174 // smallest power and scale down Y to drop one digit. It is OK to
7175 // drop one digit from the longer integer since the final digit is
7176 // past the length of the shorter integer.
7177 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7178 y_scaled /= 10;
7179 tie = LESS;
7180 } else if (y_log10 < x_log10) {
7181 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7182 x_scaled /= 10;
7183 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007184 }
7185
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007186 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7187 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7188 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007189}
7190
7191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192static Object* StringInputBufferCompare(RuntimeState* state,
7193 String* x,
7194 String* y) {
7195 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7196 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007197 bufx.Reset(x);
7198 bufy.Reset(y);
7199 while (bufx.has_more() && bufy.has_more()) {
7200 int d = bufx.GetNext() - bufy.GetNext();
7201 if (d < 0) return Smi::FromInt(LESS);
7202 else if (d > 0) return Smi::FromInt(GREATER);
7203 }
7204
7205 // x is (non-trivial) prefix of y:
7206 if (bufy.has_more()) return Smi::FromInt(LESS);
7207 // y is prefix of x:
7208 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7209}
7210
7211
7212static Object* FlatStringCompare(String* x, String* y) {
7213 ASSERT(x->IsFlat());
7214 ASSERT(y->IsFlat());
7215 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7216 int prefix_length = x->length();
7217 if (y->length() < prefix_length) {
7218 prefix_length = y->length();
7219 equal_prefix_result = Smi::FromInt(GREATER);
7220 } else if (y->length() > prefix_length) {
7221 equal_prefix_result = Smi::FromInt(LESS);
7222 }
7223 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007224 String::FlatContent x_content = x->GetFlatContent();
7225 String::FlatContent y_content = y->GetFlatContent();
7226 if (x_content.IsAscii()) {
7227 Vector<const char> x_chars = x_content.ToAsciiVector();
7228 if (y_content.IsAscii()) {
7229 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007230 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007231 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007232 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007233 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7234 }
7235 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007236 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7237 if (y_content.IsAscii()) {
7238 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007239 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7240 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007241 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007242 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7243 }
7244 }
7245 Object* result;
7246 if (r == 0) {
7247 result = equal_prefix_result;
7248 } else {
7249 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7250 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007251 ASSERT(result ==
7252 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007253 return result;
7254}
7255
7256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007257RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258 NoHandleAllocation ha;
7259 ASSERT(args.length() == 2);
7260
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007261 CONVERT_ARG_CHECKED(String, x, 0);
7262 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007263
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 // A few fast case tests before we flatten.
7267 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007268 if (y->length() == 0) {
7269 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007271 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272 return Smi::FromInt(LESS);
7273 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007274
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007275 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007276 if (d < 0) return Smi::FromInt(LESS);
7277 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278
lrn@chromium.org303ada72010-10-27 09:33:13 +00007279 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007280 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007281 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7282 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007283 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007284 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007287 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289}
7290
7291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007292RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007293 NoHandleAllocation ha;
7294 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007297 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007299}
7300
7301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007302RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303 NoHandleAllocation ha;
7304 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007307 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007308 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309}
7310
7311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007312RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 NoHandleAllocation ha;
7314 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319}
7320
7321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322static const double kPiDividedBy4 = 0.78539816339744830962;
7323
7324
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007325RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326 NoHandleAllocation ha;
7327 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007329
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007330 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7331 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332 double result;
7333 if (isinf(x) && isinf(y)) {
7334 // Make sure that the result in case of two infinite arguments
7335 // is a multiple of Pi / 4. The sign of the result is determined
7336 // by the first argument (x) and the sign of the second argument
7337 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338 int multiplier = (x < 0) ? -1 : 1;
7339 if (y < 0) multiplier *= 3;
7340 result = multiplier * kPiDividedBy4;
7341 } else {
7342 result = atan2(x, y);
7343 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007345}
7346
7347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007348RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 NoHandleAllocation ha;
7350 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007351 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007352
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007353 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355}
7356
7357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007358RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359 NoHandleAllocation ha;
7360 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007363 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365}
7366
7367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 NoHandleAllocation ha;
7370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007373 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375}
7376
7377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007378RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007383 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007388RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389 NoHandleAllocation ha;
7390 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007393 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007397// Slow version of Math.pow. We check for fast paths for special cases.
7398// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007399RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 NoHandleAllocation ha;
7401 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007405
7406 // If the second argument is a smi, it is much faster to call the
7407 // custom powi() function than the generic pow().
7408 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007409 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007411 }
7412
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007413 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007414 int y_int = static_cast<int>(y);
7415 double result;
7416 if (y == y_int) {
7417 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7418 } else if (y == 0.5) {
7419 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7420 } else if (y == -0.5) {
7421 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7422 } else {
7423 result = power_double_double(x, y);
7424 }
7425 if (isnan(result)) return isolate->heap()->nan_value();
7426 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427}
7428
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007429// 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 +00007430// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007431RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007432 NoHandleAllocation ha;
7433 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007434 isolate->counters()->math_pow()->Increment();
7435
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007436 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7437 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007438 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007439 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007440 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007441 double result = power_double_double(x, y);
7442 if (isnan(result)) return isolate->heap()->nan_value();
7443 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007444 }
7445}
7446
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007448RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 NoHandleAllocation ha;
7450 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007451 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007453 if (!args[0]->IsHeapNumber()) {
7454 // Must be smi. Return the argument unchanged for all the other types
7455 // to make fuzz-natives test happy.
7456 return args[0];
7457 }
7458
7459 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7460
7461 double value = number->value();
7462 int exponent = number->get_exponent();
7463 int sign = number->get_sign();
7464
danno@chromium.org160a7b02011-04-18 15:51:38 +00007465 if (exponent < -1) {
7466 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7467 if (sign) return isolate->heap()->minus_zero_value();
7468 return Smi::FromInt(0);
7469 }
7470
7471 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7472 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007473 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007474 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007475 return Smi::FromInt(static_cast<int>(value + 0.5));
7476 }
7477
7478 // If the magnitude is big enough, there's no place for fraction part. If we
7479 // try to add 0.5 to this number, 1.0 will be added instead.
7480 if (exponent >= 52) {
7481 return number;
7482 }
7483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007485
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007486 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488}
7489
7490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007491RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492 NoHandleAllocation ha;
7493 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007496 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007497 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498}
7499
7500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007501RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502 NoHandleAllocation ha;
7503 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007504 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007506 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007507 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508}
7509
7510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007511RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 NoHandleAllocation ha;
7513 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007516 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007517 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007518}
7519
7520
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007521static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007522 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7523 181, 212, 243, 273, 304, 334};
7524 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7525 182, 213, 244, 274, 305, 335};
7526
7527 year += month / 12;
7528 month %= 12;
7529 if (month < 0) {
7530 year--;
7531 month += 12;
7532 }
7533
7534 ASSERT(month >= 0);
7535 ASSERT(month < 12);
7536
7537 // year_delta is an arbitrary number such that:
7538 // a) year_delta = -1 (mod 400)
7539 // b) year + year_delta > 0 for years in the range defined by
7540 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7541 // Jan 1 1970. This is required so that we don't run into integer
7542 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007543 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007544 // operations.
7545 static const int year_delta = 399999;
7546 static const int base_day = 365 * (1970 + year_delta) +
7547 (1970 + year_delta) / 4 -
7548 (1970 + year_delta) / 100 +
7549 (1970 + year_delta) / 400;
7550
7551 int year1 = year + year_delta;
7552 int day_from_year = 365 * year1 +
7553 year1 / 4 -
7554 year1 / 100 +
7555 year1 / 400 -
7556 base_day;
7557
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007558 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7559 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007560 }
7561
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007562 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007563}
7564
7565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007566RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007567 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007568 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007570 CONVERT_SMI_ARG_CHECKED(year, 0);
7571 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007573 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007574}
7575
7576
7577static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7578static const int kDaysIn4Years = 4 * 365 + 1;
7579static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7580static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7581static const int kDays1970to2000 = 30 * 365 + 7;
7582static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7583 kDays1970to2000;
7584static const int kYearsOffset = 400000;
7585
7586static const char kDayInYear[] = {
7587 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7588 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28, 29, 30,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30,
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7611
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28, 29, 30,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30,
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7636
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30,
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7661
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30,
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28, 29, 30,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7686
7687static const char kMonthInYear[] = {
7688 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7689 0, 0, 0, 0, 0, 0,
7690 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7691 1, 1, 1,
7692 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7693 2, 2, 2, 2, 2, 2,
7694 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7695 3, 3, 3, 3, 3,
7696 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7697 4, 4, 4, 4, 4, 4,
7698 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7699 5, 5, 5, 5, 5,
7700 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7701 6, 6, 6, 6, 6, 6,
7702 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7703 7, 7, 7, 7, 7, 7,
7704 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7705 8, 8, 8, 8, 8,
7706 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7707 9, 9, 9, 9, 9, 9,
7708 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7709 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7710 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7711 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7712
7713 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7714 0, 0, 0, 0, 0, 0,
7715 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7716 1, 1, 1,
7717 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7718 2, 2, 2, 2, 2, 2,
7719 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7720 3, 3, 3, 3, 3,
7721 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7722 4, 4, 4, 4, 4, 4,
7723 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7724 5, 5, 5, 5, 5,
7725 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7726 6, 6, 6, 6, 6, 6,
7727 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7728 7, 7, 7, 7, 7, 7,
7729 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7730 8, 8, 8, 8, 8,
7731 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7732 9, 9, 9, 9, 9, 9,
7733 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7734 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7735 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7736 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7737
7738 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7739 0, 0, 0, 0, 0, 0,
7740 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7741 1, 1, 1, 1,
7742 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7743 2, 2, 2, 2, 2, 2,
7744 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7745 3, 3, 3, 3, 3,
7746 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7747 4, 4, 4, 4, 4, 4,
7748 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7749 5, 5, 5, 5, 5,
7750 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7751 6, 6, 6, 6, 6, 6,
7752 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7753 7, 7, 7, 7, 7, 7,
7754 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7755 8, 8, 8, 8, 8,
7756 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7757 9, 9, 9, 9, 9, 9,
7758 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7759 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7760 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7761 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7762
7763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7764 0, 0, 0, 0, 0, 0,
7765 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7766 1, 1, 1,
7767 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7768 2, 2, 2, 2, 2, 2,
7769 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7770 3, 3, 3, 3, 3,
7771 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7772 4, 4, 4, 4, 4, 4,
7773 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7774 5, 5, 5, 5, 5,
7775 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7776 6, 6, 6, 6, 6, 6,
7777 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7778 7, 7, 7, 7, 7, 7,
7779 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7780 8, 8, 8, 8, 8,
7781 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7782 9, 9, 9, 9, 9, 9,
7783 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7784 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7785 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7786 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7787
7788
7789// This function works for dates from 1970 to 2099.
7790static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007791 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007792#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007793 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007794#endif
7795
7796 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7797 date %= kDaysIn4Years;
7798
7799 month = kMonthInYear[date];
7800 day = kDayInYear[date];
7801
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007802 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007803}
7804
7805
7806static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007807 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007808#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007809 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007810#endif
7811
7812 date += kDaysOffset;
7813 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7814 date %= kDaysIn400Years;
7815
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007816 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007817
7818 date--;
7819 int yd1 = date / kDaysIn100Years;
7820 date %= kDaysIn100Years;
7821 year += 100 * yd1;
7822
7823 date++;
7824 int yd2 = date / kDaysIn4Years;
7825 date %= kDaysIn4Years;
7826 year += 4 * yd2;
7827
7828 date--;
7829 int yd3 = date / 365;
7830 date %= 365;
7831 year += yd3;
7832
7833 bool is_leap = (!yd1 || yd2) && !yd3;
7834
7835 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007836 ASSERT(is_leap || (date >= 0));
7837 ASSERT((date < 365) || (is_leap && (date < 366)));
7838 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007839 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7840 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007841
7842 if (is_leap) {
7843 day = kDayInYear[2*365 + 1 + date];
7844 month = kMonthInYear[2*365 + 1 + date];
7845 } else {
7846 day = kDayInYear[date];
7847 month = kMonthInYear[date];
7848 }
7849
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007850 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007851}
7852
7853
7854static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007855 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007856 if (date >= 0 && date < 32 * kDaysIn4Years) {
7857 DateYMDFromTimeAfter1970(date, year, month, day);
7858 } else {
7859 DateYMDFromTimeSlow(date, year, month, day);
7860 }
7861}
7862
7863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007864RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007865 NoHandleAllocation ha;
7866 ASSERT(args.length() == 2);
7867
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007868 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007869 CONVERT_ARG_CHECKED(JSArray, res_array, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870
7871 int year, month, day;
7872 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7873
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007874 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7875 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007876 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007878 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7879 if (maybe->IsFailure()) return maybe;
7880 FixedArray* elms = FixedArray::cast(res_array->elements());
7881 elms->set(0, Smi::FromInt(year));
7882 elms->set(1, Smi::FromInt(month));
7883 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007886}
7887
7888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007889RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007890 HandleScope scope(isolate);
7891 ASSERT(args.length() == 3);
7892
7893 Handle<JSFunction> callee = args.at<JSFunction>(0);
7894 Object** parameters = reinterpret_cast<Object**>(args[1]);
7895 const int argument_count = Smi::cast(args[2])->value();
7896
7897 Handle<JSObject> result =
7898 isolate->factory()->NewArgumentsObject(callee, argument_count);
7899 // Allocate the elements if needed.
7900 int parameter_count = callee->shared()->formal_parameter_count();
7901 if (argument_count > 0) {
7902 if (parameter_count > 0) {
7903 int mapped_count = Min(argument_count, parameter_count);
7904 Handle<FixedArray> parameter_map =
7905 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7906 parameter_map->set_map(
7907 isolate->heap()->non_strict_arguments_elements_map());
7908
7909 Handle<Map> old_map(result->map());
7910 Handle<Map> new_map =
7911 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007912 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007913
7914 result->set_map(*new_map);
7915 result->set_elements(*parameter_map);
7916
7917 // Store the context and the arguments array at the beginning of the
7918 // parameter map.
7919 Handle<Context> context(isolate->context());
7920 Handle<FixedArray> arguments =
7921 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7922 parameter_map->set(0, *context);
7923 parameter_map->set(1, *arguments);
7924
7925 // Loop over the actual parameters backwards.
7926 int index = argument_count - 1;
7927 while (index >= mapped_count) {
7928 // These go directly in the arguments array and have no
7929 // corresponding slot in the parameter map.
7930 arguments->set(index, *(parameters - index - 1));
7931 --index;
7932 }
7933
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007934 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007935 while (index >= 0) {
7936 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007937 Handle<String> name(scope_info->ParameterName(index));
7938 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007939 bool duplicate = false;
7940 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007941 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007942 duplicate = true;
7943 break;
7944 }
7945 }
7946
7947 if (duplicate) {
7948 // This goes directly in the arguments array with a hole in the
7949 // parameter map.
7950 arguments->set(index, *(parameters - index - 1));
7951 parameter_map->set_the_hole(index + 2);
7952 } else {
7953 // The context index goes in the parameter map with a hole in the
7954 // arguments array.
7955 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007956 for (int j = 0; j < context_local_count; ++j) {
7957 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007958 context_index = j;
7959 break;
7960 }
7961 }
7962 ASSERT(context_index >= 0);
7963 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007964 parameter_map->set(index + 2, Smi::FromInt(
7965 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 }
7967
7968 --index;
7969 }
7970 } else {
7971 // If there is no aliasing, the arguments object elements are not
7972 // special in any way.
7973 Handle<FixedArray> elements =
7974 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7975 result->set_elements(*elements);
7976 for (int i = 0; i < argument_count; ++i) {
7977 elements->set(i, *(parameters - i - 1));
7978 }
7979 }
7980 }
7981 return *result;
7982}
7983
7984
7985RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007986 NoHandleAllocation ha;
7987 ASSERT(args.length() == 3);
7988
7989 JSFunction* callee = JSFunction::cast(args[0]);
7990 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007991 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007992
lrn@chromium.org303ada72010-10-27 09:33:13 +00007993 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 { MaybeObject* maybe_result =
7995 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007996 if (!maybe_result->ToObject(&result)) return maybe_result;
7997 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007998 // Allocate the elements if needed.
7999 if (length > 0) {
8000 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008001 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008002 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008003 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8004 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008005
8006 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008007 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008008 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008009 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008010
8011 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008012 for (int i = 0; i < length; i++) {
8013 array->set(i, *--parameters, mode);
8014 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008015 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008016 }
8017 return result;
8018}
8019
8020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008021RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008023 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008024 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8025 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8026 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027
whesse@chromium.org7b260152011-06-20 15:33:18 +00008028 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008029 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008030 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008032 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8033 context,
8034 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 return *result;
8036}
8037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008038
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008039// Find the arguments of the JavaScript function invocation that called
8040// into C++ code. Collect these in a newly allocated array of handles (possibly
8041// prefixed by a number of empty handles).
8042static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8043 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008044 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008045 // Find frame containing arguments passed to the caller.
8046 JavaScriptFrameIterator it;
8047 JavaScriptFrame* frame = it.frame();
8048 List<JSFunction*> functions(2);
8049 frame->GetFunctions(&functions);
8050 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008051 int inlined_jsframe_index = functions.length() - 1;
8052 JSFunction* inlined_function = functions[inlined_jsframe_index];
8053 Vector<SlotRef> args_slots =
8054 SlotRef::ComputeSlotMappingForArguments(
8055 frame,
8056 inlined_jsframe_index,
8057 inlined_function->shared()->formal_parameter_count());
8058
8059 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008060
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008061 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008062 SmartArrayPointer<Handle<Object> > param_data(
8063 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008064 for (int i = 0; i < args_count; i++) {
8065 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008066 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008068
8069 args_slots.Dispose();
8070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008071 return param_data;
8072 } else {
8073 it.AdvanceToArgumentsFrame();
8074 frame = it.frame();
8075 int args_count = frame->ComputeParametersCount();
8076
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008077 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008078 SmartArrayPointer<Handle<Object> > param_data(
8079 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008080 for (int i = 0; i < args_count; i++) {
8081 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008082 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083 }
8084 return param_data;
8085 }
8086}
8087
8088
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8090 HandleScope scope(isolate);
8091 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008092 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008093 RUNTIME_ASSERT(args[3]->IsNumber());
8094 Handle<Object> bindee = args.at<Object>(1);
8095
8096 // TODO(lrn): Create bound function in C++ code from premade shared info.
8097 bound_function->shared()->set_bound(true);
8098 // Get all arguments of calling function (Function.prototype.bind).
8099 int argc = 0;
8100 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8101 // Don't count the this-arg.
8102 if (argc > 0) {
8103 ASSERT(*arguments[0] == args[2]);
8104 argc--;
8105 } else {
8106 ASSERT(args[2]->IsUndefined());
8107 }
8108 // Initialize array of bindings (function, this, and any existing arguments
8109 // if the function was already bound).
8110 Handle<FixedArray> new_bindings;
8111 int i;
8112 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8113 Handle<FixedArray> old_bindings(
8114 JSFunction::cast(*bindee)->function_bindings());
8115 new_bindings =
8116 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8117 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8118 i = 0;
8119 for (int n = old_bindings->length(); i < n; i++) {
8120 new_bindings->set(i, old_bindings->get(i));
8121 }
8122 } else {
8123 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8124 new_bindings = isolate->factory()->NewFixedArray(array_size);
8125 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8126 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8127 i = 2;
8128 }
8129 // Copy arguments, skipping the first which is "this_arg".
8130 for (int j = 0; j < argc; j++, i++) {
8131 new_bindings->set(i, *arguments[j + 1]);
8132 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008133 new_bindings->set_map_no_write_barrier(
8134 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008135 bound_function->set_function_bindings(*new_bindings);
8136
8137 // Update length.
8138 Handle<String> length_symbol = isolate->factory()->length_symbol();
8139 Handle<Object> new_length(args.at<Object>(3));
8140 PropertyAttributes attr =
8141 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8142 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8143 return *bound_function;
8144}
8145
8146
8147RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8148 HandleScope handles(isolate);
8149 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008150 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008151 if (callable->IsJSFunction()) {
8152 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8153 if (function->shared()->bound()) {
8154 Handle<FixedArray> bindings(function->function_bindings());
8155 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8156 return *isolate->factory()->NewJSArrayWithElements(bindings);
8157 }
8158 }
8159 return isolate->heap()->undefined_value();
8160}
8161
8162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008163RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008164 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008165 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008166 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008167 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008168 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008169
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008170 // The argument is a bound function. Extract its bound arguments
8171 // and callable.
8172 Handle<FixedArray> bound_args =
8173 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8174 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8175 Handle<Object> bound_function(
8176 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8177 ASSERT(!bound_function->IsJSFunction() ||
8178 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008180 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008181 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008182 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008183 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008184 param_data[i] = Handle<Object>(bound_args->get(
8185 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008186 }
8187
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008188 if (!bound_function->IsJSFunction()) {
8189 bool exception_thrown;
8190 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8191 &exception_thrown);
8192 if (exception_thrown) return Failure::Exception();
8193 }
8194 ASSERT(bound_function->IsJSFunction());
8195
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008196 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008197 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008198 Execution::New(Handle<JSFunction>::cast(bound_function),
8199 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008200 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008201 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008202 }
8203 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008204 return *result;
8205}
8206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208static void TrySettingInlineConstructStub(Isolate* isolate,
8209 Handle<JSFunction> function) {
8210 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008211 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008213 }
8214 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008215 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008216 Handle<Code> code = compiler.CompileConstructStub(function);
8217 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008218 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008219}
8220
8221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008222RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224 ASSERT(args.length() == 1);
8225
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008226 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008228 // If the constructor isn't a proper function we throw a type error.
8229 if (!constructor->IsJSFunction()) {
8230 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8231 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232 isolate->factory()->NewTypeError("not_constructor", arguments);
8233 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008234 }
8235
8236 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008237
8238 // If function should not have prototype, construction is not allowed. In this
8239 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008240 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008241 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8242 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 isolate->factory()->NewTypeError("not_constructor", arguments);
8244 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008245 }
8246
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008247#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008248 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008249 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008250 if (debug->StepInActive()) {
8251 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008253#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008255 if (function->has_initial_map()) {
8256 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257 // The 'Function' function ignores the receiver object when
8258 // called using 'new' and creates a new JSFunction object that
8259 // is returned. The receiver object is only used for error
8260 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008262 // allocate JSFunctions since it does not properly initialize
8263 // the shared part of the function. Since the receiver is
8264 // ignored anyway, we use the global object as the receiver
8265 // instead of a new JSFunction object. This way, errors are
8266 // reported the same way whether or not 'Function' is called
8267 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008270 }
8271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008272 // The function should be compiled for the optimization hints to be
8273 // available. We cannot use EnsureCompiled because that forces a
8274 // compilation through the shared function info which makes it
8275 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008276 if (!function->is_compiled()) {
8277 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8278 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008279
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008280 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008281 if (!function->has_initial_map() &&
8282 shared->IsInobjectSlackTrackingInProgress()) {
8283 // The tracking is already in progress for another function. We can only
8284 // track one initial_map at a time, so we force the completion before the
8285 // function is called as a constructor for the first time.
8286 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008287 }
8288
8289 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8291 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008292 // Delay setting the stub if inobject slack tracking is in progress.
8293 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008295 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 isolate->counters()->constructed_objects()->Increment();
8298 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008299
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008300 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008301}
8302
8303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008304RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008306 ASSERT(args.length() == 1);
8307
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008308 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008309 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008312 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008313}
8314
8315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008316RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008317 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 ASSERT(args.length() == 1);
8319
8320 Handle<JSFunction> function = args.at<JSFunction>(0);
8321#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008322 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008324 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008325 PrintF("]\n");
8326 }
8327#endif
8328
lrn@chromium.org34e60782011-09-15 07:25:40 +00008329 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008331 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 return Failure::Exception();
8333 }
8334
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008335 // All done. Return the compiled code.
8336 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 return function->code();
8338}
8339
8340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008341RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008342 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008343 ASSERT(args.length() == 1);
8344 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008345
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008346 function->shared()->set_profiler_ticks(0);
8347
lrn@chromium.org34e60782011-09-15 07:25:40 +00008348 // If the function is not compiled ignore the lazy
8349 // recompilation. This can happen if the debugger is activated and
8350 // the function is returned to the not compiled state.
8351 if (!function->shared()->is_compiled()) {
8352 function->ReplaceCode(function->shared()->code());
8353 return function->code();
8354 }
8355
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008356 // If the function is not optimizable or debugger is active continue using the
8357 // code from the full compiler.
8358 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008359 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008360 if (FLAG_trace_opt) {
8361 PrintF("[failed to optimize ");
8362 function->PrintName();
8363 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8364 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008365 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008366 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008367 function->ReplaceCode(function->shared()->code());
8368 return function->code();
8369 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008370 if (JSFunction::CompileOptimized(function,
8371 AstNode::kNoNumber,
8372 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008373 return function->code();
8374 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008375 if (FLAG_trace_opt) {
8376 PrintF("[failed to optimize ");
8377 function->PrintName();
8378 PrintF(": optimized compilation failed]\n");
8379 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008380 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008381 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008382}
8383
8384
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008385class ActivationsFinder : public ThreadVisitor {
8386 public:
8387 explicit ActivationsFinder(JSFunction* function)
8388 : function_(function), has_activations_(false) {}
8389
8390 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8391 if (has_activations_) return;
8392
8393 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8394 JavaScriptFrame* frame = it.frame();
8395 if (frame->is_optimized() && frame->function() == function_) {
8396 has_activations_ = true;
8397 return;
8398 }
8399 }
8400 }
8401
8402 bool has_activations() { return has_activations_; }
8403
8404 private:
8405 JSFunction* function_;
8406 bool has_activations_;
8407};
8408
8409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008410RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412 ASSERT(args.length() == 1);
8413 RUNTIME_ASSERT(args[0]->IsSmi());
8414 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008415 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008416 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8417 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008418 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008420 deoptimizer->MaterializeHeapNumbers();
8421 delete deoptimizer;
8422
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008423 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008425 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008426 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008427
8428 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008430 Handle<Object> arguments;
8431 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008433 if (arguments.is_null()) {
8434 // FunctionGetArguments can't throw an exception, so cast away the
8435 // doubt with an assert.
8436 arguments = Handle<Object>(
8437 Accessors::FunctionGetArguments(*function,
8438 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008439 ASSERT(*arguments != isolate->heap()->null_value());
8440 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 }
8442 frame->SetExpression(i, *arguments);
8443 }
8444 }
8445
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008446 if (type == Deoptimizer::EAGER) {
8447 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008448 }
8449
8450 // Avoid doing too much work when running with --always-opt and keep
8451 // the optimized code around.
8452 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008454 }
8455
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008456 // Find other optimized activations of the function.
8457 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008458 while (!it.done()) {
8459 JavaScriptFrame* frame = it.frame();
8460 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008461 has_other_activations = true;
8462 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008463 }
8464 it.Advance();
8465 }
8466
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008467 if (!has_other_activations) {
8468 ActivationsFinder activations_finder(*function);
8469 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8470 has_other_activations = activations_finder.has_activations();
8471 }
8472
8473 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474 if (FLAG_trace_deopt) {
8475 PrintF("[removing optimized code for: ");
8476 function->PrintName();
8477 PrintF("]\n");
8478 }
8479 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008480 } else {
8481 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008482 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008484}
8485
8486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008487RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008489 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491}
8492
8493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008494RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008496 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008497 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008498 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008499
8500 Deoptimizer::DeoptimizeFunction(*function);
8501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008502 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008503}
8504
8505
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008506RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8507#if defined(USE_SIMULATOR)
8508 return isolate->heap()->true_value();
8509#else
8510 return isolate->heap()->false_value();
8511#endif
8512}
8513
8514
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008515RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8516 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008517 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008518 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008519
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008520 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8521 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008522
8523 Code* unoptimized = function->shared()->code();
8524 if (args.length() == 2 &&
8525 unoptimized->kind() == Code::FUNCTION) {
8526 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8527 CHECK(type->IsEqualTo(CStrVector("osr")));
8528 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8529 unoptimized->set_allow_osr_at_loop_nesting_level(
8530 Code::kMaxLoopNestingMarker);
8531 }
8532
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008533 return isolate->heap()->undefined_value();
8534}
8535
8536
lrn@chromium.org1c092762011-05-09 09:42:16 +00008537RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8538 HandleScope scope(isolate);
8539 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008540 // The least significant bit (after untagging) indicates whether the
8541 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008542 if (!V8::UseCrankshaft()) {
8543 return Smi::FromInt(4); // 4 == "never".
8544 }
8545 if (FLAG_always_opt) {
8546 return Smi::FromInt(3); // 3 == "always".
8547 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008548 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008549 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8550 : Smi::FromInt(2); // 2 == "no".
8551}
8552
8553
8554RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8555 HandleScope scope(isolate);
8556 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008557 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008558 return Smi::FromInt(function->shared()->opt_count());
8559}
8560
8561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008562RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008564 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008565 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008566
8567 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008568 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008569
8570 // We have hit a back edge in an unoptimized frame for a function that was
8571 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008572 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008573 // Keep track of whether we've succeeded in optimizing.
8574 bool succeeded = unoptimized->optimizable();
8575 if (succeeded) {
8576 // If we are trying to do OSR when there are already optimized
8577 // activations of the function, it means (a) the function is directly or
8578 // indirectly recursive and (b) an optimized invocation has been
8579 // deoptimized so that we are currently in an unoptimized activation.
8580 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008581 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008582 while (succeeded && !it.done()) {
8583 JavaScriptFrame* frame = it.frame();
8584 succeeded = !frame->is_optimized() || frame->function() != *function;
8585 it.Advance();
8586 }
8587 }
8588
8589 int ast_id = AstNode::kNoNumber;
8590 if (succeeded) {
8591 // The top JS function is this one, the PC is somewhere in the
8592 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008593 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008594 JavaScriptFrame* frame = it.frame();
8595 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008596 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008597 ASSERT(unoptimized->contains(frame->pc()));
8598
8599 // Use linear search of the unoptimized code's stack check table to find
8600 // the AST id matching the PC.
8601 Address start = unoptimized->instruction_start();
8602 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008603 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008604 uint32_t table_length = Memory::uint32_at(table_cursor);
8605 table_cursor += kIntSize;
8606 for (unsigned i = 0; i < table_length; ++i) {
8607 // Table entries are (AST id, pc offset) pairs.
8608 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8609 if (pc_offset == target_pc_offset) {
8610 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8611 break;
8612 }
8613 table_cursor += 2 * kIntSize;
8614 }
8615 ASSERT(ast_id != AstNode::kNoNumber);
8616 if (FLAG_trace_osr) {
8617 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8618 function->PrintName();
8619 PrintF("]\n");
8620 }
8621
8622 // Try to compile the optimized code. A true return value from
8623 // CompileOptimized means that compilation succeeded, not necessarily
8624 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008625 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008626 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008627 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8628 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008629 if (data->OsrPcOffset()->value() >= 0) {
8630 if (FLAG_trace_osr) {
8631 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008633 }
8634 ASSERT(data->OsrAstId()->value() == ast_id);
8635 } else {
8636 // We may never generate the desired OSR entry if we emit an
8637 // early deoptimize.
8638 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008639 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008640 } else {
8641 succeeded = false;
8642 }
8643 }
8644
8645 // Revert to the original stack checks in the original unoptimized code.
8646 if (FLAG_trace_osr) {
8647 PrintF("[restoring original stack checks in ");
8648 function->PrintName();
8649 PrintF("]\n");
8650 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008651 Handle<Code> check_code;
8652#ifdef V8_TARGET_ARCH_IA32
8653 if (FLAG_count_based_interrupts) {
8654 InterruptStub interrupt_stub;
8655 check_code = interrupt_stub.GetCode();
8656 } else // NOLINT
8657#endif
8658 { // NOLINT
8659 StackCheckStub check_stub;
8660 check_code = check_stub.GetCode();
8661 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008662 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008663 Deoptimizer::RevertStackCheckCode(*unoptimized,
8664 *check_code,
8665 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008666
8667 // Allow OSR only at nesting level zero again.
8668 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8669
8670 // If the optimization attempt succeeded, return the AST id tagged as a
8671 // smi. This tells the builtin that we need to translate the unoptimized
8672 // frame to an optimized one.
8673 if (succeeded) {
8674 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8675 return Smi::FromInt(ast_id);
8676 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008677 if (function->IsMarkedForLazyRecompilation()) {
8678 function->ReplaceCode(function->shared()->code());
8679 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008680 return Smi::FromInt(-1);
8681 }
8682}
8683
8684
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008685RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8686 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8687 return isolate->heap()->undefined_value();
8688}
8689
8690
danno@chromium.orgc612e022011-11-10 11:38:15 +00008691RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8692 HandleScope scope(isolate);
8693 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008694 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008695 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8696 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008697
8698 // If there are too many arguments, allocate argv via malloc.
8699 const int argv_small_size = 10;
8700 Handle<Object> argv_small_buffer[argv_small_size];
8701 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8702 Handle<Object>* argv = argv_small_buffer;
8703 if (argc > argv_small_size) {
8704 argv = new Handle<Object>[argc];
8705 if (argv == NULL) return isolate->StackOverflow();
8706 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8707 }
8708
8709 for (int i = 0; i < argc; ++i) {
8710 MaybeObject* maybe = args[1 + i];
8711 Object* object;
8712 if (!maybe->To<Object>(&object)) return maybe;
8713 argv[i] = Handle<Object>(object);
8714 }
8715
8716 bool threw;
8717 Handle<JSReceiver> hfun(fun);
8718 Handle<Object> hreceiver(receiver);
8719 Handle<Object> result =
8720 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8721
8722 if (threw) return Failure::Exception();
8723 return *result;
8724}
8725
8726
lrn@chromium.org34e60782011-09-15 07:25:40 +00008727RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8728 HandleScope scope(isolate);
8729 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008730 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008731 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008732 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008733 CONVERT_SMI_ARG_CHECKED(offset, 3);
8734 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008735 ASSERT(offset >= 0);
8736 ASSERT(argc >= 0);
8737
8738 // If there are too many arguments, allocate argv via malloc.
8739 const int argv_small_size = 10;
8740 Handle<Object> argv_small_buffer[argv_small_size];
8741 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8742 Handle<Object>* argv = argv_small_buffer;
8743 if (argc > argv_small_size) {
8744 argv = new Handle<Object>[argc];
8745 if (argv == NULL) return isolate->StackOverflow();
8746 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8747 }
8748
8749 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008750 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008751 }
8752
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008753 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008754 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008755 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008756
8757 if (threw) return Failure::Exception();
8758 return *result;
8759}
8760
8761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008762RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764 ASSERT(args.length() == 1);
8765 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8766 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8767}
8768
8769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008770RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008772 ASSERT(args.length() == 1);
8773 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8774 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8775}
8776
8777
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008778RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008780 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008782 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008783 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008784 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 { MaybeObject* maybe_result =
8786 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008787 if (!maybe_result->ToObject(&result)) return maybe_result;
8788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791
kasper.lund7276f142008-07-30 08:49:36 +00008792 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008793}
8794
lrn@chromium.org303ada72010-10-27 09:33:13 +00008795
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008796RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8797 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008798 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008799 JSObject* extension_object;
8800 if (args[0]->IsJSObject()) {
8801 extension_object = JSObject::cast(args[0]);
8802 } else {
8803 // Convert the object to a proper JavaScript object.
8804 MaybeObject* maybe_js_object = args[0]->ToObject();
8805 if (!maybe_js_object->To(&extension_object)) {
8806 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8807 HandleScope scope(isolate);
8808 Handle<Object> handle = args.at<Object>(0);
8809 Handle<Object> result =
8810 isolate->factory()->NewTypeError("with_expression",
8811 HandleVector(&handle, 1));
8812 return isolate->Throw(*result);
8813 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008814 return maybe_js_object;
8815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816 }
8817 }
8818
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008819 JSFunction* function;
8820 if (args[1]->IsSmi()) {
8821 // A smi sentinel indicates a context nested inside global code rather
8822 // than some function. There is a canonical empty function that can be
8823 // gotten from the global context.
8824 function = isolate->context()->global_context()->closure();
8825 } else {
8826 function = JSFunction::cast(args[1]);
8827 }
8828
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008829 Context* context;
8830 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008831 isolate->heap()->AllocateWithContext(function,
8832 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008833 extension_object);
8834 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008836 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008837}
8838
8839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008840RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008841 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008842 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008843 String* name = String::cast(args[0]);
8844 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008845 JSFunction* function;
8846 if (args[2]->IsSmi()) {
8847 // A smi sentinel indicates a context nested inside global code rather
8848 // than some function. There is a canonical empty function that can be
8849 // gotten from the global context.
8850 function = isolate->context()->global_context()->closure();
8851 } else {
8852 function = JSFunction::cast(args[2]);
8853 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008854 Context* context;
8855 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008856 isolate->heap()->AllocateCatchContext(function,
8857 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008858 name,
8859 thrown_object);
8860 if (!maybe_context->To(&context)) return maybe_context;
8861 isolate->set_context(context);
8862 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008863}
8864
8865
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008866RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8867 NoHandleAllocation ha;
8868 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008869 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008870 JSFunction* function;
8871 if (args[1]->IsSmi()) {
8872 // A smi sentinel indicates a context nested inside global code rather
8873 // than some function. There is a canonical empty function that can be
8874 // gotten from the global context.
8875 function = isolate->context()->global_context()->closure();
8876 } else {
8877 function = JSFunction::cast(args[1]);
8878 }
8879 Context* context;
8880 MaybeObject* maybe_context =
8881 isolate->heap()->AllocateBlockContext(function,
8882 isolate->context(),
8883 scope_info);
8884 if (!maybe_context->To(&context)) return maybe_context;
8885 isolate->set_context(context);
8886 return context;
8887}
8888
8889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008891 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008892 ASSERT(args.length() == 2);
8893
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008894 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8895 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896
8897 int index;
8898 PropertyAttributes attributes;
8899 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008900 BindingFlags binding_flags;
8901 Handle<Object> holder = context->Lookup(name,
8902 flags,
8903 &index,
8904 &attributes,
8905 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008907 // If the slot was not found the result is true.
8908 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008909 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 }
8911
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008912 // If the slot was found in a context, it should be DONT_DELETE.
8913 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008914 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008915 }
8916
8917 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008918 // the global object, or the subject of a with. Try to delete it
8919 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008920 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008921 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922}
8923
8924
ager@chromium.orga1645e22009-09-09 19:27:10 +00008925// A mechanism to return a pair of Object pointers in registers (if possible).
8926// How this is achieved is calling convention-dependent.
8927// All currently supported x86 compiles uses calling conventions that are cdecl
8928// variants where a 64-bit value is returned in two 32-bit registers
8929// (edx:eax on ia32, r1:r0 on ARM).
8930// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8931// In Win64 calling convention, a struct of two pointers is returned in memory,
8932// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008933#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008934struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008935 MaybeObject* x;
8936 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008937};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008938
lrn@chromium.org303ada72010-10-27 09:33:13 +00008939static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008940 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008941 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8942 // In Win64 they are assigned to a hidden first argument.
8943 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008944}
8945#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008946typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008947static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008948 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008949 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008951#endif
8952
8953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954static inline MaybeObject* Unhole(Heap* heap,
8955 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008956 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8958 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960}
8961
8962
danno@chromium.org40cb8782011-05-25 07:58:50 +00008963static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8964 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008965 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008966 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008967 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008968 JSFunction* context_extension_function =
8969 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008970 // If the holder isn't a context extension object, we just return it
8971 // as the receiver. This allows arguments objects to be used as
8972 // receivers, but only if they are put in the context scope chain
8973 // explicitly via a with-statement.
8974 Object* constructor = holder->map()->constructor();
8975 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008976 // Fall back to using the global object as the implicit receiver if
8977 // the property turns out to be a local variable allocated in a
8978 // context extension object - introduced via eval. Implicit global
8979 // receivers are indicated with the hole value.
8980 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008981}
8982
8983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984static ObjectPair LoadContextSlotHelper(Arguments args,
8985 Isolate* isolate,
8986 bool throw_error) {
8987 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008988 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008990 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008991 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008992 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008994 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995
8996 int index;
8997 PropertyAttributes attributes;
8998 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008999 BindingFlags binding_flags;
9000 Handle<Object> holder = context->Lookup(name,
9001 flags,
9002 &index,
9003 &attributes,
9004 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009006 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009008 ASSERT(holder->IsContext());
9009 // If the "property" we were looking for is a local variable, the
9010 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009011 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009012 // Use the hole as the receiver to signal that the receiver is implicit
9013 // and that the global receiver should be used (as distinguished from an
9014 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009015 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009016 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009017 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009018 switch (binding_flags) {
9019 case MUTABLE_CHECK_INITIALIZED:
9020 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9021 if (value->IsTheHole()) {
9022 Handle<Object> reference_error =
9023 isolate->factory()->NewReferenceError("not_defined",
9024 HandleVector(&name, 1));
9025 return MakePair(isolate->Throw(*reference_error), NULL);
9026 }
9027 // FALLTHROUGH
9028 case MUTABLE_IS_INITIALIZED:
9029 case IMMUTABLE_IS_INITIALIZED:
9030 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9031 ASSERT(!value->IsTheHole());
9032 return MakePair(value, *receiver);
9033 case IMMUTABLE_CHECK_INITIALIZED:
9034 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9035 case MISSING_BINDING:
9036 UNREACHABLE();
9037 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009038 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039 }
9040
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009041 // Otherwise, if the slot was found the holder is a context extension
9042 // object, subject of a with, or a global object. We read the named
9043 // property from it.
9044 if (!holder.is_null()) {
9045 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9046 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009047 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009048 Handle<Object> receiver_handle(object->IsGlobalObject()
9049 ? GlobalObject::cast(*object)->global_receiver()
9050 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009051
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009052 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009053 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009054 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009055 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 }
9057
9058 if (throw_error) {
9059 // The property doesn't exist - throw exception.
9060 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009061 isolate->factory()->NewReferenceError("not_defined",
9062 HandleVector(&name, 1));
9063 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009065 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 return MakePair(isolate->heap()->undefined_value(),
9067 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 }
9069}
9070
9071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009072RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009073 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074}
9075
9076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009077RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009078 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079}
9080
9081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009082RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009083 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009084 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009086 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009087 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9088 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009089 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9090 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9091 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092
9093 int index;
9094 PropertyAttributes attributes;
9095 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009096 BindingFlags binding_flags;
9097 Handle<Object> holder = context->Lookup(name,
9098 flags,
9099 &index,
9100 &attributes,
9101 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102
9103 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009104 // The property was found in a context slot.
9105 Handle<Context> context = Handle<Context>::cast(holder);
9106 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9107 context->get(index)->IsTheHole()) {
9108 Handle<Object> error =
9109 isolate->factory()->NewReferenceError("not_defined",
9110 HandleVector(&name, 1));
9111 return isolate->Throw(*error);
9112 }
9113 // Ignore if read_only variable.
9114 if ((attributes & READ_ONLY) == 0) {
9115 // Context is a fixed array and set cannot fail.
9116 context->set(index, *value);
9117 } else if (strict_mode == kStrictMode) {
9118 // Setting read only property in strict mode.
9119 Handle<Object> error =
9120 isolate->factory()->NewTypeError("strict_cannot_assign",
9121 HandleVector(&name, 1));
9122 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 }
9124 return *value;
9125 }
9126
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009127 // Slow case: The property is not in a context slot. It is either in a
9128 // context extension object, a property of the subject of a with, or a
9129 // property of the global object.
9130 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009132 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009133 // The property exists on the holder.
9134 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009136 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009138
9139 if (strict_mode == kStrictMode) {
9140 // Throw in strict mode (assignment to undefined variable).
9141 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009142 isolate->factory()->NewReferenceError(
9143 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009144 return isolate->Throw(*error);
9145 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009146 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009148 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149 }
9150
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009151 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009152 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009153 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009154 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009155 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009156 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009157 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009158 // Setting read only property in strict mode.
9159 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 isolate->factory()->NewTypeError(
9161 "strict_cannot_assign", HandleVector(&name, 1));
9162 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 }
9164 return *value;
9165}
9166
9167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009168RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009169 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009170 ASSERT(args.length() == 1);
9171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173}
9174
9175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009176RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178 ASSERT(args.length() == 1);
9179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009180 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181}
9182
9183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009184RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009185 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009187}
9188
9189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009191 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192 ASSERT(args.length() == 1);
9193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 isolate->factory()->NewReferenceError("not_defined",
9197 HandleVector(&name, 1));
9198 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199}
9200
9201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009202RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009203 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204
9205 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 if (isolate->stack_guard()->IsStackOverflow()) {
9207 NoHandleAllocation na;
9208 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009211 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212}
9213
9214
yangguo@chromium.org56454712012-02-16 15:33:53 +00009215RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9216 ASSERT(args.length() == 0);
9217 return Execution::HandleStackGuardInterrupt();
9218}
9219
9220
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221static int StackSize() {
9222 int n = 0;
9223 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9224 return n;
9225}
9226
9227
9228static void PrintTransition(Object* result) {
9229 // indentation
9230 { const int nmax = 80;
9231 int n = StackSize();
9232 if (n <= nmax)
9233 PrintF("%4d:%*s", n, n, "");
9234 else
9235 PrintF("%4d:%*s", n, nmax, "...");
9236 }
9237
9238 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009239 JavaScriptFrame::PrintTop(stdout, true, false);
9240 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 } else {
9242 // function result
9243 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009244 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 PrintF("\n");
9246 }
9247}
9248
9249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009250RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009251 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 NoHandleAllocation ha;
9253 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255}
9256
9257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009258RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 NoHandleAllocation ha;
9260 PrintTransition(args[0]);
9261 return args[0]; // return TOS
9262}
9263
9264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009265RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 NoHandleAllocation ha;
9267 ASSERT(args.length() == 1);
9268
9269#ifdef DEBUG
9270 if (args[0]->IsString()) {
9271 // If we have a string, assume it's a code "marker"
9272 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009273 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009275 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9276 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 } else {
9278 PrintF("DebugPrint: ");
9279 }
9280 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009281 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009282 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009283 HeapObject::cast(args[0])->map()->Print();
9284 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009286 // ShortPrint is available in release mode. Print is not.
9287 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288#endif
9289 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009290 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291
9292 return args[0]; // return TOS
9293}
9294
9295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009296RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009297 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 isolate->PrintStack();
9300 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301}
9302
9303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009304RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009306 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307
9308 // According to ECMA-262, section 15.9.1, page 117, the precision of
9309 // the number in a Date object representing a particular instant in
9310 // time is milliseconds. Therefore, we floor the result of getting
9311 // the OS time.
9312 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314}
9315
9316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009317RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009319 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009321 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009322 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009324 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009325
9326 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009327 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009328 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009329 RUNTIME_ASSERT(output->HasFastElements());
9330
9331 AssertNoAllocation no_allocation;
9332
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009333 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009334 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9335 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009336 String::FlatContent str_content = str->GetFlatContent();
9337 if (str_content.IsAscii()) {
9338 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009339 output_array,
9340 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009342 ASSERT(str_content.IsTwoByte());
9343 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009344 output_array,
9345 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009346 }
9347
9348 if (result) {
9349 return *output;
9350 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009351 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352 }
9353}
9354
9355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009356RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009357 NoHandleAllocation ha;
9358 ASSERT(args.length() == 1);
9359
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009360 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009361 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363}
9364
9365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009366RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009368 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371}
9372
9373
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009374RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 NoHandleAllocation ha;
9376 ASSERT(args.length() == 1);
9377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009379 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009380}
9381
9382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009383RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009384 ASSERT(args.length() == 1);
9385 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009386 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009387 return JSGlobalObject::cast(global)->global_receiver();
9388}
9389
9390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009391RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009393 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009394 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009395
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009396 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009397 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009398 Handle<Object> result;
9399 if (source->IsSeqAsciiString()) {
9400 result = JsonParser<true>::Parse(source);
9401 } else {
9402 result = JsonParser<false>::Parse(source);
9403 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009404 if (result.is_null()) {
9405 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009406 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009407 return Failure::Exception();
9408 }
9409 return *result;
9410}
9411
9412
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009413bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9414 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009415 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9416 // Check with callback if set.
9417 AllowCodeGenerationFromStringsCallback callback =
9418 isolate->allow_code_gen_callback();
9419 if (callback == NULL) {
9420 // No callback set and code generation disallowed.
9421 return false;
9422 } else {
9423 // Callback set. Let it decide if code generation is allowed.
9424 VMState state(isolate, EXTERNAL);
9425 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009426 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009427}
9428
9429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009430RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009432 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009433 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009434
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009435 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009437
9438 // Check if global context allows code generation from
9439 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009440 if (context->allow_code_gen_from_strings()->IsFalse() &&
9441 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009442 return isolate->Throw(*isolate->factory()->NewError(
9443 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9444 }
9445
9446 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009447 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009448 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009449 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009451 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9452 context,
9453 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 return *fun;
9455}
9456
9457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458static ObjectPair CompileGlobalEval(Isolate* isolate,
9459 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009460 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009461 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009462 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009463 Handle<Context> context = Handle<Context>(isolate->context());
9464 Handle<Context> global_context = Handle<Context>(context->global_context());
9465
9466 // Check if global context allows code generation from
9467 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009468 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9469 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009470 isolate->Throw(*isolate->factory()->NewError(
9471 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9472 return MakePair(Failure::Exception(), NULL);
9473 }
9474
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009475 // Deal with a normal eval call with a string argument. Compile it
9476 // and return the compiled function bound in the local context.
9477 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9478 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009480 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009481 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009482 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009483 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 Handle<JSFunction> compiled =
9485 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009486 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009487 return MakePair(*compiled, *receiver);
9488}
9489
9490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009491RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009492 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009495 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009496
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009497 // If "eval" didn't refer to the original GlobalEval, it's not a
9498 // direct call to eval.
9499 // (And even if it is, but the first argument isn't a string, just let
9500 // execution default to an indirect call to eval, which will also return
9501 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009503 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009504 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009505 }
9506
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009507 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009508 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009509 return CompileGlobalEval(isolate,
9510 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009511 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009512 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009513 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009514}
9515
9516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009517RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 // This utility adjusts the property attributes for newly created Function
9519 // object ("new Function(...)") by changing the map.
9520 // All it does is changing the prototype property to enumerable
9521 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009522 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009524 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009526 Handle<Map> map = func->shared()->is_classic_mode()
9527 ? isolate->function_instance_map()
9528 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009529
9530 ASSERT(func->map()->instance_type() == map->instance_type());
9531 ASSERT(func->map()->instance_size() == map->instance_size());
9532 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009533 return *func;
9534}
9535
9536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009537RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009538 // Allocate a block of memory in NewSpace (filled with a filler).
9539 // Use as fallback for allocation in generated code when NewSpace
9540 // is full.
9541 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009542 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009543 int size = size_smi->value();
9544 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9545 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 Heap* heap = isolate->heap();
9547 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009548 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009549 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009551 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009552 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009553 }
9554 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009555 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009556}
9557
9558
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009559// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009560// array. Returns true if the element was pushed on the stack and
9561// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009562RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009563 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009564 CONVERT_ARG_CHECKED(JSArray, array, 0);
9565 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009566 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009567 int length = Smi::cast(array->length())->value();
9568 FixedArray* elements = FixedArray::cast(array->elements());
9569 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009571 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009572 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009573 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009574 { MaybeObject* maybe_obj =
9575 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009576 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009578 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009579}
9580
9581
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009582/**
9583 * A simple visitor visits every element of Array's.
9584 * The backend storage can be a fixed array for fast elements case,
9585 * or a dictionary for sparse array. Since Dictionary is a subtype
9586 * of FixedArray, the class can be used by both fast and slow cases.
9587 * The second parameter of the constructor, fast_elements, specifies
9588 * whether the storage is a FixedArray or Dictionary.
9589 *
9590 * An index limit is used to deal with the situation that a result array
9591 * length overflows 32-bit non-negative integer.
9592 */
9593class ArrayConcatVisitor {
9594 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 ArrayConcatVisitor(Isolate* isolate,
9596 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009597 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009598 isolate_(isolate),
9599 storage_(Handle<FixedArray>::cast(
9600 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 index_offset_(0u),
9602 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009604 ~ArrayConcatVisitor() {
9605 clear_storage();
9606 }
9607
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009608 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009609 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009610 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009611
9612 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 if (index < static_cast<uint32_t>(storage_->length())) {
9614 storage_->set(index, *elm);
9615 return;
9616 }
9617 // Our initial estimate of length was foiled, possibly by
9618 // getters on the arrays increasing the length of later arrays
9619 // during iteration.
9620 // This shouldn't happen in anything but pathological cases.
9621 SetDictionaryMode(index);
9622 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009623 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009624 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009625 Handle<SeededNumberDictionary> dict(
9626 SeededNumberDictionary::cast(*storage_));
9627 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009629 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009630 // Dictionary needed to grow.
9631 clear_storage();
9632 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 }
9634}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009635
9636 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9638 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009639 } else {
9640 index_offset_ += delta;
9641 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009642 }
9643
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009644 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 Handle<Map> map;
9649 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009650 map = isolate_->factory()->GetElementsTransitionMap(array,
9651 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009653 map = isolate_->factory()->GetElementsTransitionMap(array,
9654 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009655 }
9656 array->set_map(*map);
9657 array->set_length(*length);
9658 array->set_elements(*storage_);
9659 return array;
9660 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009661
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009662 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 // Convert storage to dictionary mode.
9664 void SetDictionaryMode(uint32_t index) {
9665 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009666 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009667 Handle<SeededNumberDictionary> slow_storage(
9668 isolate_->factory()->NewSeededNumberDictionary(
9669 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009670 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9671 for (uint32_t i = 0; i < current_length; i++) {
9672 HandleScope loop_scope;
9673 Handle<Object> element(current_storage->get(i));
9674 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009675 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 if (!new_storage.is_identical_to(slow_storage)) {
9678 slow_storage = loop_scope.CloseAndEscape(new_storage);
9679 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 }
9681 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009682 clear_storage();
9683 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009684 fast_elements_ = false;
9685 }
9686
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009687 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009688 isolate_->global_handles()->Destroy(
9689 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009690 }
9691
9692 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009693 storage_ = Handle<FixedArray>::cast(
9694 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009695 }
9696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009697 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009698 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 // Index after last seen index. Always less than or equal to
9700 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009701 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009702 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009703};
9704
9705
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009706static uint32_t EstimateElementCount(Handle<JSArray> array) {
9707 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9708 int element_count = 0;
9709 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009710 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009711 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 // Fast elements can't have lengths that are not representable by
9713 // a 32-bit signed integer.
9714 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9715 int fast_length = static_cast<int>(length);
9716 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9717 for (int i = 0; i < fast_length; i++) {
9718 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009719 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009720 break;
9721 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009722 case FAST_DOUBLE_ELEMENTS:
9723 // TODO(1810): Decide if it's worthwhile to implement this.
9724 UNREACHABLE();
9725 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009726 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009727 Handle<SeededNumberDictionary> dictionary(
9728 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 int capacity = dictionary->Capacity();
9730 for (int i = 0; i < capacity; i++) {
9731 Handle<Object> key(dictionary->KeyAt(i));
9732 if (dictionary->IsKey(*key)) {
9733 element_count++;
9734 }
9735 }
9736 break;
9737 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009738 case NON_STRICT_ARGUMENTS_ELEMENTS:
9739 case EXTERNAL_BYTE_ELEMENTS:
9740 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9741 case EXTERNAL_SHORT_ELEMENTS:
9742 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9743 case EXTERNAL_INT_ELEMENTS:
9744 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9745 case EXTERNAL_FLOAT_ELEMENTS:
9746 case EXTERNAL_DOUBLE_ELEMENTS:
9747 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 // External arrays are always dense.
9749 return length;
9750 }
9751 // As an estimate, we assume that the prototype doesn't contain any
9752 // inherited elements.
9753 return element_count;
9754}
9755
9756
9757
9758template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009759static void IterateExternalArrayElements(Isolate* isolate,
9760 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 bool elements_are_ints,
9762 bool elements_are_guaranteed_smis,
9763 ArrayConcatVisitor* visitor) {
9764 Handle<ExternalArrayClass> array(
9765 ExternalArrayClass::cast(receiver->elements()));
9766 uint32_t len = static_cast<uint32_t>(array->length());
9767
9768 ASSERT(visitor != NULL);
9769 if (elements_are_ints) {
9770 if (elements_are_guaranteed_smis) {
9771 for (uint32_t j = 0; j < len; j++) {
9772 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009773 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009774 visitor->visit(j, e);
9775 }
9776 } else {
9777 for (uint32_t j = 0; j < len; j++) {
9778 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009779 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009780 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9781 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9782 visitor->visit(j, e);
9783 } else {
9784 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009785 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009786 visitor->visit(j, e);
9787 }
9788 }
9789 }
9790 } else {
9791 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009792 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009793 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794 visitor->visit(j, e);
9795 }
9796 }
9797}
9798
9799
9800// Used for sorting indices in a List<uint32_t>.
9801static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9802 uint32_t a = *ap;
9803 uint32_t b = *bp;
9804 return (a == b) ? 0 : (a < b) ? -1 : 1;
9805}
9806
9807
9808static void CollectElementIndices(Handle<JSObject> object,
9809 uint32_t range,
9810 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009811 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009812 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009813 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009814 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009815 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9816 uint32_t length = static_cast<uint32_t>(elements->length());
9817 if (range < length) length = range;
9818 for (uint32_t i = 0; i < length; i++) {
9819 if (!elements->get(i)->IsTheHole()) {
9820 indices->Add(i);
9821 }
9822 }
9823 break;
9824 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009825 case FAST_DOUBLE_ELEMENTS: {
9826 // TODO(1810): Decide if it's worthwhile to implement this.
9827 UNREACHABLE();
9828 break;
9829 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009830 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009831 Handle<SeededNumberDictionary> dict(
9832 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009833 uint32_t capacity = dict->Capacity();
9834 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009836 Handle<Object> k(dict->KeyAt(j));
9837 if (dict->IsKey(*k)) {
9838 ASSERT(k->IsNumber());
9839 uint32_t index = static_cast<uint32_t>(k->Number());
9840 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009841 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009842 }
9843 }
9844 }
9845 break;
9846 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 default: {
9848 int dense_elements_length;
9849 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009850 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009851 dense_elements_length =
9852 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009853 break;
9854 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009855 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009856 dense_elements_length =
9857 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009858 break;
9859 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009860 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009861 dense_elements_length =
9862 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009863 break;
9864 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009865 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009866 dense_elements_length =
9867 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009868 break;
9869 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009870 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009871 dense_elements_length =
9872 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009873 break;
9874 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009875 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009876 dense_elements_length =
9877 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009878 break;
9879 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009880 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009881 dense_elements_length =
9882 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009883 break;
9884 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009885 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009886 dense_elements_length =
9887 ExternalFloatArray::cast(object->elements())->length();
9888 break;
9889 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009890 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009891 dense_elements_length =
9892 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009893 break;
9894 }
9895 default:
9896 UNREACHABLE();
9897 dense_elements_length = 0;
9898 break;
9899 }
9900 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9901 if (range <= length) {
9902 length = range;
9903 // We will add all indices, so we might as well clear it first
9904 // and avoid duplicates.
9905 indices->Clear();
9906 }
9907 for (uint32_t i = 0; i < length; i++) {
9908 indices->Add(i);
9909 }
9910 if (length == range) return; // All indices accounted for already.
9911 break;
9912 }
9913 }
9914
9915 Handle<Object> prototype(object->GetPrototype());
9916 if (prototype->IsJSObject()) {
9917 // The prototype will usually have no inherited element indices,
9918 // but we have to check.
9919 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9920 }
9921}
9922
9923
9924/**
9925 * A helper function that visits elements of a JSArray in numerical
9926 * order.
9927 *
9928 * The visitor argument called for each existing element in the array
9929 * with the element index and the element's value.
9930 * Afterwards it increments the base-index of the visitor by the array
9931 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009932 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009933 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934static bool IterateElements(Isolate* isolate,
9935 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009936 ArrayConcatVisitor* visitor) {
9937 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9938 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009939 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009940 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009941 // Run through the elements FixedArray and use HasElement and GetElement
9942 // to check the prototype for missing elements.
9943 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9944 int fast_length = static_cast<int>(length);
9945 ASSERT(fast_length <= elements->length());
9946 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 HandleScope loop_scope(isolate);
9948 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009949 if (!element_value->IsTheHole()) {
9950 visitor->visit(j, element_value);
9951 } else if (receiver->HasElement(j)) {
9952 // Call GetElement on receiver, not its prototype, or getters won't
9953 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009954 element_value = Object::GetElement(receiver, j);
9955 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009956 visitor->visit(j, element_value);
9957 }
9958 }
9959 break;
9960 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009961 case FAST_DOUBLE_ELEMENTS: {
9962 // TODO(1810): Decide if it's worthwhile to implement this.
9963 UNREACHABLE();
9964 break;
9965 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009966 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009967 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009968 List<uint32_t> indices(dict->Capacity() / 2);
9969 // Collect all indices in the object and the prototypes less
9970 // than length. This might introduce duplicates in the indices list.
9971 CollectElementIndices(receiver, length, &indices);
9972 indices.Sort(&compareUInt32);
9973 int j = 0;
9974 int n = indices.length();
9975 while (j < n) {
9976 HandleScope loop_scope;
9977 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009978 Handle<Object> element = Object::GetElement(receiver, index);
9979 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 visitor->visit(index, element);
9981 // Skip to next different index (i.e., omit duplicates).
9982 do {
9983 j++;
9984 } while (j < n && indices[j] == index);
9985 }
9986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009989 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9990 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009992 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009993 visitor->visit(j, e);
9994 }
9995 break;
9996 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009997 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009998 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 break;
10001 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010002 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010005 break;
10006 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010007 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010008 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010010 break;
10011 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010012 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010014 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 break;
10016 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010017 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010018 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 break;
10021 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010022 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010023 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010024 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 break;
10026 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010027 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010028 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010030 break;
10031 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010032 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010033 IterateExternalArrayElements<ExternalDoubleArray, double>(
10034 isolate, receiver, false, false, visitor);
10035 break;
10036 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010037 default:
10038 UNREACHABLE();
10039 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010040 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010041 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010042 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010043}
10044
10045
10046/**
10047 * Array::concat implementation.
10048 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010050 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010051 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010052RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010053 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010054 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010055
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010056 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 int argument_count = static_cast<int>(arguments->length()->Number());
10058 RUNTIME_ASSERT(arguments->HasFastElements());
10059 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010060
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010061 // Pass 1: estimate the length and number of elements of the result.
10062 // The actual length can be larger if any of the arguments have getters
10063 // that mutate other arguments (but will otherwise be precise).
10064 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010065
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010066 uint32_t estimate_result_length = 0;
10067 uint32_t estimate_nof_elements = 0;
10068 {
10069 for (int i = 0; i < argument_count; i++) {
10070 HandleScope loop_scope;
10071 Handle<Object> obj(elements->get(i));
10072 uint32_t length_estimate;
10073 uint32_t element_estimate;
10074 if (obj->IsJSArray()) {
10075 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010076 // TODO(1810): Find out if it's worthwhile to properly support
10077 // arbitrary ElementsKinds. For now, pessimistically transition to
10078 // FAST_ELEMENTS.
10079 if (array->HasFastDoubleElements()) {
10080 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010081 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010082 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010083 length_estimate =
10084 static_cast<uint32_t>(array->length()->Number());
10085 element_estimate =
10086 EstimateElementCount(array);
10087 } else {
10088 length_estimate = 1;
10089 element_estimate = 1;
10090 }
10091 // Avoid overflows by capping at kMaxElementCount.
10092 if (JSObject::kMaxElementCount - estimate_result_length <
10093 length_estimate) {
10094 estimate_result_length = JSObject::kMaxElementCount;
10095 } else {
10096 estimate_result_length += length_estimate;
10097 }
10098 if (JSObject::kMaxElementCount - estimate_nof_elements <
10099 element_estimate) {
10100 estimate_nof_elements = JSObject::kMaxElementCount;
10101 } else {
10102 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010103 }
10104 }
10105 }
10106
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010107 // If estimated number of elements is more than half of length, a
10108 // fixed array (fast case) is more time and space-efficient than a
10109 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010110 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010111
10112 Handle<FixedArray> storage;
10113 if (fast_case) {
10114 // The backing storage array must have non-existing elements to
10115 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 storage = isolate->factory()->NewFixedArrayWithHoles(
10117 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010118 } else {
10119 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10120 uint32_t at_least_space_for = estimate_nof_elements +
10121 (estimate_nof_elements >> 2);
10122 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010123 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010124 }
10125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010127
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010128 for (int i = 0; i < argument_count; i++) {
10129 Handle<Object> obj(elements->get(i));
10130 if (obj->IsJSArray()) {
10131 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010132 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010133 return Failure::Exception();
10134 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010135 } else {
10136 visitor.visit(0, obj);
10137 visitor.increase_index_offset(1);
10138 }
10139 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010140
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010141 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010142}
10143
10144
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145// This will not allocate (flatten the string), but it may run
10146// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010147RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148 NoHandleAllocation ha;
10149 ASSERT(args.length() == 1);
10150
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010151 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 StringInputBuffer buffer(string);
10153 while (buffer.has_more()) {
10154 uint16_t character = buffer.GetNext();
10155 PrintF("%c", character);
10156 }
10157 return string;
10158}
10159
ager@chromium.org5ec48922009-05-05 07:25:34 +000010160// Moves all own elements of an object, that are below a limit, to positions
10161// starting at zero. All undefined values are placed after non-undefined values,
10162// and are followed by non-existing element. Does not change the length
10163// property.
10164// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010165RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010166 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010167 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010168 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10169 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170}
10171
10172
10173// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010174RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010175 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010176 CONVERT_ARG_CHECKED(JSArray, from, 0);
10177 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010178 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010179 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010180 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10182 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010183 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010184 } else if (new_elements->map() ==
10185 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010186 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010187 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010188 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010189 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010190 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010191 Object* new_map;
10192 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010193 to->set_map(Map::cast(new_map));
10194 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010196 Object* obj;
10197 { MaybeObject* maybe_obj = from->ResetElements();
10198 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10199 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010200 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 return to;
10202}
10203
10204
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010205// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010206RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010208 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010209 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010211 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10212 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010213 } else if (object->IsJSArray()) {
10214 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010215 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010216 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217 }
10218}
10219
10220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010221RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010223
10224 ASSERT_EQ(3, args.length());
10225
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010226 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010227 Handle<Object> key1 = args.at<Object>(1);
10228 Handle<Object> key2 = args.at<Object>(2);
10229
10230 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010231 if (!key1->ToArrayIndex(&index1)
10232 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010234 }
10235
ager@chromium.orgac091b72010-05-05 07:34:42 +000010236 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010237 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010239 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010240 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010241
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010242 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010243 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010244 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010245 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010247 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010248}
10249
10250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010252// might have elements. Can either return keys (positive integers) or
10253// intervals (pair of a negative integer (-start-1) followed by a
10254// positive (length)) or undefined values.
10255// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010256RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010259 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010261 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 // Create an array and get all the keys into it, then remove all the
10263 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010264 bool threw = false;
10265 Handle<FixedArray> keys =
10266 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10267 if (threw) return Failure::Exception();
10268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 int keys_length = keys->length();
10270 for (int i = 0; i < keys_length; i++) {
10271 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010272 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010273 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 // Zap invalid keys.
10275 keys->set_undefined(i);
10276 }
10277 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010280 ASSERT(array->HasFastElements() ||
10281 array->HasFastSmiOnlyElements() ||
10282 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010285 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010286 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010287 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010288 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010289 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010291 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010293 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 }
10295}
10296
10297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010298RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010300 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10301 CONVERT_ARG_CHECKED(String, name, 1);
10302 CONVERT_SMI_ARG_CHECKED(flag, 2);
10303 return obj->LookupAccessor(name, flag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304}
10305
10306
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010307#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010308RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010309 ASSERT(args.length() == 0);
10310 return Execution::DebugBreakHelper();
10311}
10312
10313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314// Helper functions for wrapping and unwrapping stack frame ids.
10315static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010316 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317 return Smi::FromInt(id >> 2);
10318}
10319
10320
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010321static StackFrame::Id UnwrapFrameId(int wrapped) {
10322 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323}
10324
10325
10326// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010327// args[0]: debug event listener function to set or null or undefined for
10328// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010330RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010332 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10333 args[0]->IsUndefined() ||
10334 args[0]->IsNull());
10335 Handle<Object> callback = args.at<Object>(0);
10336 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340}
10341
10342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010343RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010344 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 isolate->stack_guard()->DebugBreak();
10346 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347}
10348
10349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350static MaybeObject* DebugLookupResultValue(Heap* heap,
10351 Object* receiver,
10352 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010353 LookupResult* result,
10354 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010355 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010357 case NORMAL:
10358 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010359 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010361 }
10362 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010363 case FIELD:
10364 value =
10365 JSObject::cast(
10366 result->holder())->FastPropertyAt(result->GetFieldIndex());
10367 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010369 }
10370 return value;
10371 case CONSTANT_FUNCTION:
10372 return result->GetConstantFunction();
10373 case CALLBACKS: {
10374 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010375 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010376 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10377 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010378 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010379 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010380 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 maybe_value = heap->isolate()->pending_exception();
10382 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010383 if (caught_exception != NULL) {
10384 *caught_exception = true;
10385 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010386 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010387 }
10388 return value;
10389 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010391 }
10392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010394 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010395 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010396 case CONSTANT_TRANSITION:
10397 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010399 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010401 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010403 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405}
10406
10407
ager@chromium.org32912102009-01-16 10:38:43 +000010408// Get debugger related details for an object property.
10409// args[0]: object holding property
10410// args[1]: name of the property
10411//
10412// The array returned contains the following information:
10413// 0: Property value
10414// 1: Property details
10415// 2: Property value is exception
10416// 3: Getter function if defined
10417// 4: Setter function if defined
10418// Items 2-4 are only filled if the property has either a getter or a setter
10419// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010420RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010422
10423 ASSERT(args.length() == 2);
10424
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010425 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10426 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010428 // Make sure to set the current context to the context before the debugger was
10429 // entered (if the debugger is entered). The reason for switching context here
10430 // is that for some property lookups (accessors and interceptors) callbacks
10431 // into the embedding application can occour, and the embedding application
10432 // could have the assumption that its own global context is the current
10433 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 SaveContext save(isolate);
10435 if (isolate->debug()->InDebugger()) {
10436 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010437 }
10438
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010439 // Skip the global proxy as it has no properties and always delegates to the
10440 // real global object.
10441 if (obj->IsJSGlobalProxy()) {
10442 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10443 }
10444
10445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 // Check if the name is trivially convertible to an index and get the element
10447 // if so.
10448 uint32_t index;
10449 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010451 Object* element_or_char;
10452 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010453 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010454 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10455 return maybe_element_or_char;
10456 }
10457 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010458 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 }
10462
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010463 // Find the number of objects making up this.
10464 int length = LocalPrototypeChainLength(*obj);
10465
10466 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010467 Handle<JSObject> jsproto = obj;
10468 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010469 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010470 jsproto->LocalLookup(*name, &result);
10471 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010472 // LookupResult is not GC safe as it holds raw object pointers.
10473 // GC can happen later in this code so put the required fields into
10474 // local variables using handles when required for later use.
10475 PropertyType result_type = result.type();
10476 Handle<Object> result_callback_obj;
10477 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10479 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010480 }
10481 Smi* property_details = result.GetPropertyDetails().AsSmi();
10482 // DebugLookupResultValue can cause GC so details from LookupResult needs
10483 // to be copied to handles before this.
10484 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010485 Object* raw_value;
10486 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 DebugLookupResultValue(isolate->heap(), *obj, *name,
10488 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010489 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10490 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010492
10493 // If the callback object is a fixed array then it contains JavaScript
10494 // getter and/or setter.
10495 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010496 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010497 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010498 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010499 details->set(0, *value);
10500 details->set(1, property_details);
10501 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010502 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010503 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10504 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010505 }
10506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010508 }
10509 if (i < length - 1) {
10510 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10511 }
10512 }
10513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515}
10516
10517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010518RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520
10521 ASSERT(args.length() == 2);
10522
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010523 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10524 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010526 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 obj->Lookup(*name, &result);
10528 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010531 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532}
10533
10534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535// Return the property type calculated from the property details.
10536// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010537RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010538 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010539 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10540 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541}
10542
10543
10544// Return the property attribute calculated from the property details.
10545// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010546RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010548 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10549 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010550}
10551
10552
10553// Return the property insertion index calculated from the property details.
10554// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010555RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010557 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10558 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559}
10560
10561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010562// Return property value from named interceptor.
10563// args[0]: object
10564// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010565RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010568 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010570 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571
10572 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010573 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574}
10575
10576
10577// Return element value from indexed interceptor.
10578// args[0]: object
10579// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010580RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010583 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10585 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10586
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010587 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588}
10589
10590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010591RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010592 ASSERT(args.length() >= 1);
10593 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010594 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 if (isolate->debug()->break_id() == 0 ||
10596 break_id != isolate->debug()->break_id()) {
10597 return isolate->Throw(
10598 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 }
10600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010601 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602}
10603
10604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010605RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 ASSERT(args.length() == 1);
10608
10609 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010610 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010611 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10612 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010613 if (!maybe_result->ToObject(&result)) return maybe_result;
10614 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615
10616 // Count all frames which are relevant to debugging stack trace.
10617 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010619 if (id == StackFrame::NO_ID) {
10620 // If there is no JavaScript stack frame count is 0.
10621 return Smi::FromInt(0);
10622 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010623
10624 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10625 n += it.frame()->GetInlineCount();
10626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 return Smi::FromInt(n);
10628}
10629
10630
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010631class FrameInspector {
10632 public:
10633 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010634 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010635 Isolate* isolate)
10636 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10637 // Calculate the deoptimized frame.
10638 if (frame->is_optimized()) {
10639 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010640 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010641 }
10642 has_adapted_arguments_ = frame_->has_adapted_arguments();
10643 is_optimized_ = frame_->is_optimized();
10644 }
10645
10646 ~FrameInspector() {
10647 // Get rid of the calculated deoptimized frame if any.
10648 if (deoptimized_frame_ != NULL) {
10649 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10650 isolate_);
10651 }
10652 }
10653
10654 int GetParametersCount() {
10655 return is_optimized_
10656 ? deoptimized_frame_->parameters_count()
10657 : frame_->ComputeParametersCount();
10658 }
10659 int expression_count() { return deoptimized_frame_->expression_count(); }
10660 Object* GetFunction() {
10661 return is_optimized_
10662 ? deoptimized_frame_->GetFunction()
10663 : frame_->function();
10664 }
10665 Object* GetParameter(int index) {
10666 return is_optimized_
10667 ? deoptimized_frame_->GetParameter(index)
10668 : frame_->GetParameter(index);
10669 }
10670 Object* GetExpression(int index) {
10671 return is_optimized_
10672 ? deoptimized_frame_->GetExpression(index)
10673 : frame_->GetExpression(index);
10674 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010675 int GetSourcePosition() {
10676 return is_optimized_
10677 ? deoptimized_frame_->GetSourcePosition()
10678 : frame_->LookupCode()->SourcePosition(frame_->pc());
10679 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010680
10681 // To inspect all the provided arguments the frame might need to be
10682 // replaced with the arguments frame.
10683 void SetArgumentsFrame(JavaScriptFrame* frame) {
10684 ASSERT(has_adapted_arguments_);
10685 frame_ = frame;
10686 is_optimized_ = frame_->is_optimized();
10687 ASSERT(!is_optimized_);
10688 }
10689
10690 private:
10691 JavaScriptFrame* frame_;
10692 DeoptimizedFrameInfo* deoptimized_frame_;
10693 Isolate* isolate_;
10694 bool is_optimized_;
10695 bool has_adapted_arguments_;
10696
10697 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10698};
10699
10700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701static const int kFrameDetailsFrameIdIndex = 0;
10702static const int kFrameDetailsReceiverIndex = 1;
10703static const int kFrameDetailsFunctionIndex = 2;
10704static const int kFrameDetailsArgumentCountIndex = 3;
10705static const int kFrameDetailsLocalCountIndex = 4;
10706static const int kFrameDetailsSourcePositionIndex = 5;
10707static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010708static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010709static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010710static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010712
10713static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10714 JavaScriptFrame* frame) {
10715 SaveContext* save = isolate->save_context();
10716 while (save != NULL && !save->IsBelowFrame(frame)) {
10717 save = save->prev();
10718 }
10719 ASSERT(save != NULL);
10720 return save;
10721}
10722
10723
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010724// Return an array with frame details
10725// args[0]: number: break id
10726// args[1]: number: frame index
10727//
10728// The array returned contains the following information:
10729// 0: Frame id
10730// 1: Receiver
10731// 2: Function
10732// 3: Argument count
10733// 4: Local count
10734// 5: Source position
10735// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010736// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010737// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738// Arguments name, value
10739// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010740// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010741RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 ASSERT(args.length() == 2);
10744
10745 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010746 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010747 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10748 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010749 if (!maybe_check->ToObject(&check)) return maybe_check;
10750 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753
10754 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010756 if (id == StackFrame::NO_ID) {
10757 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010758 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010759 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010762 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010764 if (index < count + it.frame()->GetInlineCount()) break;
10765 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010766 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010769 bool is_optimized = it.frame()->is_optimized();
10770
10771 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10772 if (is_optimized) {
10773 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010774 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010775 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010776 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778 // Traverse the saved contexts chain to find the active context for the
10779 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010780 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781
10782 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010783 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010784
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010785 // Find source position in unoptimized code.
10786 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010788 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010789 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010790 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010792 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010793 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010794 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010795 Handle<ScopeInfo> scope_info(shared->scope_info());
10796 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798 // Get the locals names and values into a temporary array.
10799 //
10800 // TODO(1240907): Hide compiler-introduced stack variables
10801 // (e.g. .result)? For users of the debugger, they will probably be
10802 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010804 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010806 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010807 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010808 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010809 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010810 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010811 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010812 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010813 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010814 // Get the context containing declarations.
10815 Handle<Context> context(
10816 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010817 for (; i < scope_info->LocalCount(); ++i) {
10818 Handle<String> name(scope_info->LocalName(i));
10819 VariableMode mode;
10820 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010821 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010822 locals->set(i * 2 + 1, context->get(
10823 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824 }
10825 }
10826
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010827 // Check whether this frame is positioned at return. If not top
10828 // frame or if the frame is optimized it cannot be at a return.
10829 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010830 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010832 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010833
10834 // If positioned just before return find the value to be returned and add it
10835 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010837 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010838 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010839 Address internal_frame_sp = NULL;
10840 while (!it2.done()) {
10841 if (it2.frame()->is_internal()) {
10842 internal_frame_sp = it2.frame()->sp();
10843 } else {
10844 if (it2.frame()->is_java_script()) {
10845 if (it2.frame()->id() == it.frame()->id()) {
10846 // The internal frame just before the JavaScript frame contains the
10847 // value to return on top. A debug break at return will create an
10848 // internal frame to store the return value (eax/rax/r0) before
10849 // entering the debug break exit frame.
10850 if (internal_frame_sp != NULL) {
10851 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 Handle<Object>(Memory::Object_at(internal_frame_sp),
10853 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010854 break;
10855 }
10856 }
10857 }
10858
10859 // Indicate that the previous frame was not an internal frame.
10860 internal_frame_sp = NULL;
10861 }
10862 it2.Advance();
10863 }
10864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865
10866 // Now advance to the arguments adapter frame (if any). It contains all
10867 // the provided parameters whereas the function frame always have the number
10868 // of arguments matching the functions parameters. The rest of the
10869 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010870 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010871 it.AdvanceToArgumentsFrame();
10872 frame_inspector.SetArgumentsFrame(it.frame());
10873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
10875 // Find the number of arguments to fill. At least fill the number of
10876 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010877 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010878 if (argument_count < frame_inspector.GetParametersCount()) {
10879 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 }
10881
10882 // Calculate the size of the result.
10883 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010884 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010885 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010886 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887
10888 // Add the frame id.
10889 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10890
10891 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010892 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893
10894 // Add the arguments count.
10895 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10896
10897 // Add the locals count
10898 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010899 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900
10901 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010902 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10904 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010905 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906 }
10907
10908 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010911 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010913
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010914 // Add flags to indicate information on whether this frame is
10915 // bit 0: invoked in the debugger context.
10916 // bit 1: optimized frame.
10917 // bit 2: inlined in optimized frame
10918 int flags = 0;
10919 if (*save->context() == *isolate->debug()->debug_context()) {
10920 flags |= 1 << 0;
10921 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010922 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010923 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010924 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010925 }
10926 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927
10928 // Fill the dynamic part.
10929 int details_index = kFrameDetailsFirstDynamicIndex;
10930
10931 // Add arguments name and value.
10932 for (int i = 0; i < argument_count; i++) {
10933 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010934 if (i < scope_info->ParameterCount()) {
10935 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010937 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 }
10939
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010940 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010941 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010942 // Get the value from the stack.
10943 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010945 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 }
10947 }
10948
10949 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010950 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 details->set(details_index++, locals->get(i));
10952 }
10953
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010954 // Add the value being returned.
10955 if (at_return) {
10956 details->set(details_index++, *return_value);
10957 }
10958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 // Add the receiver (same as in function frame).
10960 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10961 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010963 if (!receiver->IsJSObject() &&
10964 shared->is_classic_mode() &&
10965 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010966 // If the receiver is not a JSObject and the function is not a
10967 // builtin or strict-mode we have hit an optimization where a
10968 // value object is not converted into a wrapped JS objects. To
10969 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010970 // by creating correct wrapper object based on the calling frame's
10971 // global context.
10972 it.Advance();
10973 Handle<Context> calling_frames_global_context(
10974 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 receiver =
10976 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 }
10978 details->set(kFrameDetailsReceiverIndex, *receiver);
10979
10980 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982}
10983
10984
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010985// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010986static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010988 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010989 Handle<Context> context,
10990 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010991 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010992 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10993 VariableMode mode;
10994 InitializationFlag init_flag;
10995 int context_index = scope_info->ContextSlotIndex(
10996 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010997
whesse@chromium.org7b260152011-06-20 15:33:18 +000010998 RETURN_IF_EMPTY_HANDLE_VALUE(
10999 isolate,
11000 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011001 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011002 Handle<Object>(context->get(context_index), isolate),
11003 NONE,
11004 kNonStrictMode),
11005 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011006 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011007
11008 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009}
11010
11011
11012// Create a plain JSObject which materializes the local scope for the specified
11013// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011014static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011015 Isolate* isolate,
11016 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011017 FrameInspector* frame_inspector) {
11018 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011019 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011020 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011021
11022 // Allocate and initialize a JSObject with all the arguments, stack locals
11023 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011024 Handle<JSObject> local_scope =
11025 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011026
11027 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011028 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011029 Handle<Object> value(
11030 i < frame_inspector->GetParametersCount() ?
11031 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11032
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011033 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011034 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011035 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011036 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011037 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011038 NONE,
11039 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011040 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011041 }
11042
11043 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011044 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011045 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011046 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011047 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011048 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011049 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011050 NONE,
11051 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011052 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011053 }
11054
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011055 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011056 // Third fill all context locals.
11057 Handle<Context> frame_context(Context::cast(frame->context()));
11058 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011059 if (!CopyContextLocalsToScopeObject(
11060 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011061 return Handle<JSObject>();
11062 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011063
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011064 // Finally copy any properties from the function context extension.
11065 // These will be variables introduced by eval.
11066 if (function_context->closure() == *function) {
11067 if (function_context->has_extension() &&
11068 !function_context->IsGlobalContext()) {
11069 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011070 bool threw = false;
11071 Handle<FixedArray> keys =
11072 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11073 if (threw) return Handle<JSObject>();
11074
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011075 for (int i = 0; i < keys->length(); i++) {
11076 // Names of variables introduced by eval are strings.
11077 ASSERT(keys->get(i)->IsString());
11078 Handle<String> key(String::cast(keys->get(i)));
11079 RETURN_IF_EMPTY_HANDLE_VALUE(
11080 isolate,
11081 SetProperty(local_scope,
11082 key,
11083 GetProperty(ext, key),
11084 NONE,
11085 kNonStrictMode),
11086 Handle<JSObject>());
11087 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 }
11089 }
11090 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011091
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011092 return local_scope;
11093}
11094
11095
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011096static Handle<JSObject> MaterializeLocalScope(
11097 Isolate* isolate,
11098 JavaScriptFrame* frame,
11099 int inlined_jsframe_index) {
11100 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11101 return MaterializeLocalScopeWithFrameInspector(isolate,
11102 frame,
11103 &frame_inspector);
11104}
11105
11106
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011107// Create a plain JSObject which materializes the closure content for the
11108// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011109static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11110 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011111 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011113 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011114 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011115
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011116 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118 Handle<JSObject> closure_scope =
11119 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011122 if (!CopyContextLocalsToScopeObject(
11123 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011124 return Handle<JSObject>();
11125 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011126
11127 // Finally copy any properties from the function context extension. This will
11128 // be variables introduced by eval.
11129 if (context->has_extension()) {
11130 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011131 bool threw = false;
11132 Handle<FixedArray> keys =
11133 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11134 if (threw) return Handle<JSObject>();
11135
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011136 for (int i = 0; i < keys->length(); i++) {
11137 // Names of variables introduced by eval are strings.
11138 ASSERT(keys->get(i)->IsString());
11139 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 RETURN_IF_EMPTY_HANDLE_VALUE(
11141 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011142 SetProperty(closure_scope,
11143 key,
11144 GetProperty(ext, key),
11145 NONE,
11146 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011147 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011148 }
11149 }
11150
11151 return closure_scope;
11152}
11153
11154
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011155// Create a plain JSObject which materializes the scope for the specified
11156// catch context.
11157static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11158 Handle<Context> context) {
11159 ASSERT(context->IsCatchContext());
11160 Handle<String> name(String::cast(context->extension()));
11161 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11162 Handle<JSObject> catch_scope =
11163 isolate->factory()->NewJSObject(isolate->object_function());
11164 RETURN_IF_EMPTY_HANDLE_VALUE(
11165 isolate,
11166 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11167 Handle<JSObject>());
11168 return catch_scope;
11169}
11170
11171
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011172// Create a plain JSObject which materializes the block scope for the specified
11173// block context.
11174static Handle<JSObject> MaterializeBlockScope(
11175 Isolate* isolate,
11176 Handle<Context> context) {
11177 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011178 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011179
11180 // Allocate and initialize a JSObject with all the arguments, stack locals
11181 // heap locals and extension properties of the debugged function.
11182 Handle<JSObject> block_scope =
11183 isolate->factory()->NewJSObject(isolate->object_function());
11184
11185 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011186 if (!CopyContextLocalsToScopeObject(
11187 isolate, scope_info, context, block_scope)) {
11188 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011189 }
11190
11191 return block_scope;
11192}
11193
11194
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011195// Create a plain JSObject which materializes the module scope for the specified
11196// module context.
11197static Handle<JSObject> MaterializeModuleScope(
11198 Isolate* isolate,
11199 Handle<Context> context) {
11200 ASSERT(context->IsModuleContext());
11201 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11202
11203 // Allocate and initialize a JSObject with all the members of the debugged
11204 // module.
11205 Handle<JSObject> module_scope =
11206 isolate->factory()->NewJSObject(isolate->object_function());
11207
11208 // Fill all context locals.
11209 if (!CopyContextLocalsToScopeObject(
11210 isolate, scope_info, context, module_scope)) {
11211 return Handle<JSObject>();
11212 }
11213
11214 return module_scope;
11215}
11216
11217
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011218// Iterate over the actual scopes visible from a stack frame. The iteration
11219// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011220// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011221// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011222class ScopeIterator {
11223 public:
11224 enum ScopeType {
11225 ScopeTypeGlobal = 0,
11226 ScopeTypeLocal,
11227 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011228 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011229 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011230 ScopeTypeBlock,
11231 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232 };
11233
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011234 ScopeIterator(Isolate* isolate,
11235 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011236 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011237 : isolate_(isolate),
11238 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011239 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240 function_(JSFunction::cast(frame->function())),
11241 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011242 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011243
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011244 // Catch the case when the debugger stops in an internal function.
11245 Handle<SharedFunctionInfo> shared_info(function_->shared());
11246 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11247 if (shared_info->script() == isolate->heap()->undefined_value()) {
11248 while (context_->closure() == *function_) {
11249 context_ = Handle<Context>(context_->previous(), isolate_);
11250 }
11251 return;
11252 }
11253
11254 // Get the debug info (create it if it does not exist).
11255 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11256 // Return if ensuring debug info failed.
11257 return;
11258 }
11259 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11260
11261 // Find the break point where execution has stopped.
11262 BreakLocationIterator break_location_iterator(debug_info,
11263 ALL_BREAK_LOCATIONS);
11264 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11265 if (break_location_iterator.IsExit()) {
11266 // We are within the return sequence. At the momemt it is not possible to
11267 // get a source position which is consistent with the current scope chain.
11268 // Thus all nested with, catch and block contexts are skipped and we only
11269 // provide the function scope.
11270 if (scope_info->HasContext()) {
11271 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11272 } else {
11273 while (context_->closure() == *function_) {
11274 context_ = Handle<Context>(context_->previous(), isolate_);
11275 }
11276 }
11277 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11278 } else {
11279 // Reparse the code and analyze the scopes.
11280 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11281 Handle<Script> script(Script::cast(shared_info->script()));
11282 Scope* scope = NULL;
11283
11284 // Check whether we are in global, eval or function code.
11285 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11286 if (scope_info->Type() != FUNCTION_SCOPE) {
11287 // Global or eval code.
11288 CompilationInfo info(script);
11289 if (scope_info->Type() == GLOBAL_SCOPE) {
11290 info.MarkAsGlobal();
11291 } else {
11292 ASSERT(scope_info->Type() == EVAL_SCOPE);
11293 info.MarkAsEval();
11294 info.SetCallingContext(Handle<Context>(function_->context()));
11295 }
11296 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11297 scope = info.function()->scope();
11298 }
11299 } else {
11300 // Function code
11301 CompilationInfo info(shared_info);
11302 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11303 scope = info.function()->scope();
11304 }
11305 }
11306
11307 // Retrieve the scope chain for the current position.
11308 if (scope != NULL) {
11309 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11310 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11311 } else {
11312 // A failed reparse indicates that the preparser has diverged from the
11313 // parser or that the preparse data given to the initial parse has been
11314 // faulty. We fail in debug mode but in release mode we only provide the
11315 // information we get from the context chain but nothing about
11316 // completely stack allocated scopes or stack allocated locals.
11317 UNREACHABLE();
11318 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011319 }
11320 }
11321
11322 // More scopes?
11323 bool Done() { return context_.is_null(); }
11324
11325 // Move to the next scope.
11326 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011327 ScopeType scope_type = Type();
11328 if (scope_type == ScopeTypeGlobal) {
11329 // The global scope is always the last in the chain.
11330 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011331 context_ = Handle<Context>();
11332 return;
11333 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011334 if (nested_scope_chain_.is_empty()) {
11335 context_ = Handle<Context>(context_->previous(), isolate_);
11336 } else {
11337 if (nested_scope_chain_.last()->HasContext()) {
11338 ASSERT(context_->previous() != NULL);
11339 context_ = Handle<Context>(context_->previous(), isolate_);
11340 }
11341 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011342 }
11343 }
11344
11345 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011346 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011347 if (!nested_scope_chain_.is_empty()) {
11348 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11349 switch (scope_info->Type()) {
11350 case FUNCTION_SCOPE:
11351 ASSERT(context_->IsFunctionContext() ||
11352 !scope_info->HasContext());
11353 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011354 case MODULE_SCOPE:
11355 ASSERT(context_->IsModuleContext());
11356 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011357 case GLOBAL_SCOPE:
11358 ASSERT(context_->IsGlobalContext());
11359 return ScopeTypeGlobal;
11360 case WITH_SCOPE:
11361 ASSERT(context_->IsWithContext());
11362 return ScopeTypeWith;
11363 case CATCH_SCOPE:
11364 ASSERT(context_->IsCatchContext());
11365 return ScopeTypeCatch;
11366 case BLOCK_SCOPE:
11367 ASSERT(!scope_info->HasContext() ||
11368 context_->IsBlockContext());
11369 return ScopeTypeBlock;
11370 case EVAL_SCOPE:
11371 UNREACHABLE();
11372 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011373 }
11374 if (context_->IsGlobalContext()) {
11375 ASSERT(context_->global()->IsGlobalObject());
11376 return ScopeTypeGlobal;
11377 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011378 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011379 return ScopeTypeClosure;
11380 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011381 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011382 return ScopeTypeCatch;
11383 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011384 if (context_->IsBlockContext()) {
11385 return ScopeTypeBlock;
11386 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011387 if (context_->IsModuleContext()) {
11388 return ScopeTypeModule;
11389 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011390 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011391 return ScopeTypeWith;
11392 }
11393
11394 // Return the JavaScript object with the content of the current scope.
11395 Handle<JSObject> ScopeObject() {
11396 switch (Type()) {
11397 case ScopeIterator::ScopeTypeGlobal:
11398 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011399 case ScopeIterator::ScopeTypeLocal:
11400 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011401 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011402 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011403 case ScopeIterator::ScopeTypeWith:
11404 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011405 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11406 case ScopeIterator::ScopeTypeCatch:
11407 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011408 case ScopeIterator::ScopeTypeClosure:
11409 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011411 case ScopeIterator::ScopeTypeBlock:
11412 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011413 case ScopeIterator::ScopeTypeModule:
11414 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011415 }
11416 UNREACHABLE();
11417 return Handle<JSObject>();
11418 }
11419
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011420 Handle<ScopeInfo> CurrentScopeInfo() {
11421 if (!nested_scope_chain_.is_empty()) {
11422 return nested_scope_chain_.last();
11423 } else if (context_->IsBlockContext()) {
11424 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11425 } else if (context_->IsFunctionContext()) {
11426 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11427 }
11428 return Handle<ScopeInfo>::null();
11429 }
11430
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011431 // Return the context for this scope. For the local context there might not
11432 // be an actual context.
11433 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011434 if (Type() == ScopeTypeGlobal ||
11435 nested_scope_chain_.is_empty()) {
11436 return context_;
11437 } else if (nested_scope_chain_.last()->HasContext()) {
11438 return context_;
11439 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011440 return Handle<Context>();
11441 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011442 }
11443
11444#ifdef DEBUG
11445 // Debug print of the content of the current scope.
11446 void DebugPrint() {
11447 switch (Type()) {
11448 case ScopeIterator::ScopeTypeGlobal:
11449 PrintF("Global:\n");
11450 CurrentContext()->Print();
11451 break;
11452
11453 case ScopeIterator::ScopeTypeLocal: {
11454 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011455 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011456 if (!CurrentContext().is_null()) {
11457 CurrentContext()->Print();
11458 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011459 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011460 if (extension->IsJSContextExtensionObject()) {
11461 extension->Print();
11462 }
11463 }
11464 }
11465 break;
11466 }
11467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011468 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011469 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011470 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011471 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011472
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011473 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011474 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011475 CurrentContext()->extension()->Print();
11476 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011477 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011478
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011479 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011480 PrintF("Closure:\n");
11481 CurrentContext()->Print();
11482 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011483 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011484 if (extension->IsJSContextExtensionObject()) {
11485 extension->Print();
11486 }
11487 }
11488 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011489
11490 default:
11491 UNREACHABLE();
11492 }
11493 PrintF("\n");
11494 }
11495#endif
11496
11497 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011499 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011500 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 Handle<JSFunction> function_;
11502 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011503 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011504
11505 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11506};
11507
11508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011509RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011511 ASSERT(args.length() == 2);
11512
11513 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011514 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011515 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11516 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011517 if (!maybe_check->ToObject(&check)) return maybe_check;
11518 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011519 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011520
11521 // Get the frame where the debugging is performed.
11522 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011523 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524 JavaScriptFrame* frame = it.frame();
11525
11526 // Count the visible scopes.
11527 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011528 for (ScopeIterator it(isolate, frame, 0);
11529 !it.Done();
11530 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531 n++;
11532 }
11533
11534 return Smi::FromInt(n);
11535}
11536
11537
11538static const int kScopeDetailsTypeIndex = 0;
11539static const int kScopeDetailsObjectIndex = 1;
11540static const int kScopeDetailsSize = 2;
11541
11542// Return an array with scope details
11543// args[0]: number: break id
11544// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011545// args[2]: number: inlined frame index
11546// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011547//
11548// The array returned contains the following information:
11549// 0: Scope type
11550// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011551RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011553 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011554
11555 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011556 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011557 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11558 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011559 if (!maybe_check->ToObject(&check)) return maybe_check;
11560 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011561 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011562 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011563 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011564
11565 // Get the frame where the debugging is performed.
11566 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011567 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568 JavaScriptFrame* frame = frame_it.frame();
11569
11570 // Find the requested scope.
11571 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011572 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011573 for (; !it.Done() && n < index; it.Next()) {
11574 n++;
11575 }
11576 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011577 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011578 }
11579
11580 // Calculate the size of the result.
11581 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011582 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011583
11584 // Fill in scope details.
11585 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011586 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011587 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011588 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591}
11592
11593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011596 ASSERT(args.length() == 0);
11597
11598#ifdef DEBUG
11599 // Print the scopes for the top frame.
11600 StackFrameLocator locator;
11601 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011602 for (ScopeIterator it(isolate, frame, 0);
11603 !it.Done();
11604 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605 it.DebugPrint();
11606 }
11607#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011609}
11610
11611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011612RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011614 ASSERT(args.length() == 1);
11615
11616 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011617 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011618 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11619 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011620 if (!maybe_result->ToObject(&result)) return maybe_result;
11621 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011622
11623 // Count all archived V8 threads.
11624 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 for (ThreadState* thread =
11626 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011627 thread != NULL;
11628 thread = thread->Next()) {
11629 n++;
11630 }
11631
11632 // Total number of threads is current thread and archived threads.
11633 return Smi::FromInt(n + 1);
11634}
11635
11636
11637static const int kThreadDetailsCurrentThreadIndex = 0;
11638static const int kThreadDetailsThreadIdIndex = 1;
11639static const int kThreadDetailsSize = 2;
11640
11641// Return an array with thread details
11642// args[0]: number: break id
11643// args[1]: number: thread index
11644//
11645// The array returned contains the following information:
11646// 0: Is current thread?
11647// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011648RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011650 ASSERT(args.length() == 2);
11651
11652 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011653 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11655 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011656 if (!maybe_check->ToObject(&check)) return maybe_check;
11657 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011658 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11659
11660 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 Handle<FixedArray> details =
11662 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011663
11664 // Thread index 0 is current thread.
11665 if (index == 0) {
11666 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 details->set(kThreadDetailsCurrentThreadIndex,
11668 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011669 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011670 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011671 } else {
11672 // Find the thread with the requested index.
11673 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011674 ThreadState* thread =
11675 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011676 while (index != n && thread != NULL) {
11677 thread = thread->Next();
11678 n++;
11679 }
11680 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011682 }
11683
11684 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685 details->set(kThreadDetailsCurrentThreadIndex,
11686 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011687 details->set(kThreadDetailsThreadIdIndex,
11688 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011689 }
11690
11691 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011693}
11694
11695
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011696// Sets the disable break state
11697// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011698RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011700 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011701 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 isolate->debug()->set_disable_break(disable_break);
11703 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011704}
11705
11706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709 ASSERT(args.length() == 1);
11710
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011711 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011712 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011713 // Find the number of break points
11714 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011716 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011717 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011718 Handle<FixedArray>::cast(break_locations));
11719}
11720
11721
11722// Set a break point in a function
11723// args[0]: function
11724// args[1]: number: break source position (within the function source)
11725// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011726RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011728 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011729 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011730 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011731 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11732 RUNTIME_ASSERT(source_position >= 0);
11733 Handle<Object> break_point_object_arg = args.at<Object>(2);
11734
11735 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11737 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011739 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011740}
11741
11742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11744 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011745 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011746 // Iterate the heap looking for SharedFunctionInfo generated from the
11747 // script. The inner most SharedFunctionInfo containing the source position
11748 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011749 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750 // which is found is not compiled it is compiled and the heap is iterated
11751 // again as the compilation might create inner functions from the newly
11752 // compiled function and the actual requested break point might be in one of
11753 // these functions.
11754 bool done = false;
11755 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011756 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011758 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011759 { // Extra scope for iterator and no-allocation.
11760 isolate->heap()->EnsureHeapIsIterable();
11761 AssertNoAllocation no_alloc_during_heap_iteration;
11762 HeapIterator iterator;
11763 for (HeapObject* obj = iterator.next();
11764 obj != NULL; obj = iterator.next()) {
11765 if (obj->IsSharedFunctionInfo()) {
11766 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11767 if (shared->script() == *script) {
11768 // If the SharedFunctionInfo found has the requested script data and
11769 // contains the source position it is a candidate.
11770 int start_position = shared->function_token_position();
11771 if (start_position == RelocInfo::kNoPosition) {
11772 start_position = shared->start_position();
11773 }
11774 if (start_position <= position &&
11775 position <= shared->end_position()) {
11776 // If there is no candidate or this function is within the current
11777 // candidate this is the new candidate.
11778 if (target.is_null()) {
11779 target_start_position = start_position;
11780 target = shared;
11781 } else {
11782 if (target_start_position == start_position &&
11783 shared->end_position() == target->end_position()) {
11784 // If a top-level function contain only one function
11785 // declartion the source for the top-level and the
11786 // function is the same. In that case prefer the non
11787 // top-level function.
11788 if (!shared->is_toplevel()) {
11789 target_start_position = start_position;
11790 target = shared;
11791 }
11792 } else if (target_start_position <= start_position &&
11793 shared->end_position() <= target->end_position()) {
11794 // This containment check includes equality as a function
11795 // inside a top-level function can share either start or end
11796 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011797 target_start_position = start_position;
11798 target = shared;
11799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011800 }
11801 }
11802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011804 } // End for loop.
11805 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011808 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809 }
11810
11811 // If the candidate found is compiled we are done. NOTE: when lazy
11812 // compilation of inner functions is introduced some additional checking
11813 // needs to be done here to compile inner functions.
11814 done = target->is_compiled();
11815 if (!done) {
11816 // If the candidate is not compiled compile it to reveal any inner
11817 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011818 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011819 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011820 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821
11822 return *target;
11823}
11824
11825
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011826// Changes the state of a break point in a script and returns source position
11827// where break point was set. NOTE: Regarding performance see the NOTE for
11828// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829// args[0]: script to set break point in
11830// args[1]: number: break source position (within the script source)
11831// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011832RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011834 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011835 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11837 RUNTIME_ASSERT(source_position >= 0);
11838 Handle<Object> break_point_object_arg = args.at<Object>(2);
11839
11840 // Get the script from the script wrapper.
11841 RUNTIME_ASSERT(wrapper->value()->IsScript());
11842 Handle<Script> script(Script::cast(wrapper->value()));
11843
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011844 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011845 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 if (!result->IsUndefined()) {
11847 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11848 // Find position within function. The script position might be before the
11849 // source position of the first function.
11850 int position;
11851 if (shared->start_position() > source_position) {
11852 position = 0;
11853 } else {
11854 position = source_position - shared->start_position();
11855 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011857 position += shared->start_position();
11858 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861}
11862
11863
11864// Clear a break point
11865// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011866RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 ASSERT(args.length() == 1);
11869 Handle<Object> break_point_object_arg = args.at<Object>(0);
11870
11871 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011873
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011875}
11876
11877
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011878// Change the state of break on exceptions.
11879// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11880// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011881RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011884 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011885 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011887 // If the number doesn't match an enum value, the ChangeBreakOnException
11888 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889 ExceptionBreakType type =
11890 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011891 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 isolate->debug()->ChangeBreakOnException(type, enable);
11893 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894}
11895
11896
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011897// Returns the state of break on exceptions
11898// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011901 ASSERT(args.length() == 1);
11902 RUNTIME_ASSERT(args[0]->IsNumber());
11903
11904 ExceptionBreakType type =
11905 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011906 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011907 return Smi::FromInt(result);
11908}
11909
11910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911// Prepare for stepping
11912// args[0]: break id for checking execution state
11913// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011914// args[2]: number of times to perform the step, for step out it is the number
11915// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011916RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918 ASSERT(args.length() == 3);
11919 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011920 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011921 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11922 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011923 if (!maybe_check->ToObject(&check)) return maybe_check;
11924 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927 }
11928
11929 // Get the step action and check validity.
11930 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11931 if (step_action != StepIn &&
11932 step_action != StepNext &&
11933 step_action != StepOut &&
11934 step_action != StepInMin &&
11935 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937 }
11938
11939 // Get the number of steps.
11940 int step_count = NumberToInt32(args[2]);
11941 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011942 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011943 }
11944
ager@chromium.orga1645e22009-09-09 19:27:10 +000011945 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11950 step_count);
11951 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952}
11953
11954
11955// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011956RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011957 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011958 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 isolate->debug()->ClearStepping();
11960 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961}
11962
11963
11964// Creates a copy of the with context chain. The copy of the context chain is
11965// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011966static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11967 Handle<JSFunction> function,
11968 Handle<Context> base,
11969 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011970 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011971 HandleScope scope(isolate);
11972 List<Handle<ScopeInfo> > scope_chain;
11973 List<Handle<Context> > context_chain;
11974
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011975 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011976 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11977 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11978 ASSERT(!it.Done());
11979 scope_chain.Add(it.CurrentScopeInfo());
11980 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011981 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011982
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011983 // At the end of the chain. Return the base context to link to.
11984 Handle<Context> context = base;
11985
11986 // Iteratively copy and or materialize the nested contexts.
11987 while (!scope_chain.is_empty()) {
11988 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11989 Handle<Context> current = context_chain.RemoveLast();
11990 ASSERT(!(scope_info->HasContext() & current.is_null()));
11991
11992 if (scope_info->Type() == CATCH_SCOPE) {
11993 Handle<String> name(String::cast(current->extension()));
11994 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11995 context =
11996 isolate->factory()->NewCatchContext(function,
11997 context,
11998 name,
11999 thrown_object);
12000 } else if (scope_info->Type() == BLOCK_SCOPE) {
12001 // Materialize the contents of the block scope into a JSObject.
12002 Handle<JSObject> block_scope_object =
12003 MaterializeBlockScope(isolate, current);
12004 if (block_scope_object.is_null()) {
12005 return Handle<Context>::null();
12006 }
12007 // Allocate a new function context for the debug evaluation and set the
12008 // extension object.
12009 Handle<Context> new_context =
12010 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12011 function);
12012 new_context->set_extension(*block_scope_object);
12013 new_context->set_previous(*context);
12014 context = new_context;
12015 } else {
12016 ASSERT(scope_info->Type() == WITH_SCOPE);
12017 ASSERT(current->IsWithContext());
12018 Handle<JSObject> extension(JSObject::cast(current->extension()));
12019 context =
12020 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012021 }
erikcorry0ad885c2011-11-21 13:51:57 +000012022 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012023
12024 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025}
12026
12027
12028// Helper function to find or create the arguments object for
12029// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030static Handle<Object> GetArgumentsObject(Isolate* isolate,
12031 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012032 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012033 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012034 Handle<Context> function_context) {
12035 // Try to find the value of 'arguments' to pass as parameter. If it is not
12036 // found (that is the debugged function does not reference 'arguments' and
12037 // does not support eval) then create an 'arguments' object.
12038 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012039 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012041 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012042 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043 }
12044 }
12045
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012046 if (scope_info->HasHeapAllocatedLocals()) {
12047 VariableMode mode;
12048 InitializationFlag init_flag;
12049 index = scope_info->ContextSlotIndex(
12050 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012052 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 }
12054 }
12055
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012056 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12057 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012058 Handle<JSObject> arguments =
12059 isolate->factory()->NewArgumentsObject(function, length);
12060 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012061
12062 AssertNoAllocation no_gc;
12063 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012064 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012065 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012066 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012067 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068 return arguments;
12069}
12070
12071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072static const char kSourceStr[] =
12073 "(function(arguments,__source__){return eval(__source__);})";
12074
12075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012077// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078// extension part has all the parameters and locals of the function on the
12079// stack frame. A function which calls eval with the code to evaluate is then
12080// compiled in this context and called in this context. As this context
12081// replaces the context of the function on the stack frame a new (empty)
12082// function is created as well to be used as the closure for the context.
12083// This function and the context acts as replacements for the function on the
12084// stack frame presenting the same view of the values of parameters and
12085// local variables as if the piece of JavaScript was evaluated at the point
12086// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012087RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089
12090 // Check the execution state and decode arguments frame and source to be
12091 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012092 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012093 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012094 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12095 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012096 if (!maybe_check_result->ToObject(&check_result)) {
12097 return maybe_check_result;
12098 }
12099 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012100 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012101 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012102 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12103 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012104 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012105
12106 // Handle the processing of break.
12107 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108
12109 // Get the frame where the debugging is performed.
12110 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012111 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012113 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12114 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012115 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116
12117 // Traverse the saved contexts chain to find the active context for the
12118 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012119 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 SaveContext savex(isolate);
12122 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123
12124 // Create the (empty) function replacing the function on the stack frame for
12125 // the purpose of evaluating in the context created below. It is important
12126 // that this function does not describe any parameters and local variables
12127 // in the context. If it does then this will cause problems with the lookup
12128 // in Context::Lookup, where context slots for parameters and local variables
12129 // are looked at before the extension object.
12130 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12132 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012133 go_between->set_context(function->context());
12134#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012135 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12136 ASSERT(go_between_scope_info->ParameterCount() == 0);
12137 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012138#endif
12139
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012140 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012141 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12142 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144
12145 // Allocate a new context for the debug evaluation and set the extension
12146 // object build.
12147 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12149 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012150 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012152 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012153 Handle<Context> function_context;
12154 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012155 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012156 function_context = Handle<Context>(frame_context->declaration_context());
12157 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012158 context = CopyNestedScopeContextChain(isolate,
12159 go_between,
12160 context,
12161 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012162 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012164 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012165 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012166 context =
12167 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012168 }
12169
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170 // Wrap the evaluation statement in a new function compiled in the newly
12171 // created context. The function has one parameter which has to be called
12172 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012173 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012176 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012177 isolate->factory()->NewStringFromAscii(
12178 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012179
12180 // Currently, the eval code will be executed in non-strict mode,
12181 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012182 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012183 Compiler::CompileEval(function_source,
12184 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012185 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012186 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012187 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012188 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012189 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012190 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191
12192 // Invoke the result of the compilation to get the evaluation function.
12193 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012194 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195 Handle<Object> evaluation_function =
12196 Execution::Call(compiled_function, receiver, 0, NULL,
12197 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012198 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012200 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012201 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012202 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012203 scope_info,
12204 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205
12206 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012207 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012209 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12210 receiver,
12211 ARRAY_SIZE(argv),
12212 argv,
12213 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012214 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012215
12216 // Skip the global proxy as it has no properties and always delegates to the
12217 // real global object.
12218 if (result->IsJSGlobalProxy()) {
12219 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12220 }
12221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222 return *result;
12223}
12224
12225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012227 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228
12229 // Check the execution state and decode arguments frame and source to be
12230 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012231 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012232 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012233 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12234 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012235 if (!maybe_check_result->ToObject(&check_result)) {
12236 return maybe_check_result;
12237 }
12238 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012239 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12240 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012241 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012242
12243 // Handle the processing of break.
12244 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012245
12246 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012247 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012249 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250 top = top->prev();
12251 }
12252 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254 }
12255
12256 // Get the global context now set to the top context from before the
12257 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012258 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012260 bool is_global = true;
12261
12262 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012263 // Create a new with context with the additional context information between
12264 // the context of the debugged function and the eval code to be executed.
12265 context = isolate->factory()->NewWithContext(
12266 Handle<JSFunction>(context->closure()),
12267 context,
12268 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012269 is_global = false;
12270 }
12271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012273 // Currently, the eval code will be executed in non-strict mode,
12274 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012275 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012276 Compiler::CompileEval(source,
12277 context,
12278 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012279 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012280 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012281 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012283 Handle<JSFunction>(
12284 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12285 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012286
12287 // Invoke the result of the compilation to get the evaluation function.
12288 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012290 Handle<Object> result =
12291 Execution::Call(compiled_function, receiver, 0, NULL,
12292 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012293 // Clear the oneshot breakpoints so that the debugger does not step further.
12294 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012295 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296 return *result;
12297}
12298
12299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012300RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012302 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012305 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306
12307 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012308 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012309 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12310 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12311 // because using
12312 // instances->set(i, *GetScriptWrapper(script))
12313 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012314 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012315 Handle<JSValue> wrapper = GetScriptWrapper(script);
12316 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012317 }
12318
12319 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012320 Handle<JSObject> result =
12321 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012322 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012323 return *result;
12324}
12325
12326
12327// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012328static int DebugReferencedBy(HeapIterator* iterator,
12329 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330 Object* instance_filter, int max_references,
12331 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012332 JSFunction* arguments_function) {
12333 NoHandleAllocation ha;
12334 AssertNoAllocation no_alloc;
12335
12336 // Iterate the heap.
12337 int count = 0;
12338 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012339 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012340 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341 (max_references == 0 || count < max_references)) {
12342 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012343 if (heap_obj->IsJSObject()) {
12344 // Skip context extension objects and argument arrays as these are
12345 // checked in the context of functions using them.
12346 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012347 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012348 obj->map()->constructor() == arguments_function) {
12349 continue;
12350 }
12351
12352 // Check if the JS object has a reference to the object looked for.
12353 if (obj->ReferencesObject(target)) {
12354 // Check instance filter if supplied. This is normally used to avoid
12355 // references from mirror objects (see Runtime_IsInPrototypeChain).
12356 if (!instance_filter->IsUndefined()) {
12357 Object* V = obj;
12358 while (true) {
12359 Object* prototype = V->GetPrototype();
12360 if (prototype->IsNull()) {
12361 break;
12362 }
12363 if (instance_filter == prototype) {
12364 obj = NULL; // Don't add this object.
12365 break;
12366 }
12367 V = prototype;
12368 }
12369 }
12370
12371 if (obj != NULL) {
12372 // Valid reference found add to instance array if supplied an update
12373 // count.
12374 if (instances != NULL && count < instances_size) {
12375 instances->set(count, obj);
12376 }
12377 last = obj;
12378 count++;
12379 }
12380 }
12381 }
12382 }
12383
12384 // Check for circular reference only. This can happen when the object is only
12385 // referenced from mirrors and has a circular reference in which case the
12386 // object is not really alive and would have been garbage collected if not
12387 // referenced from the mirror.
12388 if (count == 1 && last == target) {
12389 count = 0;
12390 }
12391
12392 // Return the number of referencing objects found.
12393 return count;
12394}
12395
12396
12397// Scan the heap for objects with direct references to an object
12398// args[0]: the object to find references to
12399// args[1]: constructor function for instances to exclude (Mirror)
12400// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012401RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402 ASSERT(args.length() == 3);
12403
12404 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012405 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12406 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012407 // The heap iterator reserves the right to do a GC to make the heap iterable.
12408 // Due to the GC above we know it won't need to do that, but it seems cleaner
12409 // to get the heap iterator constructed before we start having unprotected
12410 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012411
12412 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012413 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012414 Object* instance_filter = args[1];
12415 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12416 instance_filter->IsJSObject());
12417 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12418 RUNTIME_ASSERT(max_references >= 0);
12419
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012422 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012423 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 JSFunction* arguments_function =
12425 JSFunction::cast(arguments_boilerplate->map()->constructor());
12426
12427 // Get the number of referencing objects.
12428 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012429 HeapIterator heap_iterator;
12430 count = DebugReferencedBy(&heap_iterator,
12431 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012432 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012433
12434 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012435 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012436 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012437 if (!maybe_object->ToObject(&object)) return maybe_object;
12438 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012439 FixedArray* instances = FixedArray::cast(object);
12440
12441 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012442 // AllocateFixedArray above does not make the heap non-iterable.
12443 ASSERT(HEAP->IsHeapIterable());
12444 HeapIterator heap_iterator2;
12445 count = DebugReferencedBy(&heap_iterator2,
12446 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012447 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448
12449 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012450 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012451 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012452 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012453 if (!maybe_result->ToObject(&result)) return maybe_result;
12454 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012455}
12456
12457
12458// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012459static int DebugConstructedBy(HeapIterator* iterator,
12460 JSFunction* constructor,
12461 int max_references,
12462 FixedArray* instances,
12463 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012464 AssertNoAllocation no_alloc;
12465
12466 // Iterate the heap.
12467 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012468 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012469 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012470 (max_references == 0 || count < max_references)) {
12471 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 if (heap_obj->IsJSObject()) {
12473 JSObject* obj = JSObject::cast(heap_obj);
12474 if (obj->map()->constructor() == constructor) {
12475 // Valid reference found add to instance array if supplied an update
12476 // count.
12477 if (instances != NULL && count < instances_size) {
12478 instances->set(count, obj);
12479 }
12480 count++;
12481 }
12482 }
12483 }
12484
12485 // Return the number of referencing objects found.
12486 return count;
12487}
12488
12489
12490// Scan the heap for objects constructed by a specific function.
12491// args[0]: the constructor to find instances of
12492// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012493RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012494 ASSERT(args.length() == 2);
12495
12496 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012497 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12498 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012499
12500 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012501 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12503 RUNTIME_ASSERT(max_references >= 0);
12504
12505 // Get the number of referencing objects.
12506 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012507 HeapIterator heap_iterator;
12508 count = DebugConstructedBy(&heap_iterator,
12509 constructor,
12510 max_references,
12511 NULL,
12512 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012513
12514 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012515 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012517 if (!maybe_object->ToObject(&object)) return maybe_object;
12518 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012519 FixedArray* instances = FixedArray::cast(object);
12520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012521 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012522 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012523 HeapIterator heap_iterator2;
12524 count = DebugConstructedBy(&heap_iterator2,
12525 constructor,
12526 max_references,
12527 instances,
12528 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012529
12530 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012531 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012532 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12533 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012534 if (!maybe_result->ToObject(&result)) return maybe_result;
12535 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012536 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012537}
12538
12539
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012540// Find the effective prototype object as returned by __proto__.
12541// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012542RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012543 ASSERT(args.length() == 1);
12544
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012545 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012546
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012547 // Use the __proto__ accessor.
12548 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012549}
12550
12551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012553 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556}
12557
12558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012559RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012560#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012562 ASSERT(args.length() == 1);
12563 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012564 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012565 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012566 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012567 return Failure::Exception();
12568 }
12569 func->code()->PrintLn();
12570#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012572}
ager@chromium.org9085a012009-05-11 19:22:57 +000012573
12574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012575RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012576#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012577 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012578 ASSERT(args.length() == 1);
12579 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012580 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012581 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012582 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012583 return Failure::Exception();
12584 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012585 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012586#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012587 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012588}
12589
12590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012591RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012592 NoHandleAllocation ha;
12593 ASSERT(args.length() == 1);
12594
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012595 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012596 return f->shared()->inferred_name();
12597}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012598
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012599
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012600static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12601 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012602 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012603 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012604 int counter = 0;
12605 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012606 for (HeapObject* obj = iterator->next();
12607 obj != NULL;
12608 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012609 ASSERT(obj != NULL);
12610 if (!obj->IsSharedFunctionInfo()) {
12611 continue;
12612 }
12613 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12614 if (shared->script() != script) {
12615 continue;
12616 }
12617 if (counter < buffer_size) {
12618 buffer->set(counter, shared);
12619 }
12620 counter++;
12621 }
12622 return counter;
12623}
12624
12625// For a script finds all SharedFunctionInfo's in the heap that points
12626// to this script. Returns JSArray of SharedFunctionInfo wrapped
12627// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012628RUNTIME_FUNCTION(MaybeObject*,
12629 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012630 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012632 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012633
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012634
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012635 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12636
12637 const int kBufferSize = 32;
12638
12639 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012640 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012641 int number;
12642 {
12643 isolate->heap()->EnsureHeapIsIterable();
12644 AssertNoAllocation no_allocations;
12645 HeapIterator heap_iterator;
12646 Script* scr = *script;
12647 FixedArray* arr = *array;
12648 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12649 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012650 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012651 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012652 isolate->heap()->EnsureHeapIsIterable();
12653 AssertNoAllocation no_allocations;
12654 HeapIterator heap_iterator;
12655 Script* scr = *script;
12656 FixedArray* arr = *array;
12657 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658 }
12659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012660 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012661 result->set_length(Smi::FromInt(number));
12662
12663 LiveEdit::WrapSharedFunctionInfos(result);
12664
12665 return *result;
12666}
12667
12668// For a script calculates compilation information about all its functions.
12669// The script source is explicitly specified by the second argument.
12670// The source of the actual script is not used, however it is important that
12671// all generated code keeps references to this particular instance of script.
12672// Returns a JSArray of compilation infos. The array is ordered so that
12673// each function with all its descendant is always stored in a continues range
12674// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012675RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012676 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012677 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012678 CONVERT_ARG_CHECKED(JSValue, script, 0);
12679 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012680 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12681
12682 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012685 return Failure::Exception();
12686 }
12687
12688 return result;
12689}
12690
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012691// Changes the source of the script to a new_source.
12692// If old_script_name is provided (i.e. is a String), also creates a copy of
12693// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012694RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012695 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012696 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012697 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12698 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012699 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012700
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012701 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12702 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012704 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12705 new_source,
12706 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012707
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012708 if (old_script->IsScript()) {
12709 Handle<Script> script_handle(Script::cast(old_script));
12710 return *(GetScriptWrapper(script_handle));
12711 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012712 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012713 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012714}
12715
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012717RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012718 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012719 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012720 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012721 return LiveEdit::FunctionSourceUpdated(shared_info);
12722}
12723
12724
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012725// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012726RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012727 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012729 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12730 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012731
ager@chromium.orgac091b72010-05-05 07:34:42 +000012732 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012733}
12734
12735// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012736RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012737 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 HandleScope scope(isolate);
12739 Handle<Object> function_object(args[0], isolate);
12740 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012741
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012742 if (function_object->IsJSValue()) {
12743 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12744 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012745 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12746 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012747 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012748 }
12749
12750 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12751 } else {
12752 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12753 // and we check it in this function.
12754 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012757}
12758
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012759
12760// In a code of a parent function replaces original function as embedded object
12761// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012762RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012763 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012765
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012766 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12767 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12768 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012769
12770 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12771 subst_wrapper);
12772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012774}
12775
12776
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012777// Updates positions of a shared function info (first parameter) according
12778// to script source change. Text change is described in second parameter as
12779// array of groups of 3 numbers:
12780// (change_begin, change_end, change_end_new_position).
12781// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012782RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012783 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012784 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012785 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12786 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012787
ager@chromium.orgac091b72010-05-05 07:34:42 +000012788 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012789}
12790
12791
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012792// For array of SharedFunctionInfo's (each wrapped in JSValue)
12793// checks that none of them have activations on stacks (of any thread).
12794// Returns array of the same length with corresponding results of
12795// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012796RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012797 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012798 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012799 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12800 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012801
ager@chromium.org357bf652010-04-12 11:30:10 +000012802 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012803}
12804
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012805// Compares 2 strings line-by-line, then token-wise and returns diff in form
12806// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12807// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012808RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012809 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012810 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012811 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12812 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012813
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012814 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012815}
12816
12817
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012818// A testing entry. Returns statement position which is the closest to
12819// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012820RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012821 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012822 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012823 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012824 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012826 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012827
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012828 if (code->kind() != Code::FUNCTION &&
12829 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012831 }
12832
12833 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012834 int closest_pc = 0;
12835 int distance = kMaxInt;
12836 while (!it.done()) {
12837 int statement_position = static_cast<int>(it.rinfo()->data());
12838 // Check if this break point is closer that what was previously found.
12839 if (source_position <= statement_position &&
12840 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012841 closest_pc =
12842 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012843 distance = statement_position - source_position;
12844 // Check whether we can't get any closer.
12845 if (distance == 0) break;
12846 }
12847 it.next();
12848 }
12849
12850 return Smi::FromInt(closest_pc);
12851}
12852
12853
ager@chromium.org357bf652010-04-12 11:30:10 +000012854// Calls specified function with or without entering the debugger.
12855// This is used in unit tests to run code as if debugger is entered or simply
12856// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012857RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012858 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012859 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012860 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12861 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012862
12863 Handle<Object> result;
12864 bool pending_exception;
12865 {
12866 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012867 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012868 &pending_exception);
12869 } else {
12870 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012871 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012872 &pending_exception);
12873 }
12874 }
12875 if (!pending_exception) {
12876 return *result;
12877 } else {
12878 return Failure::Exception();
12879 }
12880}
12881
12882
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012883// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012884RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012885 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012886 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012887 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12888 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012890}
12891
12892
12893// Performs a GC.
12894// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012895RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012896 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012897 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012898}
12899
12900
12901// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012902RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012903 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012904 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012905 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012906 }
12907 return Smi::FromInt(usage);
12908}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012909
12910
12911// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012913#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012914 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012915#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012916 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012917#endif
12918}
12919
12920
12921// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012922RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923#ifdef LIVE_OBJECT_LIST
12924 return LiveObjectList::Capture();
12925#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012927#endif
12928}
12929
12930
12931// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012932RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012933#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012934 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012935 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012936 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012937#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012938 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012939#endif
12940}
12941
12942
12943// Generates the response to a debugger request for a dump of the objects
12944// contained in the difference between the captured live object lists
12945// specified by id1 and id2.
12946// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12947// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012948RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012949#ifdef LIVE_OBJECT_LIST
12950 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012951 CONVERT_SMI_ARG_CHECKED(id1, 0);
12952 CONVERT_SMI_ARG_CHECKED(id2, 1);
12953 CONVERT_SMI_ARG_CHECKED(start, 2);
12954 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012955 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956 EnterDebugger enter_debugger;
12957 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12958#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012959 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012960#endif
12961}
12962
12963
12964// Gets the specified object as requested by the debugger.
12965// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012966RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012967#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012968 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012969 Object* result = LiveObjectList::GetObj(obj_id);
12970 return result;
12971#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012972 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012973#endif
12974}
12975
12976
12977// Gets the obj id for the specified address if valid.
12978// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012979RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980#ifdef LIVE_OBJECT_LIST
12981 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012982 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012983 Object* result = LiveObjectList::GetObjId(address);
12984 return result;
12985#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012986 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012987#endif
12988}
12989
12990
12991// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012993#ifdef LIVE_OBJECT_LIST
12994 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012995 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012996 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12997 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12998 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12999 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013000 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013001
13002 Handle<JSObject> instance_filter;
13003 if (args[1]->IsJSObject()) {
13004 instance_filter = args.at<JSObject>(1);
13005 }
13006 bool verbose = false;
13007 if (args[2]->IsBoolean()) {
13008 verbose = args[2]->IsTrue();
13009 }
13010 int start = 0;
13011 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013012 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013 }
13014 int limit = Smi::kMaxValue;
13015 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013016 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013017 }
13018
13019 return LiveObjectList::GetObjRetainers(obj_id,
13020 instance_filter,
13021 verbose,
13022 start,
13023 limit,
13024 filter_obj);
13025#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013026 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013027#endif
13028}
13029
13030
13031// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013032RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013033#ifdef LIVE_OBJECT_LIST
13034 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013035 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13036 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013037 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13038
13039 Handle<JSObject> instance_filter;
13040 if (args[2]->IsJSObject()) {
13041 instance_filter = args.at<JSObject>(2);
13042 }
13043
13044 Object* result =
13045 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13046 return result;
13047#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013048 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013049#endif
13050}
13051
13052
13053// Generates the response to a debugger request for a list of all
13054// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013055RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013056#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013057 CONVERT_SMI_ARG_CHECKED(start, 0);
13058 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013059 return LiveObjectList::Info(start, count);
13060#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013061 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013062#endif
13063}
13064
13065
13066// Gets a dump of the specified object as requested by the debugger.
13067// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013068RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013069#ifdef LIVE_OBJECT_LIST
13070 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013071 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013072 Object* result = LiveObjectList::PrintObj(obj_id);
13073 return result;
13074#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013075 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076#endif
13077}
13078
13079
13080// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013081RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013082#ifdef LIVE_OBJECT_LIST
13083 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013084 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013085#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013086 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013087#endif
13088}
13089
13090
13091// Generates the response to a debugger request for a summary of the types
13092// of objects in the difference between the captured live object lists
13093// specified by id1 and id2.
13094// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13095// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013096RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013097#ifdef LIVE_OBJECT_LIST
13098 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013099 CONVERT_SMI_ARG_CHECKED(id1, 0);
13100 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013101 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013102
13103 EnterDebugger enter_debugger;
13104 return LiveObjectList::Summarize(id1, id2, filter_obj);
13105#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013106 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013107#endif
13108}
13109
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013110#endif // ENABLE_DEBUGGER_SUPPORT
13111
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013113RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013114 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013115 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013116 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013117}
13118
13119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013120RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013121 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013122 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013123 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013124}
13125
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013127// Finds the script object from the script data. NOTE: This operation uses
13128// heap traversal to find the function generated for the source position
13129// for the requested break point. For lazily compiled functions several heap
13130// traversals might be required rendering this operation as a rather slow
13131// operation. However for setting break points which is normally done through
13132// some kind of user interaction the performance is not crucial.
13133static Handle<Object> Runtime_GetScriptFromScriptName(
13134 Handle<String> script_name) {
13135 // Scan the heap for Script objects to find the script with the requested
13136 // script data.
13137 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013138 script_name->GetHeap()->EnsureHeapIsIterable();
13139 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013140 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013141 HeapObject* obj = NULL;
13142 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013143 // If a script is found check if it has the script data requested.
13144 if (obj->IsScript()) {
13145 if (Script::cast(obj)->name()->IsString()) {
13146 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13147 script = Handle<Script>(Script::cast(obj));
13148 }
13149 }
13150 }
13151 }
13152
13153 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013154 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013155
13156 // Return the script found.
13157 return GetScriptWrapper(script);
13158}
13159
13160
13161// Get the script object from script data. NOTE: Regarding performance
13162// see the NOTE for GetScriptFromScriptData.
13163// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013166
13167 ASSERT(args.length() == 1);
13168
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013169 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013170
13171 // Find the requested script.
13172 Handle<Object> result =
13173 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13174 return *result;
13175}
13176
13177
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013178// Determines whether the given stack frame should be displayed in
13179// a stack trace. The caller is the error constructor that asked
13180// for the stack trace to be collected. The first time a construct
13181// call to this function is encountered it is skipped. The seen_caller
13182// in/out parameter is used to remember if the caller has been seen
13183// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013184static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13185 Object* caller,
13186 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013187 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013188 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013189 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013190 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013191 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13192 Object* raw_fun = frame->function();
13193 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013194 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013195 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013197 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013198 *seen_caller = true;
13199 return false;
13200 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013201 // Skip all frames until we've seen the caller.
13202 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013203 // Also, skip non-visible built-in functions and any call with the builtins
13204 // object as receiver, so as to not reveal either the builtins object or
13205 // an internal function.
13206 // The --builtins-in-stack-traces command line flag allows including
13207 // internal call sites in the stack trace for debugging purposes.
13208 if (!FLAG_builtins_in_stack_traces) {
13209 JSFunction* fun = JSFunction::cast(raw_fun);
13210 if (frame->receiver()->IsJSBuiltinsObject() ||
13211 (fun->IsBuiltin() && !fun->shared()->native())) {
13212 return false;
13213 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013214 }
13215 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013216}
13217
13218
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013219// Collect the raw data for a stack trace. Returns an array of 4
13220// element segments each containing a receiver, function, code and
13221// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013222RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013223 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013224 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013225 Handle<Object> caller = args.at<Object>(1);
13226 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013228 HandleScope scope(isolate);
13229 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013230
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013231 limit = Max(limit, 0); // Ensure that limit is not negative.
13232 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013233 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013234 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013235
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013236 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013237 // If the caller parameter is a function we skip frames until we're
13238 // under it before starting to collect.
13239 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013240 int cursor = 0;
13241 int frames_seen = 0;
13242 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013243 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013244 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013245 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013246 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013247 // Set initial size to the maximum inlining level + 1 for the outermost
13248 // function.
13249 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013250 frame->Summarize(&frames);
13251 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013252 if (cursor + 4 > elements->length()) {
13253 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13254 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013255 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013256 for (int i = 0; i < cursor; i++) {
13257 new_elements->set(i, elements->get(i));
13258 }
13259 elements = new_elements;
13260 }
13261 ASSERT(cursor + 4 <= elements->length());
13262
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013263 Handle<Object> recv = frames[i].receiver();
13264 Handle<JSFunction> fun = frames[i].function();
13265 Handle<Code> code = frames[i].code();
13266 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013267 elements->set(cursor++, *recv);
13268 elements->set(cursor++, *fun);
13269 elements->set(cursor++, *code);
13270 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013271 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013272 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013273 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013275 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013276 // Capture and attach a more detailed stack trace if necessary.
13277 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013278 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013279 return *result;
13280}
13281
13282
ager@chromium.org3811b432009-10-28 14:53:37 +000013283// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013284RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013285 ASSERT_EQ(args.length(), 0);
13286
13287 NoHandleAllocation ha;
13288
13289 const char* version_string = v8::V8::GetVersion();
13290
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013291 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13292 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013293}
13294
13295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013296RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013297 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013298 OS::PrintError("abort: %s\n",
13299 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013300 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013301 OS::Abort();
13302 UNREACHABLE();
13303 return NULL;
13304}
13305
13306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013307RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013308 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013309 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013310 Object* key = args[1];
13311
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013312 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013313 Object* o = cache->get(finger_index);
13314 if (o == key) {
13315 // The fastest case: hit the same place again.
13316 return cache->get(finger_index + 1);
13317 }
13318
13319 for (int i = finger_index - 2;
13320 i >= JSFunctionResultCache::kEntriesIndex;
13321 i -= 2) {
13322 o = cache->get(i);
13323 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013324 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013325 return cache->get(i + 1);
13326 }
13327 }
13328
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013329 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013330 ASSERT(size <= cache->length());
13331
13332 for (int i = size - 2; i > finger_index; i -= 2) {
13333 o = cache->get(i);
13334 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013335 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013336 return cache->get(i + 1);
13337 }
13338 }
13339
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013340 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013341 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013342
13343 Handle<JSFunctionResultCache> cache_handle(cache);
13344 Handle<Object> key_handle(key);
13345 Handle<Object> value;
13346 {
13347 Handle<JSFunction> factory(JSFunction::cast(
13348 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13349 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013350 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013351 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013352 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013353 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013354 value = Execution::Call(factory,
13355 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013356 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013357 argv,
13358 &pending_exception);
13359 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013360 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013361
13362#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013363 if (FLAG_verify_heap) {
13364 cache_handle->JSFunctionResultCacheVerify();
13365 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013366#endif
13367
13368 // Function invocation may have cleared the cache. Reread all the data.
13369 finger_index = cache_handle->finger_index();
13370 size = cache_handle->size();
13371
13372 // If we have spare room, put new data into it, otherwise evict post finger
13373 // entry which is likely to be the least recently used.
13374 int index = -1;
13375 if (size < cache_handle->length()) {
13376 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13377 index = size;
13378 } else {
13379 index = finger_index + JSFunctionResultCache::kEntrySize;
13380 if (index == cache_handle->length()) {
13381 index = JSFunctionResultCache::kEntriesIndex;
13382 }
13383 }
13384
13385 ASSERT(index % 2 == 0);
13386 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13387 ASSERT(index < cache_handle->length());
13388
13389 cache_handle->set(index, *key_handle);
13390 cache_handle->set(index + 1, *value);
13391 cache_handle->set_finger_index(index);
13392
13393#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013394 if (FLAG_verify_heap) {
13395 cache_handle->JSFunctionResultCacheVerify();
13396 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013397#endif
13398
13399 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013400}
13401
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013403RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013404 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013405 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13406 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013407 return *isolate->factory()->NewJSMessageObject(
13408 type,
13409 arguments,
13410 0,
13411 0,
13412 isolate->factory()->undefined_value(),
13413 isolate->factory()->undefined_value(),
13414 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013415}
13416
13417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013418RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013419 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013420 return message->type();
13421}
13422
13423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013424RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013425 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013426 return message->arguments();
13427}
13428
13429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013430RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013431 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013432 return Smi::FromInt(message->start_position());
13433}
13434
13435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013436RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013437 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013438 return message->script();
13439}
13440
13441
kasper.lund44510672008-07-25 07:37:58 +000013442#ifdef DEBUG
13443// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13444// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013445RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013446 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013447 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013448#define COUNT_ENTRY(Name, argc, ressize) + 1
13449 int entry_count = 0
13450 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13451 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13452 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13453#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013454 Factory* factory = isolate->factory();
13455 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013456 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013457 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013458#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013459 { \
13460 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013461 Handle<String> name; \
13462 /* Inline runtime functions have an underscore in front of the name. */ \
13463 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013464 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013465 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13466 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013467 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013468 Vector<const char>(#Name, StrLength(#Name))); \
13469 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013470 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013471 pair_elements->set(0, *name); \
13472 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013473 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013474 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013475 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013476 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013477 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013478 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013479 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013480 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013481#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013482 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013483 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013484 return *result;
13485}
kasper.lund44510672008-07-25 07:37:58 +000013486#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013487
13488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013489RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013490 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013491 CONVERT_ARG_CHECKED(String, format, 0);
13492 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013493 String::FlatContent format_content = format->GetFlatContent();
13494 RUNTIME_ASSERT(format_content.IsAscii());
13495 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013496 LOGGER->LogRuntime(chars, elms);
13497 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013498}
13499
13500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013501RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013502 UNREACHABLE(); // implemented as macro in the parser
13503 return NULL;
13504}
13505
13506
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013507#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13508 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013509 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013510 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13511 }
13512
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013513ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013514ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13515ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13516ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13517ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13518ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13519ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13520ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13521ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13522ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13523ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13524ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13525ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13527
13528#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13529
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013530
13531RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13532 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013533 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13534 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013535 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13536}
13537
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013538// ----------------------------------------------------------------------------
13539// Implementation of Runtime
13540
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013541#define F(name, number_of_args, result_size) \
13542 { Runtime::k##name, Runtime::RUNTIME, #name, \
13543 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013544
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013545
13546#define I(name, number_of_args, result_size) \
13547 { Runtime::kInline##name, Runtime::INLINE, \
13548 "_" #name, NULL, number_of_args, result_size },
13549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013550static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013551 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013552 INLINE_FUNCTION_LIST(I)
13553 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013554};
13555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013557MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13558 Object* dictionary) {
13559 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013560 ASSERT(dictionary != NULL);
13561 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13562 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013563 Object* name_symbol;
13564 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013565 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013566 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13567 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013568 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013569 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13570 String::cast(name_symbol),
13571 Smi::FromInt(i),
13572 PropertyDetails(NONE, NORMAL));
13573 if (!maybe_dictionary->ToObject(&dictionary)) {
13574 // Non-recoverable failure. Calling code must restart heap
13575 // initialization.
13576 return maybe_dictionary;
13577 }
13578 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013579 }
13580 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013581}
13582
13583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013584const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13585 Heap* heap = name->GetHeap();
13586 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013587 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013588 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013589 int function_index = Smi::cast(smi_index)->value();
13590 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013591 }
13592 return NULL;
13593}
13594
13595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013596const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013597 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13598}
13599
13600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013601void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013602 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013603 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013604 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013605 if (isolate->heap()->new_space()->AddFreshPage()) {
13606 return;
13607 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013608 // Try to do a garbage collection; ignore it if it fails. The C
13609 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013610 isolate->heap()->CollectGarbage(failure->allocation_space(),
13611 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013612 } else {
13613 // Handle last resort GC and make sure to allow future allocations
13614 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013615 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013616 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13617 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013619}
13620
13621
13622} } // namespace v8::internal