blob: 5996b82673b60c9b9d7f307dbac315425ed58cc7 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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"
Ben Murdoch589d6972011-11-30 16:04:58 +000035#include "bootstrapper.h"
Steve Block6ded16b2010-05-10 14:33:55 +010036#include "codegen.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "compilation-cache.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038#include "compiler.h"
39#include "cpu.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040#include "dateparser-inl.h"
41#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010042#include "deoptimizer.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010043#include "date.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "execution.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010045#include "global-handles.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010046#include "isolate-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000047#include "jsregexp.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000048#include "json-parser.h"
Steve Block6ded16b2010-05-10 14:33:55 +010049#include "liveedit.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010050#include "liveobjectlist-inl.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000051#include "misc-intrinsics.h"
Steve Block3ce2e202009-11-05 08:53:23 +000052#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000053#include "platform.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010054#include "runtime-profiler.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000055#include "runtime.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000056#include "scopeinfo.h"
Ben Murdoch589d6972011-11-30 16:04:58 +000057#include "smart-array-pointer.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000058#include "string-search.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000059#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000060#include "v8threads.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000061#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000062
63namespace v8 {
64namespace internal {
65
66
67#define RUNTIME_ASSERT(value) \
Steve Block44f0eee2011-05-26 01:26:41 +010068 if (!(value)) return isolate->ThrowIllegalOperation();
Steve Blocka7e24c12009-10-30 11:49:00 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
Ben Murdoch85b71792012-04-11 18:30:58 +010073#define CONVERT_ARG_CHECKED(Type, name, index) \
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010074 RUNTIME_ASSERT(args[index]->Is##Type()); \
Ben Murdoch3ef787d2012-04-12 10:51:47 +010075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
Steve Blocka7e24c12009-10-30 11:49:00 +000079 Handle<Type> name = args.at<Type>(index);
80
81// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
Steve Blocka7e24c12009-10-30 11:49:00 +000087
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
Steve Blocka7e24c12009-10-30 11:49:00 +000090// and return.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
Steve Blocka7e24c12009-10-30 11:49:00 +000094
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
Steve Blocka7e24c12009-10-30 11:49:00 +000097// the number not-a-number) call IllegalOperation and return.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
Steve Block44f0eee2011-05-26 01:26:41 +0100139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +0000143
Steve Block44f0eee2011-05-26 01:26:41 +0100144 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -0700145 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
John Reck59135872010-11-02 12:39:01 -0700147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000157 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
Leon Clarke4515c472010-02-03 11:58:03 +0000161 properties->set(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 }
163 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000168 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
Leon Clarke4515c472010-02-03 11:58:03 +0000172 copy->InObjectPropertyAtPut(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 }
174 }
175 } else {
John Reck59135872010-11-02 12:39:01 -0700176 { MaybeObject* maybe_result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
John Reck59135872010-11-02 12:39:01 -0700178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
Leon Clarke4515c472010-02-03 11:58:03 +0000184 String* key_string = String::cast(names->get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000185 PropertyAttributes attributes =
Leon Clarke4515c472010-02-03 11:58:03 +0000186 copy->GetLocalPropertyAttribute(key_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
John Reck59135872010-11-02 12:39:01 -0700191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000194 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -0700201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
208 // Pixel elements cannot be created using an object literal.
Steve Block44f0eee2011-05-26 01:26:41 +0100209 ASSERT(!copy->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 switch (copy->GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100211 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +0000212 case FAST_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
Steve Block44f0eee2011-05-26 01:26:41 +0100214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
Iain Merrick75681382010-08-19 15:07:18 +0100227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
John Reck59135872010-11-02 12:39:01 -0700231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
Iain Merrick75681382010-08-19 15:07:18 +0100233 elements->set(i, result);
234 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 }
236 }
237 break;
238 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000239 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000247 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
John Reck59135872010-11-02 12:39:01 -0700250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000259 UNIMPLEMENTED();
260 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000271 // No contained objects, nothing to do.
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 break;
273 }
274 return copy;
275}
276
277
Steve Blocka7e24c12009-10-30 11:49:00 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
281 bool* is_result_from_cache) {
Steve Block44f0eee2011-05-26 01:26:41 +0100282 Isolate* isolate = context->GetIsolate();
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
Ben Murdoch85b71792012-04-11 18:30:58 +0100316 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100317 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100318 ASSERT(index == number_of_symbol_keys);
Ben Murdoch85b71792012-04-11 18:30:58 +0100319 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 }
323 *is_result_from_cache = false;
Steve Block44f0eee2011-05-26 01:26:41 +0100324 return isolate->factory()->CopyMap(
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
327}
328
329
330static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100331 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
334
335
336static Handle<Object> CreateObjectLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100337 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 Handle<FixedArray> literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100339 Handle<FixedArray> constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100340 bool should_have_fast_elements,
341 bool has_function_literal) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
Steve Block44f0eee2011-05-26 01:26:41 +0100351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
Steve Blocka7e24c12009-10-30 11:49:00 +0000361
Steve Block44f0eee2011-05-26 01:26:41 +0100362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
Steve Block6ded16b2010-05-10 14:33:55 +0100363
364 // Normalize the elements of the boilerplate to save space if needed.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
Steve Block6ded16b2010-05-10 14:33:55 +0100366
Steve Block44f0eee2011-05-26 01:26:41 +0100367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 }
Steve Block44f0eee2011-05-26 01:26:41 +0100402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
Steve Block44f0eee2011-05-26 01:26:41 +0100406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 }
Steve Block44f0eee2011-05-26 01:26:41 +0100418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 }
433
434 return boilerplate;
435}
436
437
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100459 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
Steve Blocka7e24c12009-10-30 11:49:00 +0000467
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000472
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
Ben Murdoch85b71792012-04-11 18:30:58 +0100478 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479 object->set_map(Map::cast(global_context->object_js_array_map()));
480 }
481
482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
487 } else {
488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
518 }
Iain Merrick75681382010-08-19 15:07:18 +0100519 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000520 }
521 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100524
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100539 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
Steve Block44f0eee2011-05-26 01:26:41 +0100543 const bool kHasNoFunctionLiteral = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000544 switch (CompileTimeValue::GetType(array)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
Steve Block6ded16b2010-05-10 14:33:55 +0100551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 case CompileTimeValue::ARRAY_LITERAL:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
Ben Murdoch8b112d22011-06-08 16:22:53 +0100567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100568 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100569 ASSERT(args.length() == 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000576
577 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100582 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100583 should_have_fast_elements,
584 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
Steve Block44f0eee2011-05-26 01:26:41 +0100589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000590}
591
592
Ben Murdoch8b112d22011-06-08 16:22:53 +0100593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100594 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100595 ASSERT(args.length() == 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000602
603 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100608 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100609 should_have_fast_elements,
610 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
Steve Block44f0eee2011-05-26 01:26:41 +0100615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000616}
617
618
Ben Murdoch8b112d22011-06-08 16:22:53 +0100619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100620 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000621 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
Leon Clarkee46be812010-01-19 14:06:41 +0000625
626 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
Steve Block44f0eee2011-05-26 01:26:41 +0100635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000636}
637
638
Ben Murdoch8b112d22011-06-08 16:22:53 +0100639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100640 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000641 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
Leon Clarkee46be812010-01-19 14:06:41 +0000645
646 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
Iain Merrick75681382010-08-19 15:07:18 +0100656 if (JSObject::cast(*boilerplate)->elements()->map() ==
Steve Block44f0eee2011-05-26 01:26:41 +0100657 isolate->heap()->fixed_cow_array_map()) {
658 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100659 }
Steve Block44f0eee2011-05-26 01:26:41 +0100660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000661}
662
663
Ben Murdoch257744e2011-11-30 15:57:28 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
Ben Murdoch257744e2011-11-30 15:57:28 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
Ben Murdoch589d6972011-11-30 16:04:58 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
691}
692
693
Ben Murdoch589d6972011-11-30 16:04:58 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000704 return proxy->handler();
705}
706
707
Ben Murdoch589d6972011-11-30 16:04:58 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
Ben Murdoch589d6972011-11-30 16:04:58 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
Ben Murdoch589d6972011-11-30 16:04:58 +0000718 return proxy->construct_trap();
719}
720
721
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000725 proxy->Fix();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000726 return isolate->heap()->undefined_value();
727}
728
729
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000832 Handle<Object> value(args[2]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000837}
838
839
Ben Murdoch8b112d22011-06-08 16:22:53 +0100840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +0100844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 return JSObject::cast(obj)->class_name();
846}
847
848
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
856 do {
857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
864 obj = obj->GetPrototype();
865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
867 return obj;
868}
869
870
Ben Murdoch8b112d22011-06-08 16:22:53 +0100871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000881 V = prototype;
882 }
883}
884
885
Leon Clarkee46be812010-01-19 14:06:41 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
Steve Block1e0659c2011-05-24 12:43:12 +0100902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100929 Isolate* isolate = obj->GetIsolate();
Steve Block1e0659c2011-05-24 12:43:12 +0100930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100932 !isolate->MayNamedAccess(current, name, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
Steve Block44f0eee2011-05-26 01:26:41 +0100969 isolate->ReportFailedAccessCheck(current, access_type);
Steve Block1e0659c2011-05-24 12:43:12 +0100970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100980 return false;
981 }
982
983 return true;
984}
985
986
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
Steve Block44f0eee2011-05-26 01:26:41 +01001003 Heap* heap = isolate->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001006 LookupResult result(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
Steve Block44f0eee2011-05-26 01:26:41 +01001012 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001013
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
Steve Block1e0659c2011-05-24 12:43:12 +01001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001022
Steve Block44f0eee2011-05-26 01:26:41 +01001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001024 elms->set(VALUE_INDEX, *substr);
Steve Block44f0eee2011-05-26 01:26:41 +01001025 elms->set(WRITABLE_INDEX, heap->false_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
Steve Block44f0eee2011-05-26 01:26:41 +01001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
Steve Block44f0eee2011-05-26 01:26:41 +01001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001034 Handle<Object> value = Object::GetElement(obj, index);
Steve Block44f0eee2011-05-26 01:26:41 +01001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001036 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +01001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
Steve Block1e0659c2011-05-24 12:43:12 +01001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001047 if (proto->IsNull()) return heap->undefined_value();
Steve Block1e0659c2011-05-24 12:43:12 +01001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00001052 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001055 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001056 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001057 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001058 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
Steve Block44f0eee2011-05-26 01:26:41 +01001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +01001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
Steve Block1e0659c2011-05-24 12:43:12 +01001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
Steve Block1e0659c2011-05-24 12:43:12 +01001072 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001073 break;
1074 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001075 case NORMAL: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001076 // This is a data property.
Steve Block44f0eee2011-05-26 01:26:41 +01001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001078 Handle<Object> value = Object::GetElement(obj, index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001079 ASSERT(!value.is_null());
1080 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +01001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001082 break;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001083 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
Steve Block44f0eee2011-05-26 01:26:41 +01001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001090 return *desc;
1091 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001092 }
1093 }
1094
Leon Clarkee46be812010-01-19 14:06:41 +00001095 // Use recursive implementation to also traverse hidden prototypes
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001096 GetOwnPropertyImplementation(*obj, *name, &result);
Leon Clarkee46be812010-01-19 14:06:41 +00001097
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001098 if (!result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001099 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001100 }
Steve Block1e0659c2011-05-24 12:43:12 +01001101
1102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001103 return heap->false_value();
Leon Clarkee46be812010-01-19 14:06:41 +00001104 }
1105
Steve Block44f0eee2011-05-26 01:26:41 +01001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
Steve Block1e0659c2011-05-24 12:43:12 +01001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001110 (result.GetCallbackObject()->IsAccessorPair());
Steve Block1e0659c2011-05-24 12:43:12 +01001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
Steve Block44f0eee2011-05-26 01:26:41 +01001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +01001115
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
Steve Block1e0659c2011-05-24 12:43:12 +01001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
Steve Block1e0659c2011-05-24 12:43:12 +01001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
Steve Block1e0659c2011-05-24 12:43:12 +01001122 }
1123 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
Steve Block1e0659c2011-05-24 12:43:12 +01001126
1127 PropertyAttributes attrs;
1128 Object* value;
1129 // GetProperty will check access and report any violations.
1130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
Leon Clarkee46be812010-01-19 14:06:41 +00001136 return *desc;
1137}
1138
1139
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
Ben Murdoch8b112d22011-06-08 16:22:53 +01001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
Steve Block8defd9f2010-07-08 12:39:36 +01001157 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
Steve Block8defd9f2010-07-08 12:39:36 +01001159 return obj->PreventExtensions();
1160}
1161
Steve Block1e0659c2011-05-24 12:43:12 +01001162
Ben Murdoch8b112d22011-06-08 16:22:53 +01001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
Leon Clarkee46be812010-01-19 14:06:41 +00001164 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
Steve Block1e0659c2011-05-24 12:43:12 +01001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001168 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +01001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
Leon Clarkee46be812010-01-19 14:06:41 +00001173}
1174
1175
Ben Murdoch8b112d22011-06-08 16:22:53 +01001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01001177 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
1185}
1186
1187
Ben Murdoch8b112d22011-06-08 16:22:53 +01001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001189 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001190 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001192 return *isolate->factory()->CreateApiFunction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001193}
1194
1195
Ben Murdoch8b112d22011-06-08 16:22:53 +01001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
1199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
Steve Block44f0eee2011-05-26 01:26:41 +01001200 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001201}
1202
1203
Ben Murdoch8b112d22011-06-08 16:22:53 +01001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
Steve Blocka7e24c12009-10-30 11:49:00 +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);
Steve Block3ce2e202009-11-05 08:53:23 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
1219}
1220
1221
Ben Murdoch8b112d22011-06-08 16:22:53 +01001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +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.
John Reck59135872010-11-02 12:39:01 -07001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
Steve Blocka7e24c12009-10-30 11:49:00 +00001238}
1239
1240
Ben Murdoch8b112d22011-06-08 16:22:53 +01001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +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.
John Reck59135872010-11-02 12:39:01 -07001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
Steve Block44f0eee2011-05-26 01:26:41 +01001255 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001256}
1257
1258
Steve Block44f0eee2011-05-26 01:26:41 +01001259static 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));
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001269}
1270
1271
Ben Murdoch8b112d22011-06-08 16:22:53 +01001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001273 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +01001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001277
Steve Block3ce2e202009-11-05 08:53:23 +00001278 Handle<Context> context = args.at<Context>(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
Ben Murdoch589d6972011-11-30 16:04:58 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001281
1282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
Steve Block44f0eee2011-05-26 01:26:41 +01001285 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001286 Handle<String> name(String::cast(pairs->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +01001287 Handle<Object> value(pairs->get(i + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +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();
Ben Murdoch589d6972011-11-30 16:04:58 +00001293 bool is_function_declaration = false;
Steve Blocka7e24c12009-10-30 11:49:00 +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.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001297 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001300 // 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) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001303 continue;
1304 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
Steve Blocka7e24c12009-10-30 11:49:00 +00001311 }
1312 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +00001313 is_function_declaration = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 // Copy the function and update its context. Use it as value.
Steve Block6ded16b2010-05-10 14:33:55 +01001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 Handle<JSFunction> function =
Steve Block44f0eee2011-05-26 01:26:41 +01001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 value = function;
1322 }
1323
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001324 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 global->LocalLookup(*name, &lookup);
1326
Ben Murdoch589d6972011-11-30 16:04:58 +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;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001333 attr |= DONT_DELETE;
1334 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
Ben Murdoch589d6972011-11-30 16:04:58 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001349 if (is_function_declaration) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 }
1360 // Do not change DONT_DELETE to false from true.
Ben Murdoch589d6972011-11-30 16:04:58 +00001361 attr |= lookup.GetAttributes() & DONT_DELETE;
Steve Blocka7e24c12009-10-30 11:49:00 +00001362 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1364
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001365 RETURN_IF_EMPTY_HANDLE(
1366 isolate,
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001370 RETURN_IF_EMPTY_HANDLE(
1371 isolate,
1372 JSReceiver::SetProperty(global, name, value,
1373 static_cast<PropertyAttributes>(attr),
1374 language_mode == CLASSIC_MODE
1375 ? kNonStrictMode : kStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 }
1377 }
1378
Steve Block44f0eee2011-05-26 01:26:41 +01001379 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001381}
1382
1383
Ben Murdoch8b112d22011-06-08 16:22:53 +01001384RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001385 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001386 ASSERT(args.length() == 4);
1387
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388 // Declarations are always made in a function or global context. In the
1389 // case of eval code, the context passed is the context of the caller,
1390 // which may be some nested context and not the declaration context.
1391 RUNTIME_ASSERT(args[0]->IsContext());
1392 Handle<Context> context(Context::cast(args[0])->declaration_context());
1393
Steve Blocka7e24c12009-10-30 11:49:00 +00001394 Handle<String> name(String::cast(args[1]));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Steve Block44f0eee2011-05-26 01:26:41 +01001397 Handle<Object> initial_value(args[3], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001398
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 int index;
1400 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001402 BindingFlags binding_flags;
Steve Blocka7e24c12009-10-30 11:49:00 +00001403 Handle<Object> holder =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001404 context->Lookup(name, flags, &index, &attributes, &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001405
1406 if (attributes != ABSENT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001407 // The name was declared before; check for conflicting re-declarations.
Steve Blocka7e24c12009-10-30 11:49:00 +00001408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001412 return ThrowRedeclarationError(isolate, type, name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001413 }
1414
1415 // Initialize it if necessary.
1416 if (*initial_value != NULL) {
1417 if (index >= 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001418 ASSERT(holder.is_identical_to(context));
1419 if (((attributes & READ_ONLY) == 0) ||
1420 context->get(index)->IsTheHole()) {
1421 context->set(index, *initial_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 }
1423 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001424 // Slow case: The property is in the context extension object of a
1425 // function context or the global object of a global context.
1426 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Steve Block1e0659c2011-05-24 12:43:12 +01001427 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001428 isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001429 JSReceiver::SetProperty(object, name, initial_value, mode,
1430 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 }
1432 }
1433
1434 } else {
1435 // The property is not in the function context. It needs to be
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 // "declared" in the function context's extension context or as a
1437 // property of the the global object.
1438 Handle<JSObject> object;
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 if (context->has_extension()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001440 object = Handle<JSObject>(JSObject::cast(context->extension()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001441 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001442 // Context extension objects are allocated lazily.
1443 ASSERT(context->IsFunctionContext());
1444 object = isolate->factory()->NewJSObject(
Steve Block44f0eee2011-05-26 01:26:41 +01001445 isolate->context_extension_function());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001446 context->set_extension(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001447 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001448 ASSERT(*object != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001449
1450 // Declare the property by setting it to the initial value if provided,
1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1452 // constant declarations).
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001453 ASSERT(!object->HasLocalProperty(*name));
Steve Block44f0eee2011-05-26 01:26:41 +01001454 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 if (*initial_value != NULL) value = initial_value;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001456 // Declaring a const context slot is a conflicting declaration if
1457 // there is a callback with that name in a prototype. It is
1458 // allowed to introduce const variables in
1459 // JSContextExtensionObjects. They are treated specially in
1460 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects.
1462 if (initial_value->IsTheHole() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001463 !object->IsJSContextExtensionObject()) {
1464 LookupResult lookup(isolate);
1465 object->Lookup(*name, &lookup);
1466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001467 return ThrowRedeclarationError(isolate, "const", name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001468 }
1469 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001470 RETURN_IF_EMPTY_HANDLE(
1471 isolate,
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 }
1474
Steve Block44f0eee2011-05-26 01:26:41 +01001475 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001476}
1477
1478
Ben Murdoch8b112d22011-06-08 16:22:53 +01001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 NoHandleAllocation nha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001481 // args[0] == name
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001482 // args[1] == language_mode
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001483 // args[2] == value (optional)
Steve Blocka7e24c12009-10-30 11:49:00 +00001484
1485 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments).
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3;
Steve Blocka7e24c12009-10-30 11:49:00 +00001489
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001491 GlobalObject* global = isolate->context()->global();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001492 RUNTIME_ASSERT(args[1]->IsSmi());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode;
Steve Blocka7e24c12009-10-30 11:49:00 +00001496
1497 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE;
1500
1501 // Lookup the property locally in the global object. If it isn't
1502 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001505 // to assign to the property.
Steve Blockd0582a62009-12-15 09:54:21 +00001506 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001508 Object* object = global;
1509 LookupResult lookup(isolate);
1510 while (object->IsJSObject() &&
1511 JSObject::cast(object)->map()->is_hidden_prototype()) {
1512 JSObject* raw_holder = JSObject::cast(object);
1513 raw_holder->LocalLookup(*name, &lookup);
1514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
1515 HandleScope handle_scope(isolate);
1516 Handle<JSObject> holder(raw_holder);
1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1518 // Update the raw pointer in case it's changed due to GC.
1519 raw_holder = *holder;
1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1521 // Found an interceptor that's not read only.
1522 if (assign) {
1523 return raw_holder->SetProperty(
1524 &lookup, *name, args[2], attributes, strict_mode_flag);
1525 } else {
1526 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00001527 }
1528 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001530 object = raw_holder->GetPrototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 }
1532
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001533 // Reload global in case the loop above performed a GC.
Steve Block44f0eee2011-05-26 01:26:41 +01001534 global = isolate->context()->global();
Steve Blockd0582a62009-12-15 09:54:21 +00001535 if (assign) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001537 }
Steve Block44f0eee2011-05-26 01:26:41 +01001538 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001539}
1540
1541
Ben Murdoch8b112d22011-06-08 16:22:53 +01001542RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 // All constants are declared with an initial value. The name
1544 // of the constant is the first argument and the initial value
1545 // is the second.
1546 RUNTIME_ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 Handle<Object> value = args.at<Object>(1);
1549
1550 // Get the current global object from top.
Steve Block44f0eee2011-05-26 01:26:41 +01001551 GlobalObject* global = isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00001552
1553 // According to ECMA-262, section 12.2, page 62, the property must
1554 // not be deletable. Since it's a const, it must be READ_ONLY too.
1555 PropertyAttributes attributes =
1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1557
1558 // Lookup the property locally in the global object. If it isn't
1559 // there, we add the property and take special precautions to always
1560 // add it as a local property even in case of callbacks in the
1561 // prototype chain (this rules out using SetProperty).
Ben Murdoch086aeea2011-05-13 15:57:08 +01001562 // We use SetLocalPropertyIgnoreAttributes instead
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001563 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001564 global->LocalLookup(*name, &lookup);
1565 if (!lookup.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001566 return global->SetLocalPropertyIgnoreAttributes(*name,
1567 *value,
1568 attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001569 }
1570
Steve Blocka7e24c12009-10-30 11:49:00 +00001571 if (!lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 // Restore global object from context (in case of GC) and continue
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001573 // with setting the value.
Steve Block44f0eee2011-05-26 01:26:41 +01001574 HandleScope handle_scope(isolate);
1575 Handle<GlobalObject> global(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001576
Steve Block1e0659c2011-05-24 12:43:12 +01001577 // BUG 1213575: Handle the case where we have to set a read-only
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 // property through an interceptor and only do it if it's
1579 // uninitialized, e.g. the hole. Nirk...
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001580 // Passing non-strict mode because the property is writable.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001581 RETURN_IF_EMPTY_HANDLE(
1582 isolate,
1583 JSReceiver::SetProperty(global, name, value, attributes,
1584 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001585 return *value;
1586 }
1587
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001588 // Set the value, but only if we're assigning the initial value to a
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 // constant. For now, we determine this by checking if the
1590 // current value is the hole.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001591 // Strict mode handling not needed (const is disallowed in strict mode).
Steve Blocka7e24c12009-10-30 11:49:00 +00001592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = global->properties();
1595 int index = lookup.GetFieldIndex();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1601 !lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 global->SetNormalizedProperty(&lookup, *value);
1603 }
1604 } else {
1605 // Ignore re-initialization of constants that have already been
1606 // assigned a function value.
1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1608 }
1609
1610 // Use the set value as the result of the operation.
1611 return *value;
1612}
1613
1614
Ben Murdoch8b112d22011-06-08 16:22:53 +01001615RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001616 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001617 ASSERT(args.length() == 3);
1618
Steve Block44f0eee2011-05-26 01:26:41 +01001619 Handle<Object> value(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001620 ASSERT(!value->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +00001621
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001622 // Initializations are always done in a function or global context.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001623 RUNTIME_ASSERT(args[1]->IsContext());
1624 Handle<Context> context(Context::cast(args[1])->declaration_context());
1625
1626 Handle<String> name(String::cast(args[2]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001627
1628 int index;
1629 PropertyAttributes attributes;
1630 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001631 BindingFlags binding_flags;
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 Handle<Object> holder =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001633 context->Lookup(name, flags, &index, &attributes, &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001634
Ben Murdoch85b71792012-04-11 18:30:58 +01001635 if (index >= 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001636 ASSERT(holder->IsContext());
1637 // Property was found in a context. Perform the assignment if we
1638 // found some non-constant or an uninitialized constant.
1639 Handle<Context> context = Handle<Context>::cast(holder);
1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1641 context->set(index, *value);
Ben Murdoch85b71792012-04-11 18:30:58 +01001642 }
1643 return *value;
1644 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001645
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001646 // The property could not be found, we introduce it as a property of the
1647 // global object.
Ben Murdoch85b71792012-04-11 18:30:58 +01001648 if (attributes == ABSENT) {
1649 Handle<JSObject> global = Handle<JSObject>(
1650 isolate->context()->global());
1651 // Strict mode not needed (const disallowed in strict mode).
1652 RETURN_IF_EMPTY_HANDLE(
1653 isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
Ben Murdoch85b71792012-04-11 18:30:58 +01001655 return *value;
1656 }
1657
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001658 // The property was present in some function's context extension object,
1659 // as a property on the subject of a with, or as a property of the global
1660 // object.
1661 //
1662 // In most situations, eval-introduced consts should still be present in
1663 // the context extension object. However, because declaration and
1664 // initialization are separate, the property might have been deleted
1665 // before we reach the initialization point.
1666 //
1667 // Example:
1668 //
1669 // function f() { eval("delete x; const x;"); }
1670 //
1671 // In that case, the initialization behaves like a normal assignment.
1672 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Ben Murdoch85b71792012-04-11 18:30:58 +01001673
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001674 if (*object == context->extension()) {
1675 // This is the property that was introduced by the const declaration.
1676 // Set it if it hasn't been set before. NOTE: We cannot use
1677 // GetProperty() to get the current value as it 'unholes' the value.
1678 LookupResult lookup(isolate);
1679 object->LocalLookupRealNamedProperty(*name, &lookup);
1680 ASSERT(lookup.IsFound()); // the property was declared
Steve Blocka7e24c12009-10-30 11:49:00 +00001681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1682
1683 PropertyType type = lookup.type();
1684 if (type == FIELD) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001685 FixedArray* properties = object->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +00001686 int index = lookup.GetFieldIndex();
1687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
1690 } else if (type == NORMAL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
1698 }
1699 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
Steve Blocka7e24c12009-10-30 11:49:00 +00001702 if ((attributes & READ_ONLY) == 0) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001703 // Strict mode not needed (const disallowed in strict mode).
Steve Block1e0659c2011-05-24 12:43:12 +01001704 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001705 isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001708 }
1709 }
1710
1711 return *value;
1712}
1713
1714
Ben Murdoch8b112d22011-06-08 16:22:53 +01001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01001717 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001718 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 if (object->HasFastProperties()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 }
1724 return *object;
1725}
1726
1727
Ben Murdoch8b112d22011-06-08 16:22:53 +01001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
Steve Block44f0eee2011-05-26 01:26:41 +01001729 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001730 ASSERT(args.length() == 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001733 // Due to the way the JS calls are constructed this must be less than the
1734 // length of a string, i.e. it is always a Smi. We check anyway for security.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001737 RUNTIME_ASSERT(last_match_info->HasFastElements());
1738 RUNTIME_ASSERT(index >= 0);
1739 RUNTIME_ASSERT(index <= subject->length());
Steve Block44f0eee2011-05-26 01:26:41 +01001740 isolate->counters()->regexp_entry_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 Handle<Object> result = RegExpImpl::Exec(regexp,
1742 subject,
1743 index,
1744 last_match_info);
1745 if (result.is_null()) return Failure::Exception();
1746 return *result;
1747}
1748
1749
Ben Murdoch8b112d22011-06-08 16:22:53 +01001750RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
Steve Block6ded16b2010-05-10 14:33:55 +01001751 ASSERT(args.length() == 3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001752 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001753 if (elements_count < 0 ||
1754 elements_count > FixedArray::kMaxLength ||
1755 !Smi::IsValid(elements_count)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001756 return isolate->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01001757 }
John Reck59135872010-11-02 12:39:01 -07001758 Object* new_object;
1759 { MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +01001760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
John Reck59135872010-11-02 12:39:01 -07001761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1762 }
Steve Block6ded16b2010-05-10 14:33:55 +01001763 FixedArray* elements = FixedArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
John Reck59135872010-11-02 12:39:01 -07001766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1767 }
Steve Block6ded16b2010-05-10 14:33:55 +01001768 {
1769 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +01001770 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001771 reinterpret_cast<HeapObject*>(new_object)->
Steve Block44f0eee2011-05-26 01:26:41 +01001772 set_map(isolate->global_context()->regexp_result_map());
Steve Block6ded16b2010-05-10 14:33:55 +01001773 }
1774 JSArray* array = JSArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001775 array->set_properties(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001776 array->set_elements(elements);
1777 array->set_length(Smi::FromInt(elements_count));
1778 // Write in-object properties after the length of the array.
1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1781 return array;
1782}
1783
1784
Ben Murdoch8b112d22011-06-08 16:22:53 +01001785RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
Steve Block6ded16b2010-05-10 14:33:55 +01001786 AssertNoAllocation no_alloc;
1787 ASSERT(args.length() == 5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1789 CONVERT_ARG_CHECKED(String, source, 1);
Steve Block6ded16b2010-05-10 14:33:55 +01001790
1791 Object* global = args[2];
Steve Block44f0eee2011-05-26 01:26:41 +01001792 if (!global->IsTrue()) global = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001793
1794 Object* ignoreCase = args[3];
Steve Block44f0eee2011-05-26 01:26:41 +01001795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001796
1797 Object* multiline = args[4];
Steve Block44f0eee2011-05-26 01:26:41 +01001798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001799
1800 Map* map = regexp->map();
1801 Object* constructor = map->constructor();
1802 if (constructor->IsJSFunction() &&
1803 JSFunction::cast(constructor)->initial_map() == map) {
1804 // If we still have the original map, set in-object properties directly.
1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001806 // Both true and false are immovable immortal objects so no need for write
1807 // barrier.
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
Steve Block6ded16b2010-05-10 14:33:55 +01001814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1815 Smi::FromInt(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001816 SKIP_WRITE_BARRIER); // It's a Smi.
Steve Block6ded16b2010-05-10 14:33:55 +01001817 return regexp;
1818 }
1819
Steve Block44f0eee2011-05-26 01:26:41 +01001820 // Map has changed, so use generic, but slower, method.
Steve Block6ded16b2010-05-10 14:33:55 +01001821 PropertyAttributes final =
1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1823 PropertyAttributes writable =
1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
Steve Block44f0eee2011-05-26 01:26:41 +01001825 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -07001826 MaybeObject* result;
Steve Block44f0eee2011-05-26 01:26:41 +01001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001828 source,
1829 final);
John Reck59135872010-11-02 12:39:01 -07001830 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001832 global,
1833 final);
John Reck59135872010-11-02 12:39:01 -07001834 ASSERT(!result->IsFailure());
1835 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001836 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001837 ignoreCase,
1838 final);
John Reck59135872010-11-02 12:39:01 -07001839 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001841 multiline,
1842 final);
John Reck59135872010-11-02 12:39:01 -07001843 ASSERT(!result->IsFailure());
1844 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001846 Smi::FromInt(0),
1847 writable);
John Reck59135872010-11-02 12:39:01 -07001848 ASSERT(!result->IsFailure());
1849 USE(result);
Steve Block6ded16b2010-05-10 14:33:55 +01001850 return regexp;
1851}
1852
1853
Ben Murdoch8b112d22011-06-08 16:22:53 +01001854RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
Steve Block44f0eee2011-05-26 01:26:41 +01001855 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001856 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001858 // This is necessary to enable fast checks for absence of elements
1859 // on Array.prototype and below.
Steve Block44f0eee2011-05-26 01:26:41 +01001860 prototype->set_elements(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001861 return Smi::FromInt(0);
1862}
1863
1864
Steve Block44f0eee2011-05-26 01:26:41 +01001865static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1866 Handle<JSObject> holder,
Steve Block6ded16b2010-05-10 14:33:55 +01001867 const char* name,
Kristian Monsen25f61362010-05-21 11:50:48 +01001868 Builtins::Name builtin_name) {
Steve Block44f0eee2011-05-26 01:26:41 +01001869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1871 Handle<JSFunction> optimized =
1872 isolate->factory()->NewFunction(key,
1873 JS_OBJECT_TYPE,
1874 JSObject::kHeaderSize,
1875 code,
1876 false);
Steve Block6ded16b2010-05-10 14:33:55 +01001877 optimized->shared()->DontAdaptArguments();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +01001879 return optimized;
1880}
1881
1882
Ben Murdoch8b112d22011-06-08 16:22:53 +01001883RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
Steve Block44f0eee2011-05-26 01:26:41 +01001884 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001885 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01001887
Steve Block44f0eee2011-05-26 01:26:41 +01001888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
Steve Block6ded16b2010-05-10 14:33:55 +01001895
1896 return *holder;
1897}
1898
1899
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001901 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
1903
1904 if (!callable->IsJSFunction()) {
1905 HandleScope scope(isolate);
1906 bool threw = false;
1907 Handle<Object> delegate =
1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1909 if (threw) return Failure::Exception();
1910 callable = JSFunction::cast(*delegate);
1911 }
1912 JSFunction* function = JSFunction::cast(callable);
1913
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001914 SharedFunctionInfo* shared = function->shared();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001915 if (shared->native() || !shared->is_classic_mode()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001916 return isolate->heap()->undefined_value();
1917 }
1918 // Returns undefined for strict or native functions, or
1919 // the associated global receiver for "normal" functions.
1920
Steve Block44f0eee2011-05-26 01:26:41 +01001921 Context* global_context =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001922 function->context()->global()->global_context();
Steve Block6ded16b2010-05-10 14:33:55 +01001923 return global_context->global()->global_receiver();
1924}
1925
1926
Ben Murdoch8b112d22011-06-08 16:22:53 +01001927RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +01001928 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 ASSERT(args.length() == 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001931 int index = args.smi_at(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 Handle<String> pattern = args.at<String>(2);
1933 Handle<String> flags = args.at<String>(3);
1934
1935 // Get the RegExp function from the context in the literals array.
1936 // This is the RegExp function from the context in which the
1937 // function was created. We do not use the RegExp function from the
1938 // current global context because this might be the RegExp function
1939 // from another context which we should not have access to.
1940 Handle<JSFunction> constructor =
1941 Handle<JSFunction>(
1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
1943 // Compute the regular expression literal.
1944 bool has_pending_exception;
1945 Handle<Object> regexp =
1946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1947 &has_pending_exception);
1948 if (has_pending_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01001949 ASSERT(isolate->has_pending_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 return Failure::Exception();
1951 }
1952 literals->set(index, *regexp);
1953 return *regexp;
1954}
1955
1956
Ben Murdoch8b112d22011-06-08 16:22:53 +01001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 return f->shared()->name();
1963}
1964
1965
Ben Murdoch8b112d22011-06-08 16:22:53 +01001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1971 CONVERT_ARG_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 f->shared()->set_name(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001973 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001974}
1975
1976
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001981 return isolate->heap()->ToBoolean(
1982 f->shared()->name_should_print_as_anonymous());
1983}
1984
1985
1986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001990 f->shared()->set_name_should_print_as_anonymous(true);
1991 return isolate->heap()->undefined_value();
1992}
1993
1994
Ben Murdoch8b112d22011-06-08 16:22:53 +01001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
Steve Block6ded16b2010-05-10 14:33:55 +01001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001999 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01002000 Object* obj = f->RemovePrototype();
2001 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01002002
Steve Block44f0eee2011-05-26 01:26:41 +01002003 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01002004}
2005
2006
Ben Murdoch8b112d22011-06-08 16:22:53 +01002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +01002008 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 ASSERT(args.length() == 1);
2010
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002011 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01002012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2013 if (!script->IsScript()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002014
2015 return *GetScriptWrapper(Handle<Script>::cast(script));
2016}
2017
2018
Ben Murdoch8b112d22011-06-08 16:22:53 +01002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002020 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002021 ASSERT(args.length() == 1);
2022
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2024 Handle<SharedFunctionInfo> shared(f->shared());
2025 return *shared->GetSourceCode();
Steve Blocka7e24c12009-10-30 11:49:00 +00002026}
2027
2028
Ben Murdoch8b112d22011-06-08 16:22:53 +01002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 1);
2032
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002033 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002034 int pos = fun->shared()->start_position();
2035 return Smi::FromInt(pos);
2036}
2037
2038
Ben Murdoch8b112d22011-06-08 16:22:53 +01002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002040 ASSERT(args.length() == 2);
2041
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002042 CONVERT_ARG_CHECKED(Code, code, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2044
Steve Blocka7e24c12009-10-30 11:49:00 +00002045 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2046
2047 Address pc = code->address() + offset;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002048 return Smi::FromInt(code->SourcePosition(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00002049}
2050
2051
Ben Murdoch8b112d22011-06-08 16:22:53 +01002052RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002053 NoHandleAllocation ha;
2054 ASSERT(args.length() == 2);
2055
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002056 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2057 CONVERT_ARG_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002058 fun->SetInstanceClassName(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002059 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002060}
2061
2062
Ben Murdoch8b112d22011-06-08 16:22:53 +01002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002067 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2068 CONVERT_SMI_ARG_CHECKED(length, 1);
2069 fun->shared()->set_length(length);
2070 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002071}
2072
2073
Ben Murdoch8b112d22011-06-08 16:22:53 +01002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 NoHandleAllocation ha;
2076 ASSERT(args.length() == 2);
2077
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002078 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01002079 ASSERT(fun->should_have_prototype());
John Reck59135872010-11-02 12:39:01 -07002080 Object* obj;
2081 { MaybeObject* maybe_obj =
2082 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2084 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002085 return args[0]; // return TOS
2086}
2087
2088
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2090 NoHandleAllocation ha;
2091 RUNTIME_ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002092 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002093
2094 MaybeObject* maybe_name =
2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2096 String* name;
2097 if (!maybe_name->To(&name)) return maybe_name;
2098
2099 if (function->HasFastProperties()) {
2100 // Construct a new field descriptor with updated attributes.
2101 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2102 int index = instance_desc->Search(name);
2103 ASSERT(index != DescriptorArray::kNotFound);
2104 PropertyDetails details(instance_desc->GetDetails(index));
2105 CallbacksDescriptor new_desc(name,
2106 instance_desc->GetValue(index),
2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2108 details.index());
2109 // Construct a new field descriptors array containing the new descriptor.
2110 Object* descriptors_unchecked;
2111 { MaybeObject* maybe_descriptors_unchecked =
2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2114 return maybe_descriptors_unchecked;
2115 }
2116 }
2117 DescriptorArray* new_descriptors =
2118 DescriptorArray::cast(descriptors_unchecked);
2119 // Create a new map featuring the new field descriptors array.
2120 Object* map_unchecked;
2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2123 return maybe_map_unchecked;
2124 }
2125 }
2126 Map* new_map = Map::cast(map_unchecked);
2127 new_map->set_instance_descriptors(new_descriptors);
2128 function->set_map(new_map);
2129 } else { // Dictionary properties.
2130 // Directly manipulate the property details.
2131 int entry = function->property_dictionary()->FindEntry(name);
2132 ASSERT(entry != StringDictionary::kNotFound);
2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2134 PropertyDetails new_details(
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.type(),
2137 details.index());
2138 function->property_dictionary()->DetailsAtPut(entry, new_details);
2139 }
2140 return function;
2141}
2142
2143
Ben Murdoch8b112d22011-06-08 16:22:53 +01002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002149 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00002150}
2151
Steve Block44f0eee2011-05-26 01:26:41 +01002152
Ben Murdoch8b112d22011-06-08 16:22:53 +01002153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002154 NoHandleAllocation ha;
2155 ASSERT(args.length() == 1);
2156
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002157 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002158 return isolate->heap()->ToBoolean(f->IsBuiltin());
Steve Blocka7e24c12009-10-30 11:49:00 +00002159}
2160
2161
Ben Murdoch8b112d22011-06-08 16:22:53 +01002162RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002163 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002164 ASSERT(args.length() == 2);
2165
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 Handle<Object> code = args.at<Object>(1);
2168
2169 Handle<Context> context(target->context());
2170
2171 if (!code->IsNull()) {
2172 RUNTIME_ASSERT(code->IsJSFunction());
2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Leon Clarke4515c472010-02-03 11:58:03 +00002174 Handle<SharedFunctionInfo> shared(fun->shared());
Leon Clarke4515c472010-02-03 11:58:03 +00002175
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002177 return Failure::Exception();
2178 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002179 // Since we don't store the source for this we should never
2180 // optimize this.
2181 shared->code()->set_optimizable(false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002182 // Set the code, scope info, formal parameter count,
2183 // and the length of the target function.
Iain Merrick75681382010-08-19 15:07:18 +01002184 target->shared()->set_code(shared->code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002185 target->ReplaceCode(shared->code());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002186 target->shared()->set_scope_info(shared->scope_info());
Leon Clarke4515c472010-02-03 11:58:03 +00002187 target->shared()->set_length(shared->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002188 target->shared()->set_formal_parameter_count(
Leon Clarke4515c472010-02-03 11:58:03 +00002189 shared->formal_parameter_count());
Steve Blocka7e24c12009-10-30 11:49:00 +00002190 // Set the source code of the target function to undefined.
2191 // SetCode is only used for built-in constructors like String,
2192 // Array, and Object, and some web code
2193 // doesn't like seeing source code for constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01002194 target->shared()->set_script(isolate->heap()->undefined_value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01002195 target->shared()->code()->set_optimizable(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002196 // Clear the optimization hints related to the compiled code as these are no
2197 // longer valid when the code is overwritten.
2198 target->shared()->ClearThisPropertyAssignmentsInfo();
2199 context = Handle<Context>(fun->context());
2200
2201 // Make sure we get a fresh copy of the literal vector to avoid
2202 // cross context contamination.
2203 int number_of_literals = fun->NumberOfLiterals();
2204 Handle<FixedArray> literals =
Steve Block44f0eee2011-05-26 01:26:41 +01002205 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00002206 if (number_of_literals > 0) {
2207 // Insert the object, regexp and array functions in the literals
2208 // array prefix. These are the functions that will be used when
2209 // creating object, regexp and array literals.
2210 literals->set(JSFunction::kLiteralGlobalContextIndex,
2211 context->global_context());
2212 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002213 target->set_literals(*literals);
Steve Block44f0eee2011-05-26 01:26:41 +01002214 target->set_next_function_link(isolate->heap()->undefined_value());
Ben Murdoch589d6972011-11-30 16:04:58 +00002215
2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2217 isolate->logger()->LogExistingFunction(
2218 shared, Handle<Code>(shared->code()));
2219 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002220 }
2221
2222 target->set_context(*context);
2223 return *target;
2224}
2225
2226
Ben Murdoch8b112d22011-06-08 16:22:53 +01002227RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01002228 HandleScope scope(isolate);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002229 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002231 CONVERT_SMI_ARG_CHECKED(num, 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002232 RUNTIME_ASSERT(num >= 0);
2233 SetExpectedNofProperties(function, num);
Steve Block44f0eee2011-05-26 01:26:41 +01002234 return isolate->heap()->undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002235}
2236
2237
Steve Block44f0eee2011-05-26 01:26:41 +01002238MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2239 Object* char_code) {
Leon Clarkee46be812010-01-19 14:06:41 +00002240 uint32_t code;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002241 if (char_code->ToArrayIndex(&code)) {
Leon Clarkee46be812010-01-19 14:06:41 +00002242 if (code <= 0xffff) {
Steve Block44f0eee2011-05-26 01:26:41 +01002243 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
Leon Clarkee46be812010-01-19 14:06:41 +00002244 }
2245 }
Steve Block44f0eee2011-05-26 01:26:41 +01002246 return isolate->heap()->empty_string();
Leon Clarkee46be812010-01-19 14:06:41 +00002247}
2248
2249
Ben Murdoch8b112d22011-06-08 16:22:53 +01002250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 2);
2253
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002254 CONVERT_ARG_CHECKED(String, subject, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002255 Object* index = args[1];
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002256 RUNTIME_ASSERT(index->IsNumber());
Steve Blocka7e24c12009-10-30 11:49:00 +00002257
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002258 uint32_t i = 0;
2259 if (index->IsSmi()) {
2260 int value = Smi::cast(index)->value();
Steve Block44f0eee2011-05-26 01:26:41 +01002261 if (value < 0) return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002262 i = value;
2263 } else {
2264 ASSERT(index->IsHeapNumber());
2265 double value = HeapNumber::cast(index)->value();
2266 i = static_cast<uint32_t>(DoubleToInteger(value));
Leon Clarkee46be812010-01-19 14:06:41 +00002267 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002268
2269 // Flatten the string. If someone wants to get a char at an index
2270 // in a cons string, it is likely that more indices will be
2271 // accessed.
John Reck59135872010-11-02 12:39:01 -07002272 Object* flat;
2273 { MaybeObject* maybe_flat = subject->TryFlatten();
2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2275 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002276 subject = String::cast(flat);
2277
2278 if (i >= static_cast<uint32_t>(subject->length())) {
Steve Block44f0eee2011-05-26 01:26:41 +01002279 return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002280 }
2281
2282 return Smi::FromInt(subject->Get(i));
Leon Clarkee46be812010-01-19 14:06:41 +00002283}
2284
2285
Ben Murdoch8b112d22011-06-08 16:22:53 +01002286RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002287 NoHandleAllocation ha;
2288 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01002289 return CharFromCode(isolate, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002290}
2291
Steve Block6ded16b2010-05-10 14:33:55 +01002292
2293class FixedArrayBuilder {
2294 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002297 length_(0),
2298 has_non_smi_elements_(false) {
Steve Block6ded16b2010-05-10 14:33:55 +01002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(initial_capacity > 0);
2302 }
2303
2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2305 : array_(backing_store),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002306 length_(0),
2307 has_non_smi_elements_(false) {
Steve Block6ded16b2010-05-10 14:33:55 +01002308 // Require a non-zero initial size. Ensures that doubling the size to
2309 // extend the array will work.
2310 ASSERT(backing_store->length() > 0);
2311 }
2312
2313 bool HasCapacity(int elements) {
2314 int length = array_->length();
2315 int required_length = length_ + elements;
2316 return (length >= required_length);
2317 }
2318
2319 void EnsureCapacity(int elements) {
2320 int length = array_->length();
2321 int required_length = length_ + elements;
2322 if (length < required_length) {
2323 int new_length = length;
2324 do {
2325 new_length *= 2;
2326 } while (new_length < required_length);
2327 Handle<FixedArray> extended_array =
Steve Block44f0eee2011-05-26 01:26:41 +01002328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
Steve Block6ded16b2010-05-10 14:33:55 +01002329 array_->CopyTo(0, *extended_array, 0, length_);
2330 array_ = extended_array;
2331 }
2332 }
2333
2334 void Add(Object* value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002335 ASSERT(!value->IsSmi());
Steve Block6ded16b2010-05-10 14:33:55 +01002336 ASSERT(length_ < capacity());
2337 array_->set(length_, value);
2338 length_++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002339 has_non_smi_elements_ = true;
Steve Block6ded16b2010-05-10 14:33:55 +01002340 }
2341
2342 void Add(Smi* value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002343 ASSERT(value->IsSmi());
Steve Block6ded16b2010-05-10 14:33:55 +01002344 ASSERT(length_ < capacity());
2345 array_->set(length_, value);
2346 length_++;
2347 }
2348
2349 Handle<FixedArray> array() {
2350 return array_;
2351 }
2352
2353 int length() {
2354 return length_;
2355 }
2356
2357 int capacity() {
2358 return array_->length();
2359 }
2360
2361 Handle<JSArray> ToJSArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01002362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
Steve Block6ded16b2010-05-10 14:33:55 +01002363 result_array->set_length(Smi::FromInt(length_));
2364 return result_array;
2365 }
2366
2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002368 FACTORY->SetContent(target_array, array_);
Steve Block6ded16b2010-05-10 14:33:55 +01002369 target_array->set_length(Smi::FromInt(length_));
2370 return target_array;
2371 }
2372
2373 private:
2374 Handle<FixedArray> array_;
2375 int length_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002376 bool has_non_smi_elements_;
Steve Block6ded16b2010-05-10 14:33:55 +01002377};
2378
2379
Steve Blocka7e24c12009-10-30 11:49:00 +00002380// Forward declarations.
Steve Block6ded16b2010-05-10 14:33:55 +01002381const int kStringBuilderConcatHelperLengthBits = 11;
2382const int kStringBuilderConcatHelperPositionBits = 19;
Steve Blocka7e24c12009-10-30 11:49:00 +00002383
2384template <typename schar>
2385static inline void StringBuilderConcatHelper(String*,
2386 schar*,
2387 FixedArray*,
2388 int);
2389
Steve Block6ded16b2010-05-10 14:33:55 +01002390typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2391 StringBuilderSubstringLength;
2392typedef BitField<int,
2393 kStringBuilderConcatHelperLengthBits,
2394 kStringBuilderConcatHelperPositionBits>
2395 StringBuilderSubstringPosition;
2396
Steve Blocka7e24c12009-10-30 11:49:00 +00002397
2398class ReplacementStringBuilder {
2399 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002400 ReplacementStringBuilder(Heap* heap,
2401 Handle<String> subject,
2402 int estimated_part_count)
2403 : heap_(heap),
2404 array_builder_(heap->isolate(), estimated_part_count),
Steve Block6ded16b2010-05-10 14:33:55 +01002405 subject_(subject),
Steve Blocka7e24c12009-10-30 11:49:00 +00002406 character_count_(0),
2407 is_ascii_(subject->IsAsciiRepresentation()) {
2408 // Require a non-zero initial size. Ensures that doubling the size to
2409 // extend the array will work.
2410 ASSERT(estimated_part_count > 0);
2411 }
2412
Steve Block6ded16b2010-05-10 14:33:55 +01002413 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2414 int from,
2415 int to) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002416 ASSERT(from >= 0);
2417 int length = to - from;
2418 ASSERT(length > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002419 if (StringBuilderSubstringLength::is_valid(length) &&
2420 StringBuilderSubstringPosition::is_valid(from)) {
2421 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2422 StringBuilderSubstringPosition::encode(from);
Steve Block6ded16b2010-05-10 14:33:55 +01002423 builder->Add(Smi::FromInt(encoded_slice));
Steve Blocka7e24c12009-10-30 11:49:00 +00002424 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002425 // Otherwise encode as two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01002426 builder->Add(Smi::FromInt(-length));
2427 builder->Add(Smi::FromInt(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00002428 }
Steve Block6ded16b2010-05-10 14:33:55 +01002429 }
2430
2431
2432 void EnsureCapacity(int elements) {
2433 array_builder_.EnsureCapacity(elements);
2434 }
2435
2436
2437 void AddSubjectSlice(int from, int to) {
2438 AddSubjectSlice(&array_builder_, from, to);
2439 IncrementCharacterCount(to - from);
Steve Blocka7e24c12009-10-30 11:49:00 +00002440 }
2441
2442
2443 void AddString(Handle<String> string) {
2444 int length = string->length();
2445 ASSERT(length > 0);
2446 AddElement(*string);
2447 if (!string->IsAsciiRepresentation()) {
2448 is_ascii_ = false;
2449 }
2450 IncrementCharacterCount(length);
2451 }
2452
2453
2454 Handle<String> ToString() {
Steve Block6ded16b2010-05-10 14:33:55 +01002455 if (array_builder_.length() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01002456 return heap_->isolate()->factory()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 }
2458
2459 Handle<String> joined_string;
2460 if (is_ascii_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002462 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00002463 char* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002466 *array_builder_.array(),
2467 array_builder_.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002468 joined_string = Handle<String>::cast(seq);
Steve Blocka7e24c12009-10-30 11:49:00 +00002469 } else {
2470 // Non-ASCII.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002472 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00002473 uc16* char_buffer = seq->GetChars();
2474 StringBuilderConcatHelper(*subject_,
2475 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002476 *array_builder_.array(),
2477 array_builder_.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002478 joined_string = Handle<String>::cast(seq);
Steve Blocka7e24c12009-10-30 11:49:00 +00002479 }
2480 return joined_string;
2481 }
2482
2483
2484 void IncrementCharacterCount(int by) {
Leon Clarkee46be812010-01-19 14:06:41 +00002485 if (character_count_ > String::kMaxLength - by) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002486 V8::FatalProcessOutOfMemory("String.replace result too large.");
2487 }
2488 character_count_ += by;
2489 }
2490
Steve Block6ded16b2010-05-10 14:33:55 +01002491 Handle<JSArray> GetParts() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002492 return array_builder_.ToJSArray();
Steve Block6ded16b2010-05-10 14:33:55 +01002493 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002494
Steve Block6ded16b2010-05-10 14:33:55 +01002495 private:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002496 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2497 return heap_->isolate()->factory()->NewRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00002498 }
2499
2500
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2502 return heap_->isolate()->factory()->NewRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00002503 }
2504
2505
2506 void AddElement(Object* element) {
2507 ASSERT(element->IsSmi() || element->IsString());
Steve Block6ded16b2010-05-10 14:33:55 +01002508 ASSERT(array_builder_.capacity() > array_builder_.length());
2509 array_builder_.Add(element);
Steve Blocka7e24c12009-10-30 11:49:00 +00002510 }
2511
Steve Block44f0eee2011-05-26 01:26:41 +01002512 Heap* heap_;
Steve Block6ded16b2010-05-10 14:33:55 +01002513 FixedArrayBuilder array_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002514 Handle<String> subject_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002515 int character_count_;
2516 bool is_ascii_;
2517};
2518
2519
2520class CompiledReplacement {
2521 public:
2522 CompiledReplacement()
Ben Murdoch589d6972011-11-30 16:04:58 +00002523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00002524
2525 void Compile(Handle<String> replacement,
2526 int capture_count,
2527 int subject_length);
2528
2529 void Apply(ReplacementStringBuilder* builder,
2530 int match_from,
2531 int match_to,
2532 Handle<JSArray> last_match_info);
2533
2534 // Number of distinct parts of the replacement pattern.
2535 int parts() {
2536 return parts_.length();
2537 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002538
Ben Murdoch589d6972011-11-30 16:04:58 +00002539 bool simple_hint() {
2540 return simple_hint_;
2541 }
2542
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 private:
2544 enum PartType {
2545 SUBJECT_PREFIX = 1,
2546 SUBJECT_SUFFIX,
2547 SUBJECT_CAPTURE,
2548 REPLACEMENT_SUBSTRING,
2549 REPLACEMENT_STRING,
2550
2551 NUMBER_OF_PART_TYPES
2552 };
2553
2554 struct ReplacementPart {
2555 static inline ReplacementPart SubjectMatch() {
2556 return ReplacementPart(SUBJECT_CAPTURE, 0);
2557 }
2558 static inline ReplacementPart SubjectCapture(int capture_index) {
2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2560 }
2561 static inline ReplacementPart SubjectPrefix() {
2562 return ReplacementPart(SUBJECT_PREFIX, 0);
2563 }
2564 static inline ReplacementPart SubjectSuffix(int subject_length) {
2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2566 }
2567 static inline ReplacementPart ReplacementString() {
2568 return ReplacementPart(REPLACEMENT_STRING, 0);
2569 }
2570 static inline ReplacementPart ReplacementSubString(int from, int to) {
2571 ASSERT(from >= 0);
2572 ASSERT(to > from);
2573 return ReplacementPart(-from, to);
2574 }
2575
2576 // If tag <= 0 then it is the negation of a start index of a substring of
2577 // the replacement pattern, otherwise it's a value from PartType.
2578 ReplacementPart(int tag, int data)
2579 : tag(tag), data(data) {
2580 // Must be non-positive or a PartType value.
2581 ASSERT(tag < NUMBER_OF_PART_TYPES);
2582 }
2583 // Either a value of PartType or a non-positive number that is
2584 // the negation of an index into the replacement string.
2585 int tag;
2586 // The data value's interpretation depends on the value of tag:
2587 // tag == SUBJECT_PREFIX ||
2588 // tag == SUBJECT_SUFFIX: data is unused.
2589 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2590 // tag == REPLACEMENT_SUBSTRING ||
2591 // tag == REPLACEMENT_STRING: data is index into array of substrings
2592 // of the replacement string.
2593 // tag <= 0: Temporary representation of the substring of the replacement
2594 // string ranging over -tag .. data.
2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2596 // substring objects.
2597 int data;
2598 };
2599
2600 template<typename Char>
Ben Murdoch589d6972011-11-30 16:04:58 +00002601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
Steve Blocka7e24c12009-10-30 11:49:00 +00002602 Vector<Char> characters,
2603 int capture_count,
2604 int subject_length) {
2605 int length = characters.length();
2606 int last = 0;
2607 for (int i = 0; i < length; i++) {
2608 Char c = characters[i];
2609 if (c == '$') {
2610 int next_index = i + 1;
2611 if (next_index == length) { // No next character!
2612 break;
2613 }
2614 Char c2 = characters[next_index];
2615 switch (c2) {
2616 case '$':
2617 if (i > last) {
2618 // There is a substring before. Include the first "$".
2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2620 last = next_index + 1; // Continue after the second "$".
2621 } else {
2622 // Let the next substring start with the second "$".
2623 last = next_index;
2624 }
2625 i = next_index;
2626 break;
2627 case '`':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectPrefix());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '\'':
2636 if (i > last) {
2637 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2638 }
2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2640 i = next_index;
2641 last = i + 1;
2642 break;
2643 case '&':
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
2647 parts->Add(ReplacementPart::SubjectMatch());
2648 i = next_index;
2649 last = i + 1;
2650 break;
2651 case '0':
2652 case '1':
2653 case '2':
2654 case '3':
2655 case '4':
2656 case '5':
2657 case '6':
2658 case '7':
2659 case '8':
2660 case '9': {
2661 int capture_ref = c2 - '0';
2662 if (capture_ref > capture_count) {
2663 i = next_index;
2664 continue;
2665 }
2666 int second_digit_index = next_index + 1;
2667 if (second_digit_index < length) {
2668 // Peek ahead to see if we have two digits.
2669 Char c3 = characters[second_digit_index];
2670 if ('0' <= c3 && c3 <= '9') { // Double digits.
2671 int double_digit_ref = capture_ref * 10 + c3 - '0';
2672 if (double_digit_ref <= capture_count) {
2673 next_index = second_digit_index;
2674 capture_ref = double_digit_ref;
2675 }
2676 }
2677 }
2678 if (capture_ref > 0) {
2679 if (i > last) {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2681 }
2682 ASSERT(capture_ref <= capture_count);
2683 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2684 last = next_index + 1;
2685 }
2686 i = next_index;
2687 break;
2688 }
2689 default:
2690 i = next_index;
2691 break;
2692 }
2693 }
2694 }
2695 if (length > last) {
2696 if (last == 0) {
2697 parts->Add(ReplacementPart::ReplacementString());
Ben Murdoch589d6972011-11-30 16:04:58 +00002698 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002699 } else {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2701 }
2702 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002703 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00002704 }
2705
2706 ZoneList<ReplacementPart> parts_;
2707 ZoneList<Handle<String> > replacement_substrings_;
Ben Murdoch589d6972011-11-30 16:04:58 +00002708 bool simple_hint_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002709};
2710
2711
2712void CompiledReplacement::Compile(Handle<String> replacement,
2713 int capture_count,
2714 int subject_length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002715 {
Steve Blocka7e24c12009-10-30 11:49:00 +00002716 AssertNoAllocation no_alloc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002717 String::FlatContent content = replacement->GetFlatContent();
2718 ASSERT(content.IsFlat());
2719 if (content.IsAscii()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002720 simple_hint_ = ParseReplacementPattern(&parts_,
2721 content.ToAsciiVector(),
2722 capture_count,
2723 subject_length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002724 } else {
2725 ASSERT(content.IsTwoByte());
Ben Murdoch589d6972011-11-30 16:04:58 +00002726 simple_hint_ = ParseReplacementPattern(&parts_,
2727 content.ToUC16Vector(),
2728 capture_count,
2729 subject_length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002730 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002731 }
Steve Block44f0eee2011-05-26 01:26:41 +01002732 Isolate* isolate = replacement->GetIsolate();
Steve Blockd0582a62009-12-15 09:54:21 +00002733 // Find substrings of replacement string and create them as String objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002734 int substring_index = 0;
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 int tag = parts_[i].tag;
2737 if (tag <= 0) { // A replacement string slice.
2738 int from = -tag;
2739 int to = parts_[i].data;
Steve Block44f0eee2011-05-26 01:26:41 +01002740 replacement_substrings_.Add(
2741 isolate->factory()->NewSubString(replacement, from, to));
Steve Blocka7e24c12009-10-30 11:49:00 +00002742 parts_[i].tag = REPLACEMENT_SUBSTRING;
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 } else if (tag == REPLACEMENT_STRING) {
2746 replacement_substrings_.Add(replacement);
2747 parts_[i].data = substring_index;
2748 substring_index++;
2749 }
2750 }
2751}
2752
2753
2754void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2755 int match_from,
2756 int match_to,
2757 Handle<JSArray> last_match_info) {
2758 for (int i = 0, n = parts_.length(); i < n; i++) {
2759 ReplacementPart part = parts_[i];
2760 switch (part.tag) {
2761 case SUBJECT_PREFIX:
2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2763 break;
2764 case SUBJECT_SUFFIX: {
2765 int subject_length = part.data;
2766 if (match_to < subject_length) {
2767 builder->AddSubjectSlice(match_to, subject_length);
2768 }
2769 break;
2770 }
2771 case SUBJECT_CAPTURE: {
2772 int capture = part.data;
2773 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2774 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2776 if (from >= 0 && to > from) {
2777 builder->AddSubjectSlice(from, to);
2778 }
2779 break;
2780 }
2781 case REPLACEMENT_SUBSTRING:
2782 case REPLACEMENT_STRING:
2783 builder->AddString(replacement_substrings_[part.data]);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791
Ben Murdoch589d6972011-11-30 16:04:58 +00002792void FindAsciiStringIndices(Vector<const char> subject,
2793 char pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject using memchr.
2798 // Stop after finding at most limit values.
2799 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2800 const char* subject_end = subject_start + subject.length();
2801 const char* pos = subject_start;
2802 while (limit > 0) {
2803 pos = reinterpret_cast<const char*>(
2804 memchr(pos, pattern, subject_end - pos));
2805 if (pos == NULL) return;
2806 indices->Add(static_cast<int>(pos - subject_start));
2807 pos++;
2808 limit--;
2809 }
2810}
2811
2812
2813template <typename SubjectChar, typename PatternChar>
2814void FindStringIndices(Isolate* isolate,
2815 Vector<const SubjectChar> subject,
2816 Vector<const PatternChar> pattern,
2817 ZoneList<int>* indices,
2818 unsigned int limit) {
2819 ASSERT(limit > 0);
2820 // Collect indices of pattern in subject.
2821 // Stop after finding at most limit values.
2822 int pattern_length = pattern.length();
2823 int index = 0;
2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2825 while (limit > 0) {
2826 index = search.Search(subject, index);
2827 if (index < 0) return;
2828 indices->Add(index);
2829 index += pattern_length;
2830 limit--;
2831 }
2832}
2833
2834
2835void FindStringIndicesDispatch(Isolate* isolate,
2836 String* subject,
2837 String* pattern,
2838 ZoneList<int>* indices,
2839 unsigned int limit) {
2840 {
2841 AssertNoAllocation no_gc;
2842 String::FlatContent subject_content = subject->GetFlatContent();
2843 String::FlatContent pattern_content = pattern->GetFlatContent();
2844 ASSERT(subject_content.IsFlat());
2845 ASSERT(pattern_content.IsFlat());
2846 if (subject_content.IsAscii()) {
2847 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2848 if (pattern_content.IsAscii()) {
2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2850 if (pattern_vector.length() == 1) {
2851 FindAsciiStringIndices(subject_vector,
2852 pattern_vector[0],
2853 indices,
2854 limit);
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_vector,
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 } else {
2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002871 if (pattern_content.IsAscii()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002872 FindStringIndices(isolate,
2873 subject_vector,
2874 pattern_content.ToAsciiVector(),
2875 indices,
2876 limit);
2877 } else {
2878 FindStringIndices(isolate,
2879 subject_vector,
2880 pattern_content.ToUC16Vector(),
2881 indices,
2882 limit);
2883 }
2884 }
2885 }
2886}
2887
2888
2889template<typename ResultSeqString>
2890MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2891 Isolate* isolate,
2892 Handle<String> subject,
2893 Handle<JSRegExp> pattern_regexp,
2894 Handle<String> replacement) {
2895 ASSERT(subject->IsFlat());
2896 ASSERT(replacement->IsFlat());
2897
2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2899 ZoneList<int> indices(8);
2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2901 String* pattern =
2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2903 int subject_len = subject->length();
2904 int pattern_len = pattern->length();
2905 int replacement_len = replacement->length();
2906
2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2908
2909 int matches = indices.length();
2910 if (matches == 0) return *subject;
2911
2912 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2913 int subject_pos = 0;
2914 int result_pos = 0;
2915
2916 Handle<ResultSeqString> result;
2917 if (ResultSeqString::kHasAsciiEncoding) {
2918 result = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawAsciiString(result_len));
2920 } else {
2921 result = Handle<ResultSeqString>::cast(
2922 isolate->factory()->NewRawTwoByteString(result_len));
2923 }
2924
2925 for (int i = 0; i < matches; i++) {
2926 // Copy non-matched subject content.
2927 if (subject_pos < indices.at(i)) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 indices.at(i));
2932 result_pos += indices.at(i) - subject_pos;
2933 }
2934
2935 // Replace match.
2936 if (replacement_len > 0) {
2937 String::WriteToFlat(*replacement,
2938 result->GetChars() + result_pos,
2939 0,
2940 replacement_len);
2941 result_pos += replacement_len;
2942 }
2943
2944 subject_pos = indices.at(i) + pattern_len;
2945 }
2946 // Add remaining subject content at the end.
2947 if (subject_pos < subject_len) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 subject_len);
2952 }
2953 return *result;
2954}
2955
Steve Blocka7e24c12009-10-30 11:49:00 +00002956
John Reck59135872010-11-02 12:39:01 -07002957MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
Steve Block44f0eee2011-05-26 01:26:41 +01002958 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07002959 String* subject,
2960 JSRegExp* regexp,
2961 String* replacement,
2962 JSArray* last_match_info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002963 ASSERT(subject->IsFlat());
2964 ASSERT(replacement->IsFlat());
2965
Steve Block44f0eee2011-05-26 01:26:41 +01002966 HandleScope handles(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002967
2968 int length = subject->length();
2969 Handle<String> subject_handle(subject);
2970 Handle<JSRegExp> regexp_handle(regexp);
2971 Handle<String> replacement_handle(replacement);
2972 Handle<JSArray> last_match_info_handle(last_match_info);
2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2974 subject_handle,
2975 0,
2976 last_match_info_handle);
2977 if (match.is_null()) {
2978 return Failure::Exception();
2979 }
2980 if (match->IsNull()) {
2981 return *subject_handle;
2982 }
2983
2984 int capture_count = regexp_handle->CaptureCount();
2985
2986 // CompiledReplacement uses zone allocation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002987 ZoneScope zone(isolate, DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +00002988 CompiledReplacement compiled_replacement;
2989 compiled_replacement.Compile(replacement_handle,
2990 capture_count,
2991 length);
2992
2993 bool is_global = regexp_handle->GetFlags().is_global();
2994
Ben Murdoch589d6972011-11-30 16:04:58 +00002995 // Shortcut for simple non-regexp global replacements
2996 if (is_global &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002997 regexp_handle->TypeTag() == JSRegExp::ATOM &&
Ben Murdoch589d6972011-11-30 16:04:58 +00002998 compiled_replacement.simple_hint()) {
2999 if (subject_handle->HasOnlyAsciiChars() &&
3000 replacement_handle->HasOnlyAsciiChars()) {
3001 return StringReplaceStringWithString<SeqAsciiString>(
3002 isolate, subject_handle, regexp_handle, replacement_handle);
3003 } else {
3004 return StringReplaceStringWithString<SeqTwoByteString>(
3005 isolate, subject_handle, regexp_handle, replacement_handle);
3006 }
3007 }
3008
Steve Blocka7e24c12009-10-30 11:49:00 +00003009 // Guessing the number of parts that the final result string is built
3010 // from. Global regexps can match any number of times, so we guess
3011 // conservatively.
3012 int expected_parts =
3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
Steve Block44f0eee2011-05-26 01:26:41 +01003014 ReplacementStringBuilder builder(isolate->heap(),
3015 subject_handle,
3016 expected_parts);
Steve Blocka7e24c12009-10-30 11:49:00 +00003017
3018 // Index of end of last match.
3019 int prev = 0;
3020
Steve Blockd0582a62009-12-15 09:54:21 +00003021 // Number of parts added by compiled replacement plus preceeding
3022 // string and possibly suffix after last match. It is possible for
3023 // all components to use two elements when encoded as two smis.
3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003025 bool matched = true;
3026 do {
3027 ASSERT(last_match_info_handle->HasFastElements());
3028 // Increase the capacity of the builder before entering local handle-scope,
3029 // so its internal buffer can safely allocate a new handle if it grows.
3030 builder.EnsureCapacity(parts_added_per_loop);
3031
Steve Block44f0eee2011-05-26 01:26:41 +01003032 HandleScope loop_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 int start, end;
3034 {
3035 AssertNoAllocation match_info_array_is_not_in_a_handle;
3036 FixedArray* match_info_array =
3037 FixedArray::cast(last_match_info_handle->elements());
3038
3039 ASSERT_EQ(capture_count * 2 + 2,
3040 RegExpImpl::GetLastCaptureCount(match_info_array));
3041 start = RegExpImpl::GetCapture(match_info_array, 0);
3042 end = RegExpImpl::GetCapture(match_info_array, 1);
3043 }
3044
3045 if (prev < start) {
3046 builder.AddSubjectSlice(prev, start);
3047 }
3048 compiled_replacement.Apply(&builder,
3049 start,
3050 end,
3051 last_match_info_handle);
3052 prev = end;
3053
3054 // Only continue checking for global regexps.
3055 if (!is_global) break;
3056
3057 // Continue from where the match ended, unless it was an empty match.
3058 int next = end;
3059 if (start == end) {
3060 next = end + 1;
3061 if (next > length) break;
3062 }
3063
3064 match = RegExpImpl::Exec(regexp_handle,
3065 subject_handle,
3066 next,
3067 last_match_info_handle);
3068 if (match.is_null()) {
3069 return Failure::Exception();
3070 }
3071 matched = !match->IsNull();
3072 } while (matched);
3073
3074 if (prev < length) {
3075 builder.AddSubjectSlice(prev, length);
3076 }
3077
3078 return *(builder.ToString());
3079}
3080
3081
Leon Clarkeac952652010-07-15 11:15:24 +01003082template <typename ResultSeqString>
John Reck59135872010-11-02 12:39:01 -07003083MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
Steve Block44f0eee2011-05-26 01:26:41 +01003084 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07003085 String* subject,
3086 JSRegExp* regexp,
3087 JSArray* last_match_info) {
Leon Clarkeac952652010-07-15 11:15:24 +01003088 ASSERT(subject->IsFlat());
3089
Steve Block44f0eee2011-05-26 01:26:41 +01003090 HandleScope handles(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01003091
3092 Handle<String> subject_handle(subject);
3093 Handle<JSRegExp> regexp_handle(regexp);
Ben Murdoch589d6972011-11-30 16:04:58 +00003094
3095 // Shortcut for simple non-regexp global replacements
3096 if (regexp_handle->GetFlags().is_global() &&
3097 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3098 Handle<String> empty_string_handle(HEAP->empty_string());
3099 if (subject_handle->HasOnlyAsciiChars()) {
3100 return StringReplaceStringWithString<SeqAsciiString>(
3101 isolate, subject_handle, regexp_handle, empty_string_handle);
3102 } else {
3103 return StringReplaceStringWithString<SeqTwoByteString>(
3104 isolate, subject_handle, regexp_handle, empty_string_handle);
3105 }
3106 }
3107
Leon Clarkeac952652010-07-15 11:15:24 +01003108 Handle<JSArray> last_match_info_handle(last_match_info);
3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3110 subject_handle,
3111 0,
3112 last_match_info_handle);
3113 if (match.is_null()) return Failure::Exception();
3114 if (match->IsNull()) return *subject_handle;
3115
3116 ASSERT(last_match_info_handle->HasFastElements());
3117
Leon Clarkeac952652010-07-15 11:15:24 +01003118 int start, end;
3119 {
3120 AssertNoAllocation match_info_array_is_not_in_a_handle;
3121 FixedArray* match_info_array =
3122 FixedArray::cast(last_match_info_handle->elements());
3123
3124 start = RegExpImpl::GetCapture(match_info_array, 0);
3125 end = RegExpImpl::GetCapture(match_info_array, 1);
3126 }
3127
Steve Block053d10c2011-06-13 19:13:29 +01003128 int length = subject_handle->length();
Leon Clarkeac952652010-07-15 11:15:24 +01003129 int new_length = length - (end - start);
3130 if (new_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003131 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01003132 }
3133 Handle<ResultSeqString> answer;
3134 if (ResultSeqString::kHasAsciiEncoding) {
Steve Block44f0eee2011-05-26 01:26:41 +01003135 answer = Handle<ResultSeqString>::cast(
3136 isolate->factory()->NewRawAsciiString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01003137 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003138 answer = Handle<ResultSeqString>::cast(
3139 isolate->factory()->NewRawTwoByteString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01003140 }
3141
3142 // If the regexp isn't global, only match once.
3143 if (!regexp_handle->GetFlags().is_global()) {
3144 if (start > 0) {
3145 String::WriteToFlat(*subject_handle,
3146 answer->GetChars(),
3147 0,
3148 start);
3149 }
3150 if (end < length) {
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + start,
3153 end,
3154 length);
3155 }
3156 return *answer;
3157 }
3158
3159 int prev = 0; // Index of end of last match.
3160 int next = 0; // Start of next search (prev unless last match was empty).
3161 int position = 0;
3162
3163 do {
3164 if (prev < start) {
3165 // Add substring subject[prev;start] to answer string.
3166 String::WriteToFlat(*subject_handle,
3167 answer->GetChars() + position,
3168 prev,
3169 start);
3170 position += start - prev;
3171 }
3172 prev = end;
3173 next = end;
3174 // Continue from where the match ended, unless it was an empty match.
3175 if (start == end) {
3176 next++;
3177 if (next > length) break;
3178 }
3179 match = RegExpImpl::Exec(regexp_handle,
3180 subject_handle,
3181 next,
3182 last_match_info_handle);
3183 if (match.is_null()) return Failure::Exception();
3184 if (match->IsNull()) break;
3185
3186 ASSERT(last_match_info_handle->HasFastElements());
Steve Block44f0eee2011-05-26 01:26:41 +01003187 HandleScope loop_scope(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01003188 {
3189 AssertNoAllocation match_info_array_is_not_in_a_handle;
3190 FixedArray* match_info_array =
3191 FixedArray::cast(last_match_info_handle->elements());
3192 start = RegExpImpl::GetCapture(match_info_array, 0);
3193 end = RegExpImpl::GetCapture(match_info_array, 1);
3194 }
3195 } while (true);
3196
3197 if (prev < length) {
3198 // Add substring subject[prev;length] to answer string.
3199 String::WriteToFlat(*subject_handle,
3200 answer->GetChars() + position,
3201 prev,
3202 length);
3203 position += length - prev;
3204 }
3205
3206 if (position == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003207 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01003208 }
3209
3210 // Shorten string and fill
3211 int string_size = ResultSeqString::SizeFor(position);
3212 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3213 int delta = allocated_string_size - string_size;
3214
3215 answer->set_length(position);
3216 if (delta == 0) return *answer;
3217
3218 Address end_of_string = answer->address() + string_size;
Steve Block44f0eee2011-05-26 01:26:41 +01003219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
3222 }
Leon Clarkeac952652010-07-15 11:15:24 +01003223
3224 return *answer;
3225}
3226
3227
Ben Murdoch8b112d22011-06-08 16:22:53 +01003228RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003229 ASSERT(args.length() == 4);
3230
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003231 CONVERT_ARG_CHECKED(String, subject, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00003232 if (!subject->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07003233 Object* flat_subject;
3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3235 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3236 return maybe_flat_subject;
3237 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003238 }
3239 subject = String::cast(flat_subject);
3240 }
3241
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003242 CONVERT_ARG_CHECKED(String, replacement, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003243 if (!replacement->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07003244 Object* flat_replacement;
3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3247 return maybe_flat_replacement;
3248 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003249 }
3250 replacement = String::cast(flat_replacement);
3251 }
3252
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00003255
3256 ASSERT(last_match_info->HasFastElements());
3257
Leon Clarkeac952652010-07-15 11:15:24 +01003258 if (replacement->length() == 0) {
3259 if (subject->HasOnlyAsciiChars()) {
3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
Steve Block44f0eee2011-05-26 01:26:41 +01003261 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01003262 } else {
3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
Steve Block44f0eee2011-05-26 01:26:41 +01003264 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01003265 }
3266 }
3267
Steve Block44f0eee2011-05-26 01:26:41 +01003268 return StringReplaceRegExpWithString(isolate,
3269 subject,
Steve Blocka7e24c12009-10-30 11:49:00 +00003270 regexp,
3271 replacement,
3272 last_match_info);
3273}
3274
3275
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003276Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3277 Handle<String> subject,
3278 Handle<String> search,
3279 Handle<String> replace,
3280 bool* found,
3281 int recursion_limit) {
3282 if (recursion_limit == 0) return Handle<String>::null();
3283 if (subject->IsConsString()) {
3284 ConsString* cons = ConsString::cast(*subject);
3285 Handle<String> first = Handle<String>(cons->first());
3286 Handle<String> second = Handle<String>(cons->second());
3287 Handle<String> new_first =
3288 StringReplaceOneCharWithString(isolate,
3289 first,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(new_first, second);
3295 if (new_first.is_null()) return new_first;
3296
3297 Handle<String> new_second =
3298 StringReplaceOneCharWithString(isolate,
3299 second,
3300 search,
3301 replace,
3302 found,
3303 recursion_limit - 1);
3304 if (*found) return isolate->factory()->NewConsString(first, new_second);
3305 if (new_second.is_null()) return new_second;
3306
3307 return subject;
3308 } else {
3309 int index = StringMatch(isolate, subject, search, 0);
3310 if (index == -1) return subject;
3311 *found = true;
3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3314 Handle<String> second =
3315 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3316 return isolate->factory()->NewConsString(cons1, second);
3317 }
3318}
3319
3320
3321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3322 ASSERT(args.length() == 3);
3323 HandleScope scope(isolate);
3324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
3327
3328 // If the cons string tree is too deep, we simply abort the recursion and
3329 // retry with a flattened subject string.
3330 const int kRecursionLimit = 0x1000;
3331 bool found = false;
3332 Handle<String> result =
3333 Runtime::StringReplaceOneCharWithString(isolate,
3334 subject,
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339 if (!result.is_null()) return *result;
3340 return *Runtime::StringReplaceOneCharWithString(isolate,
3341 FlattenGetString(subject),
3342 search,
3343 replace,
3344 &found,
3345 kRecursionLimit);
3346}
3347
3348
Steve Blocka7e24c12009-10-30 11:49:00 +00003349// Perform string match of pattern on subject, starting at start index.
3350// Caller must ensure that 0 <= start_index <= sub->length(),
Ben Murdochb0fe1622011-05-05 13:52:32 +01003351// and should check that pat->length() + start_index <= sub->length().
Steve Block44f0eee2011-05-26 01:26:41 +01003352int Runtime::StringMatch(Isolate* isolate,
3353 Handle<String> sub,
Steve Blocka7e24c12009-10-30 11:49:00 +00003354 Handle<String> pat,
3355 int start_index) {
3356 ASSERT(0 <= start_index);
3357 ASSERT(start_index <= sub->length());
3358
3359 int pattern_length = pat->length();
3360 if (pattern_length == 0) return start_index;
3361
3362 int subject_length = sub->length();
3363 if (start_index + pattern_length > subject_length) return -1;
3364
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003365 if (!sub->IsFlat()) FlattenString(sub);
3366 if (!pat->IsFlat()) FlattenString(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +00003367
3368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
Steve Block8defd9f2010-07-08 12:39:36 +01003369 // Extract flattened substrings of cons strings before determining asciiness.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003370 String::FlatContent seq_sub = sub->GetFlatContent();
3371 String::FlatContent seq_pat = pat->GetFlatContent();
Steve Block8defd9f2010-07-08 12:39:36 +01003372
Steve Blocka7e24c12009-10-30 11:49:00 +00003373 // dispatch on type of strings
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003374 if (seq_pat.IsAscii()) {
3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3376 if (seq_sub.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003377 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003378 seq_sub.ToAsciiVector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003379 pat_vector,
3380 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003381 }
Steve Block44f0eee2011-05-26 01:26:41 +01003382 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003383 seq_sub.ToUC16Vector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003384 pat_vector,
3385 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003386 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3388 if (seq_sub.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003389 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003390 seq_sub.ToAsciiVector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003391 pat_vector,
3392 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003393 }
Steve Block44f0eee2011-05-26 01:26:41 +01003394 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003395 seq_sub.ToUC16Vector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003396 pat_vector,
3397 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003398}
3399
3400
Ben Murdoch8b112d22011-06-08 16:22:53 +01003401RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01003402 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00003403 ASSERT(args.length() == 3);
3404
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003407
3408 Object* index = args[2];
3409 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003411
3412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
Steve Block44f0eee2011-05-26 01:26:41 +01003413 int position =
3414 Runtime::StringMatch(isolate, sub, pat, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003415 return Smi::FromInt(position);
3416}
3417
3418
Andrei Popescu402d9372010-02-26 13:31:12 +00003419template <typename schar, typename pchar>
Steve Block59151502010-09-22 15:07:15 +01003420static int StringMatchBackwards(Vector<const schar> subject,
3421 Vector<const pchar> pattern,
Andrei Popescu402d9372010-02-26 13:31:12 +00003422 int idx) {
Steve Block59151502010-09-22 15:07:15 +01003423 int pattern_length = pattern.length();
3424 ASSERT(pattern_length >= 1);
3425 ASSERT(idx + pattern_length <= subject.length());
Andrei Popescu402d9372010-02-26 13:31:12 +00003426
3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
Steve Block59151502010-09-22 15:07:15 +01003428 for (int i = 0; i < pattern_length; i++) {
3429 uc16 c = pattern[i];
Andrei Popescu402d9372010-02-26 13:31:12 +00003430 if (c > String::kMaxAsciiCharCode) {
3431 return -1;
3432 }
3433 }
3434 }
3435
Steve Block59151502010-09-22 15:07:15 +01003436 pchar pattern_first_char = pattern[0];
Andrei Popescu402d9372010-02-26 13:31:12 +00003437 for (int i = idx; i >= 0; i--) {
Steve Block59151502010-09-22 15:07:15 +01003438 if (subject[i] != pattern_first_char) continue;
Andrei Popescu402d9372010-02-26 13:31:12 +00003439 int j = 1;
Steve Block59151502010-09-22 15:07:15 +01003440 while (j < pattern_length) {
3441 if (pattern[j] != subject[i+j]) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003442 break;
3443 }
3444 j++;
3445 }
Steve Block59151502010-09-22 15:07:15 +01003446 if (j == pattern_length) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003447 return i;
3448 }
3449 }
3450 return -1;
3451}
3452
Ben Murdoch8b112d22011-06-08 16:22:53 +01003453RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01003454 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00003455 ASSERT(args.length() == 3);
3456
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00003459
Steve Blocka7e24c12009-10-30 11:49:00 +00003460 Object* index = args[2];
Steve Blocka7e24c12009-10-30 11:49:00 +00003461 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003463
Andrei Popescu402d9372010-02-26 13:31:12 +00003464 uint32_t pat_length = pat->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00003465 uint32_t sub_length = sub->length();
3466
Andrei Popescu402d9372010-02-26 13:31:12 +00003467 if (start_index + pat_length > sub_length) {
3468 start_index = sub_length - pat_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00003469 }
3470
Andrei Popescu402d9372010-02-26 13:31:12 +00003471 if (pat_length == 0) {
3472 return Smi::FromInt(start_index);
3473 }
3474
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003475 if (!sub->IsFlat()) FlattenString(sub);
3476 if (!pat->IsFlat()) FlattenString(pat);
Andrei Popescu402d9372010-02-26 13:31:12 +00003477
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003478 int position = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00003479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3480
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003481 String::FlatContent sub_content = sub->GetFlatContent();
3482 String::FlatContent pat_content = pat->GetFlatContent();
Andrei Popescu402d9372010-02-26 13:31:12 +00003483
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003484 if (pat_content.IsAscii()) {
3485 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3486 if (sub_content.IsAscii()) {
3487 position = StringMatchBackwards(sub_content.ToAsciiVector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003488 pat_vector,
3489 start_index);
3490 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003491 position = StringMatchBackwards(sub_content.ToUC16Vector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003492 pat_vector,
3493 start_index);
3494 }
3495 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3497 if (sub_content.IsAscii()) {
3498 position = StringMatchBackwards(sub_content.ToAsciiVector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003499 pat_vector,
3500 start_index);
3501 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003502 position = StringMatchBackwards(sub_content.ToUC16Vector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003503 pat_vector,
3504 start_index);
3505 }
3506 }
3507
3508 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +00003509}
3510
3511
Ben Murdoch8b112d22011-06-08 16:22:53 +01003512RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003513 NoHandleAllocation ha;
3514 ASSERT(args.length() == 2);
3515
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003516 CONVERT_ARG_CHECKED(String, str1, 0);
3517 CONVERT_ARG_CHECKED(String, str2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003518
3519 if (str1 == str2) return Smi::FromInt(0); // Equal.
3520 int str1_length = str1->length();
3521 int str2_length = str2->length();
3522
3523 // Decide trivial cases without flattening.
3524 if (str1_length == 0) {
3525 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3526 return Smi::FromInt(-str2_length);
3527 } else {
3528 if (str2_length == 0) return Smi::FromInt(str1_length);
3529 }
3530
3531 int end = str1_length < str2_length ? str1_length : str2_length;
3532
3533 // No need to flatten if we are going to find the answer on the first
3534 // character. At this point we know there is at least one character
3535 // in each string, due to the trivial case handling above.
3536 int d = str1->Get(0) - str2->Get(0);
3537 if (d != 0) return Smi::FromInt(d);
3538
Steve Block6ded16b2010-05-10 14:33:55 +01003539 str1->TryFlatten();
3540 str2->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003541
Steve Block44f0eee2011-05-26 01:26:41 +01003542 StringInputBuffer& buf1 =
3543 *isolate->runtime_state()->string_locale_compare_buf1();
3544 StringInputBuffer& buf2 =
3545 *isolate->runtime_state()->string_locale_compare_buf2();
Steve Blocka7e24c12009-10-30 11:49:00 +00003546
3547 buf1.Reset(str1);
3548 buf2.Reset(str2);
3549
3550 for (int i = 0; i < end; i++) {
3551 uint16_t char1 = buf1.GetNext();
3552 uint16_t char2 = buf2.GetNext();
3553 if (char1 != char2) return Smi::FromInt(char1 - char2);
3554 }
3555
3556 return Smi::FromInt(str1_length - str2_length);
3557}
3558
3559
Ben Murdoch8b112d22011-06-08 16:22:53 +01003560RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 3);
3563
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003564 CONVERT_ARG_CHECKED(String, value, 0);
Steve Blockd0582a62009-12-15 09:54:21 +00003565 int start, end;
3566 // We have a fast integer-only case here to avoid a conversion to double in
3567 // the common case where from and to are Smis.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003568 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3569 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3570 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3571 start = from_number;
3572 end = to_number;
Steve Blockd0582a62009-12-15 09:54:21 +00003573 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
Steve Blockd0582a62009-12-15 09:54:21 +00003576 start = FastD2I(from_number);
3577 end = FastD2I(to_number);
3578 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003579 RUNTIME_ASSERT(end >= start);
3580 RUNTIME_ASSERT(start >= 0);
3581 RUNTIME_ASSERT(end <= value->length());
Steve Block44f0eee2011-05-26 01:26:41 +01003582 isolate->counters()->sub_string_runtime()->Increment();
Steve Blockd0582a62009-12-15 09:54:21 +00003583 return value->SubString(start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +00003584}
3585
3586
Ben Murdoch8b112d22011-06-08 16:22:53 +01003587RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003588 ASSERT_EQ(3, args.length());
3589
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00003593 HandleScope handles;
3594
3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3596
3597 if (match.is_null()) {
3598 return Failure::Exception();
3599 }
3600 if (match->IsNull()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003601 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003602 }
3603 int length = subject->length();
3604
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003605 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +00003606 ZoneList<int> offsets(8);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003607 int start;
3608 int end;
Steve Blocka7e24c12009-10-30 11:49:00 +00003609 do {
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 {
3611 AssertNoAllocation no_alloc;
3612 FixedArray* elements = FixedArray::cast(regexp_info->elements());
3613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3615 }
3616 offsets.Add(start);
3617 offsets.Add(end);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003618 if (start == end) if (++end > length) break;
3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00003620 if (match.is_null()) {
3621 return Failure::Exception();
3622 }
3623 } while (!match->IsNull());
3624 int matches = offsets.length() / 2;
Steve Block44f0eee2011-05-26 01:26:41 +01003625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003626 Handle<String> substring = isolate->factory()->
3627 NewSubString(subject, offsets.at(0), offsets.at(1));
3628 elements->set(0, *substring);
3629 for (int i = 1; i < matches ; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003630 int from = offsets.at(i * 2);
3631 int to = offsets.at(i * 2 + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003632 Handle<String> substring = isolate->factory()->
3633 NewProperSubString(subject, from, to);
3634 elements->set(i, *substring);
Steve Blocka7e24c12009-10-30 11:49:00 +00003635 }
Steve Block44f0eee2011-05-26 01:26:41 +01003636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003637 result->set_length(Smi::FromInt(matches));
3638 return *result;
3639}
3640
3641
Steve Block6ded16b2010-05-10 14:33:55 +01003642// Two smis before and after the match, for very long strings.
3643const int kMaxBuilderEntriesPerRegExpMatch = 5;
3644
3645
3646static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3647 Handle<JSArray> last_match_info,
3648 int match_start,
3649 int match_end) {
3650 // Fill last_match_info with a single capture.
3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3652 AssertNoAllocation no_gc;
3653 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3654 RegExpImpl::SetLastCaptureCount(elements, 2);
3655 RegExpImpl::SetLastInput(elements, *subject);
3656 RegExpImpl::SetLastSubject(elements, *subject);
3657 RegExpImpl::SetCapture(elements, 0, match_start);
3658 RegExpImpl::SetCapture(elements, 1, match_end);
3659}
3660
3661
Ben Murdochf87a2032010-10-22 12:50:53 +01003662template <typename SubjectChar, typename PatternChar>
Steve Block44f0eee2011-05-26 01:26:41 +01003663static bool SearchStringMultiple(Isolate* isolate,
3664 Vector<const SubjectChar> subject,
Ben Murdochf87a2032010-10-22 12:50:53 +01003665 Vector<const PatternChar> pattern,
3666 String* pattern_string,
Steve Block6ded16b2010-05-10 14:33:55 +01003667 FixedArrayBuilder* builder,
3668 int* match_pos) {
3669 int pos = *match_pos;
3670 int subject_length = subject.length();
Ben Murdochf87a2032010-10-22 12:50:53 +01003671 int pattern_length = pattern.length();
Steve Block6ded16b2010-05-10 14:33:55 +01003672 int max_search_start = subject_length - pattern_length;
Steve Block44f0eee2011-05-26 01:26:41 +01003673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
Ben Murdochf87a2032010-10-22 12:50:53 +01003674 while (pos <= max_search_start) {
3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3676 *match_pos = pos;
3677 return false;
3678 }
3679 // Position of end of previous match.
3680 int match_end = pos + pattern_length;
3681 int new_pos = search.Search(subject, match_end);
3682 if (new_pos >= 0) {
3683 // A match.
3684 if (new_pos > match_end) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 new_pos);
Steve Block6ded16b2010-05-10 14:33:55 +01003688 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003689 pos = new_pos;
3690 builder->Add(pattern_string);
3691 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003692 break;
Ben Murdochf87a2032010-10-22 12:50:53 +01003693 }
Steve Block6ded16b2010-05-10 14:33:55 +01003694 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003695
Steve Block6ded16b2010-05-10 14:33:55 +01003696 if (pos < max_search_start) {
3697 ReplacementStringBuilder::AddSubjectSlice(builder,
3698 pos + pattern_length,
3699 subject_length);
3700 }
3701 *match_pos = pos;
3702 return true;
3703}
3704
3705
Steve Block44f0eee2011-05-26 01:26:41 +01003706static bool SearchStringMultiple(Isolate* isolate,
3707 Handle<String> subject,
Steve Block6ded16b2010-05-10 14:33:55 +01003708 Handle<String> pattern,
3709 Handle<JSArray> last_match_info,
3710 FixedArrayBuilder* builder) {
3711 ASSERT(subject->IsFlat());
3712 ASSERT(pattern->IsFlat());
Steve Block6ded16b2010-05-10 14:33:55 +01003713
3714 // Treating as if a previous match was before first character.
3715 int match_pos = -pattern->length();
3716
3717 for (;;) { // Break when search complete.
3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3719 AssertNoAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003720 String::FlatContent subject_content = subject->GetFlatContent();
3721 String::FlatContent pattern_content = pattern->GetFlatContent();
3722 if (subject_content.IsAscii()) {
3723 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3724 if (pattern_content.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003727 pattern_content.ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003728 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003729 builder,
3730 &match_pos)) break;
3731 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003734 pattern_content.ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003735 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003736 builder,
3737 &match_pos)) break;
3738 }
3739 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3741 if (pattern_content.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003744 pattern_content.ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003745 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003746 builder,
3747 &match_pos)) break;
3748 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003749 if (SearchStringMultiple(isolate,
3750 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003751 pattern_content.ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003752 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003753 builder,
3754 &match_pos)) break;
3755 }
3756 }
3757 }
3758
3759 if (match_pos >= 0) {
3760 SetLastMatchInfoNoCaptures(subject,
3761 last_match_info,
3762 match_pos,
3763 match_pos + pattern->length());
3764 return true;
3765 }
3766 return false; // No matches at all.
3767}
3768
3769
3770static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003771 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003772 Handle<String> subject,
3773 Handle<JSRegExp> regexp,
3774 Handle<JSArray> last_match_array,
3775 FixedArrayBuilder* builder) {
3776 ASSERT(subject->IsFlat());
3777 int match_start = -1;
3778 int match_end = 0;
3779 int pos = 0;
3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3782
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003783 OffsetsVector registers(required_registers, isolate);
Steve Block791712a2010-08-27 10:21:07 +01003784 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003785 int subject_length = subject->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003786 bool first = true;
Steve Block6ded16b2010-05-10 14:33:55 +01003787
3788 for (;;) { // Break on failure, return on exception.
3789 RegExpImpl::IrregexpResult result =
3790 RegExpImpl::IrregexpExecOnce(regexp,
3791 subject,
3792 pos,
3793 register_vector);
3794 if (result == RegExpImpl::RE_SUCCESS) {
3795 match_start = register_vector[0];
3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3797 if (match_end < match_start) {
3798 ReplacementStringBuilder::AddSubjectSlice(builder,
3799 match_end,
3800 match_start);
3801 }
3802 match_end = register_vector[1];
Steve Block44f0eee2011-05-26 01:26:41 +01003803 HandleScope loop_scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003804 if (!first) {
3805 builder->Add(*isolate->factory()->NewProperSubString(subject,
3806 match_start,
3807 match_end));
3808 } else {
3809 builder->Add(*isolate->factory()->NewSubString(subject,
3810 match_start,
3811 match_end));
3812 }
Steve Block6ded16b2010-05-10 14:33:55 +01003813 if (match_start != match_end) {
3814 pos = match_end;
3815 } else {
3816 pos = match_end + 1;
3817 if (pos > subject_length) break;
3818 }
3819 } else if (result == RegExpImpl::RE_FAILURE) {
3820 break;
3821 } else {
3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3823 return result;
3824 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003825 first = false;
Steve Block6ded16b2010-05-10 14:33:55 +01003826 }
3827
3828 if (match_start >= 0) {
3829 if (match_end < subject_length) {
3830 ReplacementStringBuilder::AddSubjectSlice(builder,
3831 match_end,
3832 subject_length);
3833 }
3834 SetLastMatchInfoNoCaptures(subject,
3835 last_match_array,
3836 match_start,
3837 match_end);
3838 return RegExpImpl::RE_SUCCESS;
3839 } else {
3840 return RegExpImpl::RE_FAILURE; // No matches at all.
3841 }
3842}
3843
3844
3845static RegExpImpl::IrregexpResult SearchRegExpMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003846 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003847 Handle<String> subject,
3848 Handle<JSRegExp> regexp,
3849 Handle<JSArray> last_match_array,
3850 FixedArrayBuilder* builder) {
3851
3852 ASSERT(subject->IsFlat());
3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3855
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003856 OffsetsVector registers(required_registers, isolate);
Steve Block791712a2010-08-27 10:21:07 +01003857 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003858
3859 RegExpImpl::IrregexpResult result =
3860 RegExpImpl::IrregexpExecOnce(regexp,
3861 subject,
3862 0,
3863 register_vector);
3864
3865 int capture_count = regexp->CaptureCount();
3866 int subject_length = subject->length();
3867
3868 // Position to search from.
3869 int pos = 0;
3870 // End of previous match. Differs from pos if match was empty.
3871 int match_end = 0;
3872 if (result == RegExpImpl::RE_SUCCESS) {
3873 // Need to keep a copy of the previous match for creating last_match_info
3874 // at the end, so we have two vectors that we swap between.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003875 OffsetsVector registers2(required_registers, isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003876 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003877 bool first = true;
Steve Block6ded16b2010-05-10 14:33:55 +01003878 do {
3879 int match_start = register_vector[0];
3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3881 if (match_end < match_start) {
3882 ReplacementStringBuilder::AddSubjectSlice(builder,
3883 match_end,
3884 match_start);
3885 }
3886 match_end = register_vector[1];
3887
3888 {
3889 // Avoid accumulating new handles inside loop.
Steve Block44f0eee2011-05-26 01:26:41 +01003890 HandleScope temp_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003891 // Arguments array to replace function is match, captures, index and
3892 // subject, i.e., 3 + capture count in total.
Steve Block44f0eee2011-05-26 01:26:41 +01003893 Handle<FixedArray> elements =
3894 isolate->factory()->NewFixedArray(3 + capture_count);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003895 Handle<String> match;
3896 if (!first) {
3897 match = isolate->factory()->NewProperSubString(subject,
3898 match_start,
3899 match_end);
3900 } else {
3901 match = isolate->factory()->NewSubString(subject,
3902 match_start,
3903 match_end);
3904 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003905 elements->set(0, *match);
Steve Block6ded16b2010-05-10 14:33:55 +01003906 for (int i = 1; i <= capture_count; i++) {
3907 int start = register_vector[i * 2];
3908 if (start >= 0) {
3909 int end = register_vector[i * 2 + 1];
3910 ASSERT(start <= end);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003911 Handle<String> substring;
3912 if (!first) {
3913 substring = isolate->factory()->NewProperSubString(subject,
3914 start,
3915 end);
3916 } else {
3917 substring = isolate->factory()->NewSubString(subject, start, end);
3918 }
Steve Block6ded16b2010-05-10 14:33:55 +01003919 elements->set(i, *substring);
3920 } else {
3921 ASSERT(register_vector[i * 2 + 1] < 0);
Steve Block44f0eee2011-05-26 01:26:41 +01003922 elements->set(i, isolate->heap()->undefined_value());
Steve Block6ded16b2010-05-10 14:33:55 +01003923 }
3924 }
3925 elements->set(capture_count + 1, Smi::FromInt(match_start));
3926 elements->set(capture_count + 2, *subject);
Steve Block44f0eee2011-05-26 01:26:41 +01003927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
Steve Block6ded16b2010-05-10 14:33:55 +01003928 }
3929 // Swap register vectors, so the last successful match is in
3930 // prev_register_vector.
Steve Block791712a2010-08-27 10:21:07 +01003931 Vector<int32_t> tmp = prev_register_vector;
Steve Block6ded16b2010-05-10 14:33:55 +01003932 prev_register_vector = register_vector;
3933 register_vector = tmp;
3934
3935 if (match_end > match_start) {
3936 pos = match_end;
3937 } else {
3938 pos = match_end + 1;
3939 if (pos > subject_length) {
3940 break;
3941 }
3942 }
3943
3944 result = RegExpImpl::IrregexpExecOnce(regexp,
3945 subject,
3946 pos,
3947 register_vector);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003948 first = false;
Steve Block6ded16b2010-05-10 14:33:55 +01003949 } while (result == RegExpImpl::RE_SUCCESS);
3950
3951 if (result != RegExpImpl::RE_EXCEPTION) {
3952 // Finished matching, with at least one match.
3953 if (match_end < subject_length) {
3954 ReplacementStringBuilder::AddSubjectSlice(builder,
3955 match_end,
3956 subject_length);
3957 }
3958
3959 int last_match_capture_count = (capture_count + 1) * 2;
3960 int last_match_array_size =
3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3962 last_match_array->EnsureSize(last_match_array_size);
3963 AssertNoAllocation no_gc;
3964 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3966 RegExpImpl::SetLastSubject(elements, *subject);
3967 RegExpImpl::SetLastInput(elements, *subject);
3968 for (int i = 0; i < last_match_capture_count; i++) {
3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3970 }
3971 return RegExpImpl::RE_SUCCESS;
3972 }
3973 }
3974 // No matches at all, return failure or exception result directly.
3975 return result;
3976}
3977
3978
Ben Murdoch8b112d22011-06-08 16:22:53 +01003979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
Steve Block6ded16b2010-05-10 14:33:55 +01003980 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01003981 HandleScope handles(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003982
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003984 if (!subject->IsFlat()) FlattenString(subject);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
Steve Block6ded16b2010-05-10 14:33:55 +01003988
3989 ASSERT(last_match_info->HasFastElements());
3990 ASSERT(regexp->GetFlags().is_global());
3991 Handle<FixedArray> result_elements;
3992 if (result_array->HasFastElements()) {
3993 result_elements =
3994 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003995 }
3996 if (result_elements.is_null() || result_elements->length() < 16) {
Steve Block44f0eee2011-05-26 01:26:41 +01003997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
Steve Block6ded16b2010-05-10 14:33:55 +01003998 }
3999 FixedArrayBuilder builder(result_elements);
4000
4001 if (regexp->TypeTag() == JSRegExp::ATOM) {
4002 Handle<String> pattern(
4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004004 ASSERT(pattern->IsFlat());
Steve Block44f0eee2011-05-26 01:26:41 +01004005 if (SearchStringMultiple(isolate, subject, pattern,
4006 last_match_info, &builder)) {
Steve Block6ded16b2010-05-10 14:33:55 +01004007 return *builder.ToJSArray(result_array);
4008 }
Steve Block44f0eee2011-05-26 01:26:41 +01004009 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004010 }
4011
4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4013
4014 RegExpImpl::IrregexpResult result;
4015 if (regexp->CaptureCount() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004016 result = SearchRegExpNoCaptureMultiple(isolate,
4017 subject,
Steve Block6ded16b2010-05-10 14:33:55 +01004018 regexp,
4019 last_match_info,
4020 &builder);
4021 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004022 result = SearchRegExpMultiple(isolate,
4023 subject,
4024 regexp,
4025 last_match_info,
4026 &builder);
Steve Block6ded16b2010-05-10 14:33:55 +01004027 }
4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
Steve Block44f0eee2011-05-26 01:26:41 +01004029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4031 return Failure::Exception();
4032}
4033
4034
Ben Murdoch8b112d22011-06-08 16:22:53 +01004035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004036 NoHandleAllocation ha;
4037 ASSERT(args.length() == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004038 CONVERT_SMI_ARG_CHECKED(radix, 1);
4039 RUNTIME_ASSERT(2 <= radix && radix <= 36);
Steve Blocka7e24c12009-10-30 11:49:00 +00004040
4041 // Fast case where the result is a one character string.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004042 if (args[0]->IsSmi()) {
4043 int value = args.smi_at(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004044 if (value >= 0 && value < radix) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004045 // Character array used for conversion.
4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
Steve Block44f0eee2011-05-26 01:26:41 +01004047 return isolate->heap()->
4048 LookupSingleCharacterStringFromCode(kCharTable[value]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004049 }
4050 }
4051
4052 // Slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004053 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004054 if (isnan(value)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004055 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004056 }
4057 if (isinf(value)) {
4058 if (value < 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004059 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004060 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004061 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004062 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004063 char* str = DoubleToRadixCString(value, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01004064 MaybeObject* result =
4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004066 DeleteArray(str);
4067 return result;
4068}
4069
4070
Ben Murdoch8b112d22011-06-08 16:22:53 +01004071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004072 NoHandleAllocation ha;
4073 ASSERT(args.length() == 2);
4074
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004075 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004076 if (isnan(value)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004077 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004078 }
4079 if (isinf(value)) {
4080 if (value < 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004081 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004082 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004083 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004084 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004086 int f = FastD2I(f_number);
4087 RUNTIME_ASSERT(f >= 0);
4088 char* str = DoubleToFixedCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004089 MaybeObject* res =
4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004091 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004092 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004093}
4094
4095
Ben Murdoch8b112d22011-06-08 16:22:53 +01004096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004097 NoHandleAllocation ha;
4098 ASSERT(args.length() == 2);
4099
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004100 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004101 if (isnan(value)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004102 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004103 }
4104 if (isinf(value)) {
4105 if (value < 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004106 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004107 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004108 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004109 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004111 int f = FastD2I(f_number);
4112 RUNTIME_ASSERT(f >= -1 && f <= 20);
4113 char* str = DoubleToExponentialCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004114 MaybeObject* res =
4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004116 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004117 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004118}
4119
4120
Ben Murdoch8b112d22011-06-08 16:22:53 +01004121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004122 NoHandleAllocation ha;
4123 ASSERT(args.length() == 2);
4124
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004125 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004126 if (isnan(value)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004127 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004128 }
4129 if (isinf(value)) {
4130 if (value < 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004131 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004132 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004133 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004134 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004136 int f = FastD2I(f_number);
4137 RUNTIME_ASSERT(f >= 1 && f <= 21);
4138 char* str = DoubleToPrecisionCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004139 MaybeObject* res =
4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004141 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004142 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004143}
4144
4145
4146// Returns a single character string where first character equals
4147// string->Get(index).
4148static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4149 if (index < static_cast<uint32_t>(string->length())) {
Steve Block6ded16b2010-05-10 14:33:55 +01004150 string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004151 return LookupSingleCharacterStringFromCode(
4152 string->Get(index));
4153 }
4154 return Execution::CharAt(string, index);
4155}
4156
4157
Steve Block44f0eee2011-05-26 01:26:41 +01004158MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4159 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004160 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004161 // Handle [] indexing on Strings
4162 if (object->IsString()) {
4163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4164 if (!result->IsUndefined()) return *result;
4165 }
4166
4167 // Handle [] indexing on String objects
4168 if (object->IsStringObjectWithCharacterAt(index)) {
4169 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4170 Handle<Object> result =
4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4172 if (!result->IsUndefined()) return *result;
4173 }
4174
4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004176 return object->GetPrototype()->GetElement(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004177 }
4178
4179 return object->GetElement(index);
4180}
4181
4182
Steve Block44f0eee2011-05-26 01:26:41 +01004183MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4184 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004185 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004186 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004187
4188 if (object->IsUndefined() || object->IsNull()) {
4189 Handle<Object> args[2] = { key, object };
4190 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01004191 isolate->factory()->NewTypeError("non_object_property_load",
4192 HandleVector(args, 2));
4193 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00004194 }
4195
4196 // Check if the given key is an array index.
4197 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004198 if (key->ToArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004199 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004200 }
4201
4202 // Convert the key to a string - possibly by calling back into JavaScript.
4203 Handle<String> name;
4204 if (key->IsString()) {
4205 name = Handle<String>::cast(key);
4206 } else {
4207 bool has_pending_exception = false;
4208 Handle<Object> converted =
4209 Execution::ToString(key, &has_pending_exception);
4210 if (has_pending_exception) return Failure::Exception();
4211 name = Handle<String>::cast(converted);
4212 }
4213
4214 // Check if the name is trivially convertible to an index and get
4215 // the element if so.
4216 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004217 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004218 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004219 return object->GetProperty(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +00004220 }
4221}
4222
4223
Ben Murdoch8b112d22011-06-08 16:22:53 +01004224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004225 NoHandleAllocation ha;
4226 ASSERT(args.length() == 2);
4227
4228 Handle<Object> object = args.at<Object>(0);
4229 Handle<Object> key = args.at<Object>(1);
4230
Steve Block44f0eee2011-05-26 01:26:41 +01004231 return Runtime::GetObjectProperty(isolate, object, key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004232}
4233
4234
Steve Blocka7e24c12009-10-30 11:49:00 +00004235// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004236RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 2);
4239
4240 // Fast cases for getting named properties of the receiver JSObject
4241 // itself.
4242 //
4243 // The global proxy objects has to be excluded since LocalLookup on
4244 // the global proxy object can return a valid result even though the
4245 // global proxy object never has properties. This is the case
4246 // because the global proxy object forwards everything to its hidden
4247 // prototype including local lookups.
4248 //
4249 // Additionally, we need to make sure that we do not cache results
4250 // for objects that require access checks.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004251 if (args[0]->IsJSObject()) {
4252 if (!args[0]->IsJSGlobalProxy() &&
4253 !args[0]->IsAccessCheckNeeded() &&
4254 args[1]->IsString()) {
4255 JSObject* receiver = JSObject::cast(args[0]);
4256 String* key = String::cast(args[1]);
4257 if (receiver->HasFastProperties()) {
4258 // Attempt to use lookup cache.
4259 Map* receiver_map = receiver->map();
4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4262 if (offset != -1) {
4263 Object* value = receiver->FastPropertyAt(offset);
4264 return value->IsTheHole()
4265 ? isolate->heap()->undefined_value()
4266 : value;
4267 }
4268 // Lookup cache miss. Perform lookup and update the cache if
4269 // appropriate.
4270 LookupResult result(isolate);
4271 receiver->LocalLookup(key, &result);
4272 if (result.IsFound() && result.type() == FIELD) {
4273 int offset = result.GetFieldIndex();
4274 keyed_lookup_cache->Update(receiver_map, key, offset);
4275 return receiver->FastPropertyAt(offset);
4276 }
4277 } else {
4278 // Attempt dictionary lookup.
4279 StringDictionary* dictionary = receiver->property_dictionary();
4280 int entry = dictionary->FindEntry(key);
4281 if ((entry != StringDictionary::kNotFound) &&
4282 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4283 Object* value = dictionary->ValueAt(entry);
4284 if (!receiver->IsGlobalObject()) return value;
4285 value = JSGlobalPropertyCell::cast(value)->value();
4286 if (!value->IsTheHole()) return value;
4287 // If value is the hole do the general lookup.
4288 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004289 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4291 // JSObject without a string key. If the key is a Smi, check for a
4292 // definite out-of-bounds access to elements, which is a strong indicator
4293 // that subsequent accesses will also call the runtime. Proactively
4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4295 // doubles for those future calls in the case that the elements would
4296 // become FAST_DOUBLE_ELEMENTS.
4297 Handle<JSObject> js_object(args.at<JSObject>(0));
4298 ElementsKind elements_kind = js_object->GetElementsKind();
4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4300 elements_kind == FAST_DOUBLE_ELEMENTS) {
4301 FixedArrayBase* elements = js_object->elements();
4302 if (args.at<Smi>(1)->value() >= elements->length()) {
4303 MaybeObject* maybe_object = TransitionElements(js_object,
4304 FAST_ELEMENTS,
4305 isolate);
4306 if (maybe_object->IsFailure()) return maybe_object;
4307 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004308 }
4309 }
Leon Clarkee46be812010-01-19 14:06:41 +00004310 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4311 // Fast case for string indexing using [] with a smi index.
Steve Block44f0eee2011-05-26 01:26:41 +01004312 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004313 Handle<String> str = args.at<String>(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004314 int index = args.smi_at(1);
Steve Block1e0659c2011-05-24 12:43:12 +01004315 if (index >= 0 && index < str->length()) {
4316 Handle<Object> result = GetCharAt(str, index);
4317 return *result;
4318 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004319 }
4320
4321 // Fall back to GetObjectProperty.
Steve Block44f0eee2011-05-26 01:26:41 +01004322 return Runtime::GetObjectProperty(isolate,
4323 args.at<Object>(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00004324 args.at<Object>(1));
4325}
4326
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004327
4328static bool IsValidAccessor(Handle<Object> obj) {
4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4330}
4331
4332
Steve Block1e0659c2011-05-24 12:43:12 +01004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4b - define a new accessor property.
4336// Steps 9c & 12 - replace an existing data property with an accessor property.
4337// Step 12 - update an existing accessor property with an accessor or generic
4338// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00004340 ASSERT(args.length() == 5);
Steve Block44f0eee2011-05-26 01:26:41 +01004341 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Ben Murdoch85b71792012-04-11 18:30:58 +01004343 RUNTIME_ASSERT(!obj->IsNull());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4346 RUNTIME_ASSERT(IsValidAccessor(getter));
4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4348 RUNTIME_ASSERT(IsValidAccessor(setter));
4349 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
4350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Ben Murdoch85b71792012-04-11 18:30:58 +01004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004352
4353 bool fast = obj->HasFastProperties();
4354 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4355 if (fast) JSObject::TransformToFastProperties(obj, 0);
4356 return isolate->heap()->undefined_value();
Andrei Popescu31002712010-02-23 13:46:05 +00004357}
4358
Steve Block1e0659c2011-05-24 12:43:12 +01004359// Implements part of 8.12.9 DefineOwnProperty.
4360// There are 3 cases that lead here:
4361// Step 4a - define a new data property.
4362// Steps 9b & 12 - replace an existing accessor property with a data property.
4363// Step 12 - update an existing data property with a data or generic
4364// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004365RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00004366 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01004367 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004368 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4369 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4370 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
4371 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
Andrei Popescu31002712010-02-23 13:46:05 +00004372 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004373 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4374
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004375 LookupResult result(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004376 js_object->LocalLookupRealNamedProperty(*name, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00004377
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004378 // Special case for callback properties.
4379 if (result.IsFound() && result.type() == CALLBACKS) {
4380 Object* callback = result.GetCallbackObject();
4381 // To be compatible with Safari we do not change the value on API objects
4382 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4383 // the value.
4384 if (callback->IsAccessorInfo()) {
4385 return isolate->heap()->undefined_value();
4386 }
4387 // Avoid redefining foreign callback as data property, just use the stored
4388 // setter to update the value instead.
4389 // TODO(mstarzinger): So far this only works if property attributes don't
4390 // change, this should be fixed once we cleanup the underlying code.
4391 if (callback->IsForeign() && result.GetAttributes() == attr) {
4392 return js_object->SetPropertyWithCallback(callback,
4393 *name,
4394 *obj_value,
4395 result.holder(),
4396 kStrictMode);
4397 }
Steve Block44f0eee2011-05-26 01:26:41 +01004398 }
4399
Andrei Popescu31002712010-02-23 13:46:05 +00004400 // Take special care when attributes are different and there is already
4401 // a property. For simplicity we normalize the property which enables us
4402 // to not worry about changing the instance_descriptor and creating a new
4403 // map. The current version of SetObjectProperty does not handle attributes
4404 // correctly in the case where a property is a field and is reset with
4405 // new attributes.
Ben Murdochb0fe1622011-05-05 13:52:32 +01004406 if (result.IsProperty() &&
4407 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
Andrei Popescu31002712010-02-23 13:46:05 +00004408 // New attributes - normalize to avoid writing to instance descriptor
Steve Block1e0659c2011-05-24 12:43:12 +01004409 if (js_object->IsJSGlobalProxy()) {
4410 // Since the result is a property, the prototype will exist so
4411 // we don't have to check for null.
4412 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
4413 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004414 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00004415 // Use IgnoreAttributes version since a readonly property may be
4416 // overridden and SetProperty does not allow this.
Ben Murdoch086aeea2011-05-13 15:57:08 +01004417 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4418 *obj_value,
4419 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00004420 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004421
Steve Block44f0eee2011-05-26 01:26:41 +01004422 return Runtime::ForceSetObjectProperty(isolate,
4423 js_object,
4424 name,
4425 obj_value,
4426 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00004427}
4428
4429
Steve Block44f0eee2011-05-26 01:26:41 +01004430MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4431 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004432 Handle<Object> key,
4433 Handle<Object> value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004434 PropertyAttributes attr,
4435 StrictModeFlag strict_mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004436 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
Steve Block44f0eee2011-05-26 01:26:41 +01004437 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004438
4439 if (object->IsUndefined() || object->IsNull()) {
4440 Handle<Object> args[2] = { key, object };
4441 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01004442 isolate->factory()->NewTypeError("non_object_property_store",
4443 HandleVector(args, 2));
4444 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00004445 }
4446
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004447 if (object->IsJSProxy()) {
4448 bool has_pending_exception = false;
4449 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4450 if (has_pending_exception) return Failure::Exception();
4451 return JSProxy::cast(*object)->SetProperty(
4452 String::cast(*name), *value, attr, strict_mode);
4453 }
4454
Steve Blocka7e24c12009-10-30 11:49:00 +00004455 // If the object isn't a JavaScript object, we ignore the store.
4456 if (!object->IsJSObject()) return *value;
4457
4458 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4459
4460 // Check if the given key is an array index.
4461 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004462 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
4470 if (js_object->IsStringObjectWithCharacterAt(index)) {
4471 return *value;
4472 }
4473
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004474 Handle<Object> result = JSObject::SetElement(
4475 js_object, index, value, attr, strict_mode, set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004476 if (result.is_null()) return Failure::Exception();
4477 return *value;
4478 }
4479
4480 if (key->IsString()) {
4481 Handle<Object> result;
4482 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004483 result = JSObject::SetElement(
4484 js_object, index, value, attr, strict_mode, set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004485 } else {
4486 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01004487 key_string->TryFlatten();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004488 result = JSReceiver::SetProperty(
4489 js_object, key_string, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004490 }
4491 if (result.is_null()) return Failure::Exception();
4492 return *value;
4493 }
4494
4495 // Call-back into JavaScript to convert the key to a string.
4496 bool has_pending_exception = false;
4497 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4498 if (has_pending_exception) return Failure::Exception();
4499 Handle<String> name = Handle<String>::cast(converted);
4500
4501 if (name->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004502 return js_object->SetElement(
4503 index, *value, attr, strict_mode, true, set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004504 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004505 return js_object->SetProperty(*name, *value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004506 }
4507}
4508
4509
Steve Block44f0eee2011-05-26 01:26:41 +01004510MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4511 Handle<JSObject> js_object,
John Reck59135872010-11-02 12:39:01 -07004512 Handle<Object> key,
4513 Handle<Object> value,
4514 PropertyAttributes attr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004515 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004516
4517 // Check if the given key is an array index.
4518 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004519 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004520 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4521 // of a string using [] notation. We need to support this too in
4522 // JavaScript.
4523 // In the case of a String object we just need to redirect the assignment to
4524 // the underlying string if the index is in range. Since the underlying
4525 // string does nothing with the assignment then we can ignore such
4526 // assignments.
4527 if (js_object->IsStringObjectWithCharacterAt(index)) {
4528 return *value;
4529 }
4530
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004531 return js_object->SetElement(
4532 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
Steve Blocka7e24c12009-10-30 11:49:00 +00004533 }
4534
4535 if (key->IsString()) {
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004537 return js_object->SetElement(
4538 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
Steve Blocka7e24c12009-10-30 11:49:00 +00004539 } else {
4540 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01004541 key_string->TryFlatten();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004542 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4543 *value,
4544 attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004545 }
4546 }
4547
4548 // Call-back into JavaScript to convert the key to a string.
4549 bool has_pending_exception = false;
4550 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4551 if (has_pending_exception) return Failure::Exception();
4552 Handle<String> name = Handle<String>::cast(converted);
4553
4554 if (name->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004555 return js_object->SetElement(
4556 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
Steve Blocka7e24c12009-10-30 11:49:00 +00004557 } else {
Ben Murdoch086aeea2011-05-13 15:57:08 +01004558 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004559 }
4560}
4561
4562
Steve Block44f0eee2011-05-26 01:26:41 +01004563MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004564 Handle<JSReceiver> receiver,
John Reck59135872010-11-02 12:39:01 -07004565 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004566 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004567
4568 // Check if the given key is an array index.
4569 uint32_t index;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004570 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004571 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4572 // characters of a string using [] notation. In the case of a
4573 // String object we just need to redirect the deletion to the
4574 // underlying string if the index is in range. Since the
4575 // underlying string does nothing with the deletion, we can ignore
4576 // such deletions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004577 if (receiver->IsStringObjectWithCharacterAt(index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004578 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004579 }
4580
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004581 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004582 }
4583
4584 Handle<String> key_string;
4585 if (key->IsString()) {
4586 key_string = Handle<String>::cast(key);
4587 } else {
4588 // Call-back into JavaScript to convert the key to a string.
4589 bool has_pending_exception = false;
4590 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4591 if (has_pending_exception) return Failure::Exception();
4592 key_string = Handle<String>::cast(converted);
4593 }
4594
Steve Block6ded16b2010-05-10 14:33:55 +01004595 key_string->TryFlatten();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004596 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004597}
4598
4599
Ben Murdoch8b112d22011-06-08 16:22:53 +01004600RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004601 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004602 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00004603
4604 Handle<Object> object = args.at<Object>(0);
4605 Handle<Object> key = args.at<Object>(1);
4606 Handle<Object> value = args.at<Object>(2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004607 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004608 RUNTIME_ASSERT(
4609 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004610 // Compute attributes.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004611 PropertyAttributes attributes =
4612 static_cast<PropertyAttributes>(unchecked_attributes);
4613
4614 StrictModeFlag strict_mode = kNonStrictMode;
4615 if (args.length() == 5) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004616 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
4617 strict_mode = strict_mode_flag;
Steve Blocka7e24c12009-10-30 11:49:00 +00004618 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004619
Steve Block44f0eee2011-05-26 01:26:41 +01004620 return Runtime::SetObjectProperty(isolate,
4621 object,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004622 key,
4623 value,
4624 attributes,
4625 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004626}
4627
4628
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004629RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4630 NoHandleAllocation ha;
4631 RUNTIME_ASSERT(args.length() == 1);
4632 Handle<Object> object = args.at<Object>(0);
4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4634}
4635
4636
4637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_ELEMENTS, isolate);
4642}
4643
4644
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004645// Set the native flag on the function.
Ben Murdoch257744e2011-11-30 15:57:28 +00004646// This is used to decide if we should transform null and undefined
4647// into the global object when doing call and apply.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004649 NoHandleAllocation ha;
4650 RUNTIME_ASSERT(args.length() == 1);
4651
4652 Handle<Object> object = args.at<Object>(0);
4653
4654 if (object->IsJSFunction()) {
4655 JSFunction* func = JSFunction::cast(*object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004656 func->shared()->set_native(true);
Ben Murdoch257744e2011-11-30 15:57:28 +00004657 }
4658 return isolate->heap()->undefined_value();
4659}
4660
4661
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004662RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4663 RUNTIME_ASSERT(args.length() == 5);
4664 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
4665 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4666 Handle<Object> value = args.at<Object>(2);
4667 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
4668 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4669 HandleScope scope;
4670
4671 Object* raw_boilerplate_object = literals->get(literal_index);
4672 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4673#if DEBUG
4674 ElementsKind elements_kind = object->GetElementsKind();
4675#endif
4676 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4677 // Smis should never trigger transitions.
4678 ASSERT(!value->IsSmi());
4679
4680 if (value->IsNumber()) {
4681 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4682 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4683 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
4684 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4685 FixedDoubleArray* double_array =
4686 FixedDoubleArray::cast(object->elements());
4687 HeapNumber* number = HeapNumber::cast(*value);
4688 double_array->set(store_index, number->Number());
4689 } else {
4690 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4691 elements_kind == FAST_DOUBLE_ELEMENTS);
4692 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4693 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
4694 FixedArray* object_array =
4695 FixedArray::cast(object->elements());
4696 object_array->set(store_index, *value);
4697 }
4698 return *object;
4699}
4700
4701
Steve Blocka7e24c12009-10-30 11:49:00 +00004702// Set a local property, even if it is READ_ONLY. If the property does not
4703// exist, it will be added with attributes NONE.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004704RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004705 NoHandleAllocation ha;
4706 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004707 CONVERT_ARG_CHECKED(JSObject, object, 0);
4708 CONVERT_ARG_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004709 // Compute attributes.
4710 PropertyAttributes attributes = NONE;
4711 if (args.length() == 4) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004712 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00004713 // Only attribute bits should be set.
4714 RUNTIME_ASSERT(
4715 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4716 attributes = static_cast<PropertyAttributes>(unchecked_value);
4717 }
4718
4719 return object->
Ben Murdoch086aeea2011-05-13 15:57:08 +01004720 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004721}
4722
4723
Ben Murdoch8b112d22011-06-08 16:22:53 +01004724RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004725 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004726 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00004727
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004728 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4729 CONVERT_ARG_CHECKED(String, key, 1);
4730 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
4731 return object->DeleteProperty(key, (strict_mode == kStrictMode)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004732 ? JSReceiver::STRICT_DELETION
4733 : JSReceiver::NORMAL_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004734}
4735
4736
Steve Block44f0eee2011-05-26 01:26:41 +01004737static Object* HasLocalPropertyImplementation(Isolate* isolate,
4738 Handle<JSObject> object,
Steve Blocka7e24c12009-10-30 11:49:00 +00004739 Handle<String> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004740 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004741 // Handle hidden prototypes. If there's a hidden prototype above this thing
4742 // then we have to check it for properties, because they are supposed to
4743 // look like they are on this object.
4744 Handle<Object> proto(object->GetPrototype());
4745 if (proto->IsJSObject() &&
4746 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004747 return HasLocalPropertyImplementation(isolate,
4748 Handle<JSObject>::cast(proto),
4749 key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004750 }
Steve Block44f0eee2011-05-26 01:26:41 +01004751 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004752}
4753
4754
Ben Murdoch8b112d22011-06-08 16:22:53 +01004755RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004756 NoHandleAllocation ha;
4757 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004758 CONVERT_ARG_CHECKED(String, key, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004759
Ben Murdoch257744e2011-11-30 15:57:28 +00004760 uint32_t index;
4761 const bool key_is_array_index = key->AsArrayIndex(&index);
4762
Steve Blocka7e24c12009-10-30 11:49:00 +00004763 Object* obj = args[0];
4764 // Only JS objects can have properties.
4765 if (obj->IsJSObject()) {
4766 JSObject* object = JSObject::cast(obj);
Ben Murdoch257744e2011-11-30 15:57:28 +00004767 // Fast case: either the key is a real named property or it is not
4768 // an array index and there are no interceptors or hidden
4769 // prototypes.
Steve Block44f0eee2011-05-26 01:26:41 +01004770 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
Ben Murdoch257744e2011-11-30 15:57:28 +00004771 Map* map = object->map();
4772 if (!key_is_array_index &&
4773 !map->has_named_interceptor() &&
4774 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4775 return isolate->heap()->false_value();
4776 }
4777 // Slow case.
Steve Block44f0eee2011-05-26 01:26:41 +01004778 HandleScope scope(isolate);
4779 return HasLocalPropertyImplementation(isolate,
4780 Handle<JSObject>(object),
Steve Blocka7e24c12009-10-30 11:49:00 +00004781 Handle<String>(key));
Ben Murdoch257744e2011-11-30 15:57:28 +00004782 } else if (obj->IsString() && key_is_array_index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004783 // Well, there is one exception: Handle [] on strings.
Ben Murdoch257744e2011-11-30 15:57:28 +00004784 String* string = String::cast(obj);
4785 if (index < static_cast<uint32_t>(string->length())) {
4786 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004787 }
4788 }
Steve Block44f0eee2011-05-26 01:26:41 +01004789 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004790}
4791
4792
Ben Murdoch8b112d22011-06-08 16:22:53 +01004793RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004794 NoHandleAllocation na;
4795 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004796 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4797 CONVERT_ARG_CHECKED(String, key, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004798
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004799 bool result = receiver->HasProperty(key);
4800 if (isolate->has_pending_exception()) return Failure::Exception();
4801 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004802}
4803
4804
Ben Murdoch8b112d22011-06-08 16:22:53 +01004805RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004806 NoHandleAllocation na;
4807 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004808 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4809 CONVERT_SMI_ARG_CHECKED(index, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004810
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004811 bool result = receiver->HasElement(index);
4812 if (isolate->has_pending_exception()) return Failure::Exception();
4813 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004814}
4815
4816
Ben Murdoch8b112d22011-06-08 16:22:53 +01004817RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004818 NoHandleAllocation ha;
4819 ASSERT(args.length() == 2);
4820
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004821 CONVERT_ARG_CHECKED(JSObject, object, 0);
4822 CONVERT_ARG_CHECKED(String, key, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004823
4824 uint32_t index;
4825 if (key->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004826 JSObject::LocalElementType type = object->HasLocalElement(index);
4827 switch (type) {
4828 case JSObject::UNDEFINED_ELEMENT:
4829 case JSObject::STRING_CHARACTER_ELEMENT:
4830 return isolate->heap()->false_value();
4831 case JSObject::INTERCEPTED_ELEMENT:
4832 case JSObject::FAST_ELEMENT:
4833 return isolate->heap()->true_value();
4834 case JSObject::DICTIONARY_ELEMENT: {
4835 if (object->IsJSGlobalProxy()) {
4836 Object* proto = object->GetPrototype();
4837 if (proto->IsNull()) {
4838 return isolate->heap()->false_value();
4839 }
4840 ASSERT(proto->IsJSGlobalObject());
4841 object = JSObject::cast(proto);
4842 }
4843 FixedArray* elements = FixedArray::cast(object->elements());
4844 SeededNumberDictionary* dictionary = NULL;
4845 if (elements->map() ==
4846 isolate->heap()->non_strict_arguments_elements_map()) {
4847 dictionary = SeededNumberDictionary::cast(elements->get(1));
4848 } else {
4849 dictionary = SeededNumberDictionary::cast(elements);
4850 }
4851 int entry = dictionary->FindEntry(index);
4852 ASSERT(entry != SeededNumberDictionary::kNotFound);
4853 PropertyDetails details = dictionary->DetailsAt(entry);
4854 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4855 }
4856 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004857 }
4858
4859 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
Steve Block44f0eee2011-05-26 01:26:41 +01004860 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004861}
4862
4863
Ben Murdoch8b112d22011-06-08 16:22:53 +01004864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004865 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004866 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
4868 bool threw = false;
4869 Handle<JSArray> result = GetKeysFor(object, &threw);
4870 if (threw) return Failure::Exception();
4871 return *result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004872}
4873
4874
4875// Returns either a FixedArray as Runtime_GetPropertyNames,
4876// or, if the given object has an enum cache that contains
4877// all enumerable properties of the object and its prototypes
4878// have none, the map of the object. This is used to speed up
4879// the check for deletions during a for-in.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004880RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004881 ASSERT(args.length() == 1);
4882
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004883 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004884
4885 if (raw_object->IsSimpleEnum()) return raw_object->map();
4886
Steve Block44f0eee2011-05-26 01:26:41 +01004887 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004888 Handle<JSReceiver> object(raw_object);
4889 bool threw = false;
4890 Handle<FixedArray> content =
4891 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4892 if (threw) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00004893
4894 // Test again, since cache may have been built by preceding call.
4895 if (object->IsSimpleEnum()) return object->map();
4896
4897 return *content;
4898}
4899
4900
Leon Clarkee46be812010-01-19 14:06:41 +00004901// Find the length of the prototype chain that is to to handled as one. If a
4902// prototype object is hidden it is to be viewed as part of the the object it
4903// is prototype for.
4904static int LocalPrototypeChainLength(JSObject* obj) {
4905 int count = 1;
4906 Object* proto = obj->GetPrototype();
4907 while (proto->IsJSObject() &&
4908 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4909 count++;
4910 proto = JSObject::cast(proto)->GetPrototype();
4911 }
4912 return count;
4913}
4914
4915
4916// Return the names of the local named properties.
4917// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004918RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004919 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004920 ASSERT(args.length() == 1);
4921 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004922 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004923 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004924 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00004925
4926 // Skip the global proxy as it has no properties and always delegates to the
4927 // real global object.
4928 if (obj->IsJSGlobalProxy()) {
Leon Clarke4515c472010-02-03 11:58:03 +00004929 // Only collect names if access is permitted.
4930 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004931 !isolate->MayNamedAccess(*obj,
4932 isolate->heap()->undefined_value(),
4933 v8::ACCESS_KEYS)) {
4934 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4935 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00004936 }
Leon Clarkee46be812010-01-19 14:06:41 +00004937 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4938 }
4939
4940 // Find the number of objects making up this.
4941 int length = LocalPrototypeChainLength(*obj);
4942
4943 // Find the number of local properties for each of the objects.
Steve Block6ded16b2010-05-10 14:33:55 +01004944 ScopedVector<int> local_property_count(length);
Leon Clarkee46be812010-01-19 14:06:41 +00004945 int total_property_count = 0;
4946 Handle<JSObject> jsproto = obj;
4947 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00004948 // Only collect names if access is permitted.
4949 if (jsproto->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004950 !isolate->MayNamedAccess(*jsproto,
4951 isolate->heap()->undefined_value(),
4952 v8::ACCESS_KEYS)) {
4953 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4954 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00004955 }
Leon Clarkee46be812010-01-19 14:06:41 +00004956 int n;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004957 n = jsproto->NumberOfLocalProperties();
Leon Clarkee46be812010-01-19 14:06:41 +00004958 local_property_count[i] = n;
4959 total_property_count += n;
4960 if (i < length - 1) {
4961 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4962 }
4963 }
4964
4965 // Allocate an array with storage for all the property names.
Steve Block44f0eee2011-05-26 01:26:41 +01004966 Handle<FixedArray> names =
4967 isolate->factory()->NewFixedArray(total_property_count);
Leon Clarkee46be812010-01-19 14:06:41 +00004968
4969 // Get the property names.
4970 jsproto = obj;
4971 int proto_with_hidden_properties = 0;
Ben Murdoch6d7cb002011-08-04 19:25:22 +01004972 int next_copy_index = 0;
Leon Clarkee46be812010-01-19 14:06:41 +00004973 for (int i = 0; i < length; i++) {
Ben Murdoch6d7cb002011-08-04 19:25:22 +01004974 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4975 next_copy_index += local_property_count[i];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004976 if (jsproto->HasHiddenProperties()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004977 proto_with_hidden_properties++;
4978 }
4979 if (i < length - 1) {
4980 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4981 }
4982 }
4983
4984 // Filter out name of hidden propeties object.
4985 if (proto_with_hidden_properties > 0) {
4986 Handle<FixedArray> old_names = names;
Steve Block44f0eee2011-05-26 01:26:41 +01004987 names = isolate->factory()->NewFixedArray(
Leon Clarkee46be812010-01-19 14:06:41 +00004988 names->length() - proto_with_hidden_properties);
4989 int dest_pos = 0;
4990 for (int i = 0; i < total_property_count; i++) {
4991 Object* name = old_names->get(i);
Steve Block44f0eee2011-05-26 01:26:41 +01004992 if (name == isolate->heap()->hidden_symbol()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004993 continue;
4994 }
4995 names->set(dest_pos++, name);
4996 }
4997 }
4998
Steve Block44f0eee2011-05-26 01:26:41 +01004999 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00005000}
5001
5002
5003// Return the names of the local indexed properties.
5004// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005006 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005007 ASSERT(args.length() == 1);
5008 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005009 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005010 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005011 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00005012
5013 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01005014 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
Leon Clarkee46be812010-01-19 14:06:41 +00005015 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01005016 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00005017}
5018
5019
5020// Return information on whether an object has a named or indexed interceptor.
5021// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01005023 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005024 ASSERT(args.length() == 1);
5025 if (!args[0]->IsJSObject()) {
5026 return Smi::FromInt(0);
5027 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005028 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00005029
5030 int result = 0;
5031 if (obj->HasNamedInterceptor()) result |= 2;
5032 if (obj->HasIndexedInterceptor()) result |= 1;
5033
5034 return Smi::FromInt(result);
5035}
5036
5037
5038// Return property names from named interceptor.
5039// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005040RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005041 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005042 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005043 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00005044
5045 if (obj->HasNamedInterceptor()) {
5046 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5047 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5048 }
Steve Block44f0eee2011-05-26 01:26:41 +01005049 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005050}
5051
5052
5053// Return element names from indexed interceptor.
5054// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005055RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005056 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005057 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00005059
5060 if (obj->HasIndexedInterceptor()) {
5061 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5062 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5063 }
Steve Block44f0eee2011-05-26 01:26:41 +01005064 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005065}
5066
5067
Ben Murdoch8b112d22011-06-08 16:22:53 +01005068RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005069 ASSERT_EQ(args.length(), 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005070 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005071 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005072 Handle<JSObject> object(raw_object);
Steve Block1e0659c2011-05-24 12:43:12 +01005073
5074 if (object->IsJSGlobalProxy()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005075 // Do access checks before going to the global object.
5076 if (object->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01005077 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005078 v8::ACCESS_KEYS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01005079 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5080 return *isolate->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005081 }
5082
Steve Block1e0659c2011-05-24 12:43:12 +01005083 Handle<Object> proto(object->GetPrototype());
5084 // If proxy is detached we simply return an empty array.
Steve Block44f0eee2011-05-26 01:26:41 +01005085 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
Steve Block1e0659c2011-05-24 12:43:12 +01005086 object = Handle<JSObject>::cast(proto);
5087 }
5088
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005089 bool threw = false;
5090 Handle<FixedArray> contents =
5091 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5092 if (threw) return Failure::Exception();
5093
Steve Blocka7e24c12009-10-30 11:49:00 +00005094 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5095 // property array and since the result is mutable we have to create
5096 // a fresh clone on each invocation.
5097 int length = contents->length();
Steve Block44f0eee2011-05-26 01:26:41 +01005098 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005099 for (int i = 0; i < length; i++) {
5100 Object* entry = contents->get(i);
5101 if (entry->IsString()) {
5102 copy->set(i, entry);
5103 } else {
5104 ASSERT(entry->IsNumber());
Steve Block44f0eee2011-05-26 01:26:41 +01005105 HandleScope scope(isolate);
5106 Handle<Object> entry_handle(entry, isolate);
5107 Handle<Object> entry_str =
5108 isolate->factory()->NumberToString(entry_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +00005109 copy->set(i, *entry_str);
5110 }
5111 }
Steve Block44f0eee2011-05-26 01:26:41 +01005112 return *isolate->factory()->NewJSArrayWithElements(copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00005113}
5114
5115
Ben Murdoch8b112d22011-06-08 16:22:53 +01005116RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005117 NoHandleAllocation ha;
5118 ASSERT(args.length() == 1);
5119
5120 // Compute the frame holding the arguments.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005121 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005122 it.AdvanceToArgumentsFrame();
5123 JavaScriptFrame* frame = it.frame();
5124
5125 // Get the actual number of provided arguments.
Steve Block44f0eee2011-05-26 01:26:41 +01005126 const uint32_t n = frame->ComputeParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00005127
5128 // Try to convert the key to an index. If successful and within
5129 // index return the the argument from the frame.
5130 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005131 if (args[0]->ToArrayIndex(&index) && index < n) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005132 return frame->GetParameter(index);
5133 }
5134
5135 // Convert the key to a string.
Steve Block44f0eee2011-05-26 01:26:41 +01005136 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005137 bool exception = false;
5138 Handle<Object> converted =
5139 Execution::ToString(args.at<Object>(0), &exception);
5140 if (exception) return Failure::Exception();
5141 Handle<String> key = Handle<String>::cast(converted);
5142
5143 // Try to convert the string key into an array index.
5144 if (key->AsArrayIndex(&index)) {
5145 if (index < n) {
5146 return frame->GetParameter(index);
5147 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005148 return isolate->initial_object_prototype()->GetElement(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00005149 }
5150 }
5151
5152 // Handle special arguments properties.
Steve Block44f0eee2011-05-26 01:26:41 +01005153 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5154 if (key->Equals(isolate->heap()->callee_symbol())) {
5155 Object* function = frame->function();
5156 if (function->IsJSFunction() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005157 !JSFunction::cast(function)->shared()->is_classic_mode()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005158 return isolate->Throw(*isolate->factory()->NewTypeError(
5159 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5160 }
5161 return function;
5162 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005163
5164 // Lookup in the initial Object.prototype object.
Steve Block44f0eee2011-05-26 01:26:41 +01005165 return isolate->initial_object_prototype()->GetProperty(*key);
Steve Blocka7e24c12009-10-30 11:49:00 +00005166}
5167
5168
Ben Murdoch8b112d22011-06-08 16:22:53 +01005169RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005170 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005171 Object* object = args[0];
5172 return (object->IsJSObject() && !object->IsGlobalObject())
5173 ? JSObject::cast(object)->TransformToFastProperties(0)
5174 : object;
Steve Blocka7e24c12009-10-30 11:49:00 +00005175}
5176
5177
Ben Murdoch8b112d22011-06-08 16:22:53 +01005178RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005179 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005180 Object* obj = args[0];
5181 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5182 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5183 : obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00005184}
5185
5186
Ben Murdoch8b112d22011-06-08 16:22:53 +01005187RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005188 NoHandleAllocation ha;
5189 ASSERT(args.length() == 1);
5190
5191 return args[0]->ToBoolean();
5192}
5193
5194
5195// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5196// Possible optimizations: put the type string into the oddballs.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005197RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005198 NoHandleAllocation ha;
5199
5200 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01005201 if (obj->IsNumber()) return isolate->heap()->number_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005202 HeapObject* heap_obj = HeapObject::cast(obj);
5203
5204 // typeof an undetectable object is 'undefined'
Steve Block44f0eee2011-05-26 01:26:41 +01005205 if (heap_obj->map()->is_undetectable()) {
5206 return isolate->heap()->undefined_symbol();
5207 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005208
5209 InstanceType instance_type = heap_obj->map()->instance_type();
5210 if (instance_type < FIRST_NONSTRING_TYPE) {
Steve Block44f0eee2011-05-26 01:26:41 +01005211 return isolate->heap()->string_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005212 }
5213
5214 switch (instance_type) {
5215 case ODDBALL_TYPE:
5216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005217 return isolate->heap()->boolean_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005218 }
5219 if (heap_obj->IsNull()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005220 return FLAG_harmony_typeof
5221 ? isolate->heap()->null_symbol()
5222 : isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005223 }
5224 ASSERT(heap_obj->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01005225 return isolate->heap()->undefined_symbol();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005226 case JS_FUNCTION_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00005227 case JS_FUNCTION_PROXY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01005228 return isolate->heap()->function_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005229 default:
5230 // For any kind of object not handled above, the spec rule for
5231 // host objects gives that it is okay to return "object"
Steve Block44f0eee2011-05-26 01:26:41 +01005232 return isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005233 }
5234}
5235
5236
Steve Block6ded16b2010-05-10 14:33:55 +01005237static bool AreDigits(const char*s, int from, int to) {
5238 for (int i = from; i < to; i++) {
5239 if (s[i] < '0' || s[i] > '9') return false;
5240 }
5241
5242 return true;
5243}
5244
5245
5246static int ParseDecimalInteger(const char*s, int from, int to) {
5247 ASSERT(to - from < 10); // Overflow is not possible.
5248 ASSERT(from < to);
5249 int d = s[from] - '0';
5250
5251 for (int i = from + 1; i < to; i++) {
5252 d = 10 * d + (s[i] - '0');
5253 }
5254
5255 return d;
5256}
5257
5258
Ben Murdoch8b112d22011-06-08 16:22:53 +01005259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005260 NoHandleAllocation ha;
5261 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005262 CONVERT_ARG_CHECKED(String, subject, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01005263 subject->TryFlatten();
5264
5265 // Fast case: short integer or some sorts of junk values.
5266 int len = subject->length();
5267 if (subject->IsSeqAsciiString()) {
5268 if (len == 0) return Smi::FromInt(0);
5269
5270 char const* data = SeqAsciiString::cast(subject)->GetChars();
5271 bool minus = (data[0] == '-');
5272 int start_pos = (minus ? 1 : 0);
5273
5274 if (start_pos == len) {
Steve Block44f0eee2011-05-26 01:26:41 +01005275 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005276 } else if (data[start_pos] > '9') {
5277 // Fast check for a junk value. A valid string may start from a
5278 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5279 // the 'I' character ('Infinity'). All of that have codes not greater than
5280 // '9' except 'I'.
5281 if (data[start_pos] != 'I') {
Steve Block44f0eee2011-05-26 01:26:41 +01005282 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005283 }
5284 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5285 // The maximal/minimal smi has 10 digits. If the string has less digits we
5286 // know it will fit into the smi-data type.
5287 int d = ParseDecimalInteger(data, start_pos, len);
5288 if (minus) {
Steve Block44f0eee2011-05-26 01:26:41 +01005289 if (d == 0) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005290 d = -d;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005291 } else if (!subject->HasHashCode() &&
5292 len <= String::kMaxArrayIndexSize &&
5293 (len == 1 || data[0] != '0')) {
5294 // String hash is not calculated yet but all the data are present.
5295 // Update the hash field to speed up sequential convertions.
Iain Merrick9ac36c92010-09-13 15:29:50 +01005296 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005297#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005298 subject->Hash(); // Force hash calculation.
5299 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5300 static_cast<int>(hash));
5301#endif
5302 subject->set_hash_field(hash);
Steve Block6ded16b2010-05-10 14:33:55 +01005303 }
5304 return Smi::FromInt(d);
5305 }
5306 }
5307
5308 // Slower case.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005309 return isolate->heap()->NumberFromDouble(
5310 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
Steve Blocka7e24c12009-10-30 11:49:00 +00005311}
5312
5313
Ben Murdoch8b112d22011-06-08 16:22:53 +01005314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005315 NoHandleAllocation ha;
5316 ASSERT(args.length() == 1);
5317
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005318 CONVERT_ARG_CHECKED(JSArray, codes, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00005319 int length = Smi::cast(codes->length())->value();
5320
5321 // Check if the string can be ASCII.
5322 int i;
5323 for (i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07005324 Object* element;
5325 { MaybeObject* maybe_element = codes->GetElement(i);
5326 // We probably can't get an exception here, but just in order to enforce
5327 // the checking of inputs in the runtime calls we check here.
5328 if (!maybe_element->ToObject(&element)) return maybe_element;
5329 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005330 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5331 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5332 break;
5333 }
5334
John Reck59135872010-11-02 12:39:01 -07005335 MaybeObject* maybe_object = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00005336 if (i == length) { // The string is ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01005337 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005338 } else { // The string is not ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01005339 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005340 }
5341
John Reck59135872010-11-02 12:39:01 -07005342 Object* object = NULL;
5343 if (!maybe_object->ToObject(&object)) return maybe_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00005344 String* result = String::cast(object);
5345 for (int i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07005346 Object* element;
5347 { MaybeObject* maybe_element = codes->GetElement(i);
5348 if (!maybe_element->ToObject(&element)) return maybe_element;
5349 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005350 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5351 result->Set(i, chr & 0xffff);
5352 }
5353 return result;
5354}
5355
5356
5357// kNotEscaped is generated by the following:
5358//
5359// #!/bin/perl
5360// for (my $i = 0; $i < 256; $i++) {
5361// print "\n" if $i % 16 == 0;
5362// my $c = chr($i);
5363// my $escaped = 1;
5364// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5365// print $escaped ? "0, " : "1, ";
5366// }
5367
5368
5369static bool IsNotEscaped(uint16_t character) {
5370 // Only for 8 bit characters, the rest are always escaped (in a different way)
5371 ASSERT(character < 256);
5372 static const char kNotEscaped[256] = {
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5379 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 };
5390 return kNotEscaped[character] != 0;
5391}
5392
5393
Ben Murdoch8b112d22011-06-08 16:22:53 +01005394RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005395 const char hex_chars[] = "0123456789ABCDEF";
5396 NoHandleAllocation ha;
5397 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005398 CONVERT_ARG_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00005399
Steve Block6ded16b2010-05-10 14:33:55 +01005400 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005401
5402 int escaped_length = 0;
5403 int length = source->length();
5404 {
Steve Block44f0eee2011-05-26 01:26:41 +01005405 Access<StringInputBuffer> buffer(
5406 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005407 buffer->Reset(source);
5408 while (buffer->has_more()) {
5409 uint16_t character = buffer->GetNext();
5410 if (character >= 256) {
5411 escaped_length += 6;
5412 } else if (IsNotEscaped(character)) {
5413 escaped_length++;
5414 } else {
5415 escaped_length += 3;
5416 }
Steve Block3ce2e202009-11-05 08:53:23 +00005417 // We don't allow strings that are longer than a maximal length.
Leon Clarkee46be812010-01-19 14:06:41 +00005418 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
Steve Block3ce2e202009-11-05 08:53:23 +00005419 if (escaped_length > String::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +01005420 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00005421 return Failure::OutOfMemoryException();
5422 }
5423 }
5424 }
5425 // No length change implies no change. Return original string if no change.
5426 if (escaped_length == length) {
5427 return source;
5428 }
John Reck59135872010-11-02 12:39:01 -07005429 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01005430 { MaybeObject* maybe_o =
5431 isolate->heap()->AllocateRawAsciiString(escaped_length);
John Reck59135872010-11-02 12:39:01 -07005432 if (!maybe_o->ToObject(&o)) return maybe_o;
5433 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005434 String* destination = String::cast(o);
5435 int dest_position = 0;
5436
Steve Block44f0eee2011-05-26 01:26:41 +01005437 Access<StringInputBuffer> buffer(
5438 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005439 buffer->Rewind();
5440 while (buffer->has_more()) {
5441 uint16_t chr = buffer->GetNext();
5442 if (chr >= 256) {
5443 destination->Set(dest_position, '%');
5444 destination->Set(dest_position+1, 'u');
5445 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5446 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5447 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5448 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
5449 dest_position += 6;
5450 } else if (IsNotEscaped(chr)) {
5451 destination->Set(dest_position, chr);
5452 dest_position++;
5453 } else {
5454 destination->Set(dest_position, '%');
5455 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5456 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
5457 dest_position += 3;
5458 }
5459 }
5460 return destination;
5461}
5462
5463
5464static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5465 static const signed char kHexValue['g'] = {
5466 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5467 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5470 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5472 -1, 10, 11, 12, 13, 14, 15 };
5473
5474 if (character1 > 'f') return -1;
5475 int hi = kHexValue[character1];
5476 if (hi == -1) return -1;
5477 if (character2 > 'f') return -1;
5478 int lo = kHexValue[character2];
5479 if (lo == -1) return -1;
5480 return (hi << 4) + lo;
5481}
5482
5483
5484static inline int Unescape(String* source,
5485 int i,
5486 int length,
5487 int* step) {
5488 uint16_t character = source->Get(i);
5489 int32_t hi = 0;
5490 int32_t lo = 0;
5491 if (character == '%' &&
5492 i <= length - 6 &&
5493 source->Get(i + 1) == 'u' &&
5494 (hi = TwoDigitHex(source->Get(i + 2),
5495 source->Get(i + 3))) != -1 &&
5496 (lo = TwoDigitHex(source->Get(i + 4),
5497 source->Get(i + 5))) != -1) {
5498 *step = 6;
5499 return (hi << 8) + lo;
5500 } else if (character == '%' &&
5501 i <= length - 3 &&
5502 (lo = TwoDigitHex(source->Get(i + 1),
5503 source->Get(i + 2))) != -1) {
5504 *step = 3;
5505 return lo;
5506 } else {
5507 *step = 1;
5508 return character;
5509 }
5510}
5511
5512
Ben Murdoch8b112d22011-06-08 16:22:53 +01005513RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005514 NoHandleAllocation ha;
5515 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005516 CONVERT_ARG_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00005517
Steve Block6ded16b2010-05-10 14:33:55 +01005518 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005519
5520 bool ascii = true;
5521 int length = source->length();
5522
5523 int unescaped_length = 0;
5524 for (int i = 0; i < length; unescaped_length++) {
5525 int step;
5526 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
5527 ascii = false;
5528 }
5529 i += step;
5530 }
5531
5532 // No length change implies no change. Return original string if no change.
5533 if (unescaped_length == length)
5534 return source;
5535
John Reck59135872010-11-02 12:39:01 -07005536 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01005537 { MaybeObject* maybe_o =
5538 ascii ?
5539 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5540 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
John Reck59135872010-11-02 12:39:01 -07005541 if (!maybe_o->ToObject(&o)) return maybe_o;
5542 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005543 String* destination = String::cast(o);
5544
5545 int dest_position = 0;
5546 for (int i = 0; i < length; dest_position++) {
5547 int step;
5548 destination->Set(dest_position, Unescape(source, i, length, &step));
5549 i += step;
5550 }
5551 return destination;
5552}
5553
5554
Ben Murdochb0fe1622011-05-05 13:52:32 +01005555static const unsigned int kQuoteTableLength = 128u;
5556
5557static const int kJsonQuotesCharactersPerEntry = 8;
5558static const char* const JsonQuotes =
5559 "\\u0000 \\u0001 \\u0002 \\u0003 "
5560 "\\u0004 \\u0005 \\u0006 \\u0007 "
5561 "\\b \\t \\n \\u000b "
5562 "\\f \\r \\u000e \\u000f "
5563 "\\u0010 \\u0011 \\u0012 \\u0013 "
5564 "\\u0014 \\u0015 \\u0016 \\u0017 "
5565 "\\u0018 \\u0019 \\u001a \\u001b "
5566 "\\u001c \\u001d \\u001e \\u001f "
5567 " ! \\\" # "
5568 "$ % & ' "
5569 "( ) * + "
5570 ", - . / "
5571 "0 1 2 3 "
5572 "4 5 6 7 "
5573 "8 9 : ; "
5574 "< = > ? "
5575 "@ A B C "
5576 "D E F G "
5577 "H I J K "
5578 "L M N O "
5579 "P Q R S "
5580 "T U V W "
5581 "X Y Z [ "
5582 "\\\\ ] ^ _ "
5583 "` a b c "
5584 "d e f g "
5585 "h i j k "
5586 "l m n o "
5587 "p q r s "
5588 "t u v w "
5589 "x y z { "
5590 "| } ~ \177 ";
5591
5592
5593// For a string that is less than 32k characters it should always be
5594// possible to allocate it in new space.
5595static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5596
5597
5598// Doing JSON quoting cannot make the string more than this many times larger.
5599static const int kJsonQuoteWorstCaseBlowup = 6;
5600
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005601static const int kSpaceForQuotesAndComma = 3;
5602static const int kSpaceForBrackets = 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005603
5604// Covers the entire ASCII range (all other characters are unchanged by JSON
5605// quoting).
5606static const byte JsonQuoteLengths[kQuoteTableLength] = {
5607 6, 6, 6, 6, 6, 6, 6, 6,
5608 2, 2, 2, 6, 2, 2, 6, 6,
5609 6, 6, 6, 6, 6, 6, 6, 6,
5610 6, 6, 6, 6, 6, 6, 6, 6,
5611 1, 1, 2, 1, 1, 1, 1, 1,
5612 1, 1, 1, 1, 1, 1, 1, 1,
5613 1, 1, 1, 1, 1, 1, 1, 1,
5614 1, 1, 1, 1, 1, 1, 1, 1,
5615 1, 1, 1, 1, 1, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 2, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623};
5624
5625
5626template <typename StringType>
Steve Block44f0eee2011-05-26 01:26:41 +01005627MaybeObject* AllocateRawString(Isolate* isolate, int length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005628
5629
5630template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005631MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5632 return isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005633}
5634
5635
5636template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005637MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5638 return isolate->heap()->AllocateRawAsciiString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005639}
5640
5641
Ben Murdochb8e0da22011-05-16 14:20:40 +01005642template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005643static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5644 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005645 int length = characters.length();
5646 const Char* read_cursor = characters.start();
5647 const Char* end = read_cursor + length;
Ben Murdochb8e0da22011-05-16 14:20:40 +01005648 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005649 int quoted_length = kSpaceForQuotes;
5650 while (read_cursor < end) {
5651 Char c = *(read_cursor++);
5652 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5653 quoted_length++;
5654 } else {
5655 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
5656 }
5657 }
Steve Block44f0eee2011-05-26 01:26:41 +01005658 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5659 quoted_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005660 Object* new_object;
5661 if (!new_alloc->ToObject(&new_object)) {
5662 return new_alloc;
5663 }
5664 StringType* new_string = StringType::cast(new_object);
5665
5666 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005667 new_string->address() + SeqString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005668 if (comma) *(write_cursor++) = ',';
Ben Murdochb0fe1622011-05-05 13:52:32 +01005669 *(write_cursor++) = '"';
5670
5671 read_cursor = characters.start();
5672 while (read_cursor < end) {
5673 Char c = *(read_cursor++);
5674 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5675 *(write_cursor++) = c;
5676 } else {
5677 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5678 const char* replacement = JsonQuotes +
5679 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5680 for (int i = 0; i < len; i++) {
5681 *write_cursor++ = *replacement++;
5682 }
5683 }
5684 }
5685 *(write_cursor++) = '"';
5686 return new_string;
5687}
5688
5689
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005690template <typename SinkChar, typename SourceChar>
5691static inline SinkChar* WriteQuoteJsonString(
5692 Isolate* isolate,
5693 SinkChar* write_cursor,
5694 Vector<const SourceChar> characters) {
5695 // SinkChar is only char if SourceChar is guaranteed to be char.
5696 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
5697 const SourceChar* read_cursor = characters.start();
5698 const SourceChar* end = read_cursor + characters.length();
5699 *(write_cursor++) = '"';
5700 while (read_cursor < end) {
5701 SourceChar c = *(read_cursor++);
5702 if (sizeof(SourceChar) > 1u &&
5703 static_cast<unsigned>(c) >= kQuoteTableLength) {
5704 *(write_cursor++) = static_cast<SinkChar>(c);
5705 } else {
5706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5707 const char* replacement = JsonQuotes +
5708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5709 write_cursor[0] = replacement[0];
5710 if (len > 1) {
5711 write_cursor[1] = replacement[1];
5712 if (len > 2) {
5713 ASSERT(len == 6);
5714 write_cursor[2] = replacement[2];
5715 write_cursor[3] = replacement[3];
5716 write_cursor[4] = replacement[4];
5717 write_cursor[5] = replacement[5];
5718 }
5719 }
5720 write_cursor += len;
5721 }
5722 }
5723 *(write_cursor++) = '"';
5724 return write_cursor;
5725}
5726
5727
Ben Murdochb8e0da22011-05-16 14:20:40 +01005728template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005729static MaybeObject* QuoteJsonString(Isolate* isolate,
5730 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005731 int length = characters.length();
Steve Block44f0eee2011-05-26 01:26:41 +01005732 isolate->counters()->quote_json_char_count()->Increment(length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005733 int worst_case_length =
5734 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005735 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
Steve Block44f0eee2011-05-26 01:26:41 +01005736 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005737 }
5738
Steve Block44f0eee2011-05-26 01:26:41 +01005739 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5740 worst_case_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005741 Object* new_object;
5742 if (!new_alloc->ToObject(&new_object)) {
5743 return new_alloc;
5744 }
Steve Block44f0eee2011-05-26 01:26:41 +01005745 if (!isolate->heap()->new_space()->Contains(new_object)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005746 // Even if our string is small enough to fit in new space we still have to
5747 // handle it being allocated in old space as may happen in the third
5748 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5749 // CEntryStub::GenerateCore.
Steve Block44f0eee2011-05-26 01:26:41 +01005750 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005751 }
5752 StringType* new_string = StringType::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01005753 ASSERT(isolate->heap()->new_space()->Contains(new_string));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005754
Ben Murdochb0fe1622011-05-05 13:52:32 +01005755 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005756 new_string->address() + SeqString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005757 if (comma) *(write_cursor++) = ',';
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005758 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5759 write_cursor,
5760 characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005761 int final_length = static_cast<int>(
5762 write_cursor - reinterpret_cast<Char*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005763 new_string->address() + SeqString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01005764 isolate->heap()->new_space()->
5765 template ShrinkStringAtAllocationBoundary<StringType>(
5766 new_string, final_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005767 return new_string;
5768}
5769
5770
Ben Murdoch8b112d22011-06-08 16:22:53 +01005771RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005772 NoHandleAllocation ha;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005773 CONVERT_ARG_CHECKED(String, str, 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005774 if (!str->IsFlat()) {
5775 MaybeObject* try_flatten = str->TryFlatten();
5776 Object* flat;
5777 if (!try_flatten->ToObject(&flat)) {
5778 return try_flatten;
5779 }
5780 str = String::cast(flat);
5781 ASSERT(str->IsFlat());
5782 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005783 String::FlatContent flat = str->GetFlatContent();
5784 ASSERT(flat.IsFlat());
5785 if (flat.IsTwoByte()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005786 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005787 flat.ToUC16Vector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005788 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005789 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005790 flat.ToAsciiVector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005791 }
5792}
5793
5794
Ben Murdoch8b112d22011-06-08 16:22:53 +01005795RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01005796 NoHandleAllocation ha;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005797 CONVERT_ARG_CHECKED(String, str, 0);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005798 if (!str->IsFlat()) {
5799 MaybeObject* try_flatten = str->TryFlatten();
5800 Object* flat;
5801 if (!try_flatten->ToObject(&flat)) {
5802 return try_flatten;
5803 }
5804 str = String::cast(flat);
5805 ASSERT(str->IsFlat());
5806 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005807 String::FlatContent flat = str->GetFlatContent();
5808 if (flat.IsTwoByte()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005809 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005810 flat.ToUC16Vector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005811 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005812 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005813 flat.ToAsciiVector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005814 }
5815}
5816
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005817
5818template <typename Char, typename StringType>
5819static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5820 FixedArray* array,
5821 int worst_case_length) {
5822 int length = array->length();
5823
5824 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5825 worst_case_length);
5826 Object* new_object;
5827 if (!new_alloc->ToObject(&new_object)) {
5828 return new_alloc;
5829 }
5830 if (!isolate->heap()->new_space()->Contains(new_object)) {
5831 // Even if our string is small enough to fit in new space we still have to
5832 // handle it being allocated in old space as may happen in the third
5833 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5834 // CEntryStub::GenerateCore.
5835 return isolate->heap()->undefined_value();
5836 }
5837 AssertNoAllocation no_gc;
5838 StringType* new_string = StringType::cast(new_object);
5839 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5840
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005841 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005842 new_string->address() + SeqString::kHeaderSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005843 *(write_cursor++) = '[';
5844 for (int i = 0; i < length; i++) {
5845 if (i != 0) *(write_cursor++) = ',';
5846 String* str = String::cast(array->get(i));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005847 String::FlatContent content = str->GetFlatContent();
5848 ASSERT(content.IsFlat());
5849 if (content.IsTwoByte()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005850 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5851 write_cursor,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005852 content.ToUC16Vector());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005853 } else {
5854 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5855 write_cursor,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005856 content.ToAsciiVector());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005857 }
5858 }
5859 *(write_cursor++) = ']';
5860
5861 int final_length = static_cast<int>(
5862 write_cursor - reinterpret_cast<Char*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005863 new_string->address() + SeqString::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005864 isolate->heap()->new_space()->
5865 template ShrinkStringAtAllocationBoundary<StringType>(
5866 new_string, final_length);
5867 return new_string;
5868}
5869
5870
5871RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5872 NoHandleAllocation ha;
5873 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005874 CONVERT_ARG_CHECKED(JSArray, array, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005875
5876 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5877 FixedArray* elements = FixedArray::cast(array->elements());
5878 int n = elements->length();
5879 bool ascii = true;
5880 int total_length = 0;
5881
5882 for (int i = 0; i < n; i++) {
5883 Object* elt = elements->get(i);
5884 if (!elt->IsString()) return isolate->heap()->undefined_value();
5885 String* element = String::cast(elt);
5886 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5887 total_length += element->length();
5888 if (ascii && element->IsTwoByteRepresentation()) {
5889 ascii = false;
5890 }
5891 }
5892
5893 int worst_case_length =
5894 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5895 + total_length * kJsonQuoteWorstCaseBlowup;
5896
5897 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5898 return isolate->heap()->undefined_value();
5899 }
5900
5901 if (ascii) {
5902 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5903 elements,
5904 worst_case_length);
5905 } else {
5906 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5907 elements,
5908 worst_case_length);
5909 }
5910}
5911
5912
Ben Murdoch8b112d22011-06-08 16:22:53 +01005913RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005914 NoHandleAllocation ha;
5915
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005916 CONVERT_ARG_CHECKED(String, s, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005917 CONVERT_SMI_ARG_CHECKED(radix, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00005918
Steve Block6ded16b2010-05-10 14:33:55 +01005919 s->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005920
Steve Block6ded16b2010-05-10 14:33:55 +01005921 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
Ben Murdoch8b112d22011-06-08 16:22:53 +01005922 double value = StringToInt(isolate->unicode_cache(), s, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01005923 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005924}
5925
5926
Ben Murdoch8b112d22011-06-08 16:22:53 +01005927RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005928 NoHandleAllocation ha;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005929 CONVERT_ARG_CHECKED(String, str, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00005930
5931 // ECMA-262 section 15.1.2.3, empty string is NaN
Ben Murdoch8b112d22011-06-08 16:22:53 +01005932 double value = StringToDouble(isolate->unicode_cache(),
5933 str, ALLOW_TRAILING_JUNK, OS::nan_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005934
5935 // Create a number object from the value.
Steve Block44f0eee2011-05-26 01:26:41 +01005936 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005937}
5938
5939
Steve Blocka7e24c12009-10-30 11:49:00 +00005940template <class Converter>
John Reck59135872010-11-02 12:39:01 -07005941MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01005942 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07005943 String* s,
5944 int length,
5945 int input_string_length,
5946 unibrow::Mapping<Converter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005947 // We try this twice, once with the assumption that the result is no longer
5948 // than the input and, if that assumption breaks, again with the exact
5949 // length. This may not be pretty, but it is nicer than what was here before
5950 // and I hereby claim my vaffel-is.
5951 //
5952 // Allocate the resulting string.
5953 //
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005954 // NOTE: This assumes that the upper/lower case of an ASCII
5955 // character is also ASCII. This is currently the case, but it
Steve Blocka7e24c12009-10-30 11:49:00 +00005956 // might break in the future if we implement more context and locale
5957 // dependent upper/lower conversions.
John Reck59135872010-11-02 12:39:01 -07005958 Object* o;
5959 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
Steve Block44f0eee2011-05-26 01:26:41 +01005960 ? isolate->heap()->AllocateRawAsciiString(length)
5961 : isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07005962 if (!maybe_o->ToObject(&o)) return maybe_o;
5963 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005964 String* result = String::cast(o);
5965 bool has_changed_character = false;
5966
5967 // Convert all characters to upper case, assuming that they will fit
5968 // in the buffer
Steve Block44f0eee2011-05-26 01:26:41 +01005969 Access<StringInputBuffer> buffer(
5970 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005971 buffer->Reset(s);
5972 unibrow::uchar chars[Converter::kMaxWidth];
5973 // We can assume that the string is not empty
5974 uc32 current = buffer->GetNext();
5975 for (int i = 0; i < length;) {
5976 bool has_next = buffer->has_more();
5977 uc32 next = has_next ? buffer->GetNext() : 0;
5978 int char_length = mapping->get(current, next, chars);
5979 if (char_length == 0) {
5980 // The case conversion of this character is the character itself.
5981 result->Set(i, current);
5982 i++;
5983 } else if (char_length == 1) {
5984 // Common case: converting the letter resulted in one character.
5985 ASSERT(static_cast<uc32>(chars[0]) != current);
5986 result->Set(i, chars[0]);
5987 has_changed_character = true;
5988 i++;
5989 } else if (length == input_string_length) {
5990 // We've assumed that the result would be as long as the
5991 // input but here is a character that converts to several
5992 // characters. No matter, we calculate the exact length
5993 // of the result and try the whole thing again.
5994 //
5995 // Note that this leaves room for optimization. We could just
5996 // memcpy what we already have to the result string. Also,
5997 // the result string is the last object allocated we could
5998 // "realloc" it and probably, in the vast majority of cases,
5999 // extend the existing string to be able to hold the full
6000 // result.
6001 int next_length = 0;
6002 if (has_next) {
6003 next_length = mapping->get(next, 0, chars);
6004 if (next_length == 0) next_length = 1;
6005 }
6006 int current_length = i + char_length + next_length;
6007 while (buffer->has_more()) {
6008 current = buffer->GetNext();
6009 // NOTE: we use 0 as the next character here because, while
6010 // the next character may affect what a character converts to,
6011 // it does not in any case affect the length of what it convert
6012 // to.
6013 int char_length = mapping->get(current, 0, chars);
6014 if (char_length == 0) char_length = 1;
6015 current_length += char_length;
6016 if (current_length > Smi::kMaxValue) {
Steve Block44f0eee2011-05-26 01:26:41 +01006017 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00006018 return Failure::OutOfMemoryException();
6019 }
6020 }
6021 // Try again with the real length.
6022 return Smi::FromInt(current_length);
6023 } else {
6024 for (int j = 0; j < char_length; j++) {
6025 result->Set(i, chars[j]);
6026 i++;
6027 }
6028 has_changed_character = true;
6029 }
6030 current = next;
6031 }
6032 if (has_changed_character) {
6033 return result;
6034 } else {
6035 // If we didn't actually change anything in doing the conversion
6036 // we simple return the result and let the converted string
6037 // become garbage; there is no reason to keep two identical strings
6038 // alive.
6039 return s;
6040 }
6041}
6042
6043
Steve Block6ded16b2010-05-10 14:33:55 +01006044namespace {
6045
John Reck59135872010-11-02 12:39:01 -07006046static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6047
6048
6049// Given a word and two range boundaries returns a word with high bit
6050// set in every byte iff the corresponding input byte was strictly in
6051// the range (m, n). All the other bits in the result are cleared.
6052// This function is only useful when it can be inlined and the
6053// boundaries are statically known.
6054// Requires: all bytes in the input word and the boundaries must be
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006055// ASCII (less than 0x7F).
John Reck59135872010-11-02 12:39:01 -07006056static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006057 // Every byte in an ASCII string is less than or equal to 0x7F.
John Reck59135872010-11-02 12:39:01 -07006058 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6059 // Use strict inequalities since in edge cases the function could be
6060 // further simplified.
6061 ASSERT(0 < m && m < n && n < 0x7F);
6062 // Has high bit set in every w byte less than n.
6063 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6064 // Has high bit set in every w byte greater than m.
6065 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6066 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6067}
6068
6069
6070enum AsciiCaseConversion {
6071 ASCII_TO_LOWER,
6072 ASCII_TO_UPPER
6073};
6074
6075
6076template <AsciiCaseConversion dir>
6077struct FastAsciiConverter {
6078 static bool Convert(char* dst, char* src, int length) {
6079#ifdef DEBUG
6080 char* saved_dst = dst;
6081 char* saved_src = src;
6082#endif
6083 // We rely on the distance between upper and lower case letters
6084 // being a known power of 2.
6085 ASSERT('a' - 'A' == (1 << 5));
6086 // Boundaries for the range of input characters than require conversion.
6087 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6088 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6089 bool changed = false;
6090 char* const limit = src + length;
6091#ifdef V8_HOST_CAN_READ_UNALIGNED
6092 // Process the prefix of the input that requires no conversion one
6093 // (machine) word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 if (AsciiRangeMask(w, lo, hi) != 0) {
6097 changed = true;
6098 break;
6099 }
6100 *reinterpret_cast<uintptr_t*>(dst) = w;
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104 // Process the remainder of the input performing conversion when
6105 // required one word at a time.
6106 while (src <= limit - sizeof(uintptr_t)) {
6107 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6108 uintptr_t m = AsciiRangeMask(w, lo, hi);
6109 // The mask has high (7th) bit set in every byte that needs
6110 // conversion and we know that the distance between cases is
6111 // 1 << 5.
6112 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6113 src += sizeof(uintptr_t);
6114 dst += sizeof(uintptr_t);
6115 }
6116#endif
6117 // Process the last few bytes of the input (or the whole input if
6118 // unaligned access is not supported).
6119 while (src < limit) {
6120 char c = *src;
6121 if (lo < c && c < hi) {
6122 c ^= (1 << 5);
6123 changed = true;
6124 }
6125 *dst = c;
6126 ++src;
6127 ++dst;
6128 }
6129#ifdef DEBUG
6130 CheckConvert(saved_dst, saved_src, length, changed);
6131#endif
6132 return changed;
6133 }
6134
6135#ifdef DEBUG
6136 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6137 bool expected_changed = false;
6138 for (int i = 0; i < length; i++) {
6139 if (dst[i] == src[i]) continue;
6140 expected_changed = true;
6141 if (dir == ASCII_TO_LOWER) {
6142 ASSERT('A' <= src[i] && src[i] <= 'Z');
6143 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6144 } else {
6145 ASSERT(dir == ASCII_TO_UPPER);
6146 ASSERT('a' <= src[i] && src[i] <= 'z');
6147 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6148 }
6149 }
6150 ASSERT(expected_changed == changed);
6151 }
6152#endif
6153};
6154
6155
Steve Block6ded16b2010-05-10 14:33:55 +01006156struct ToLowerTraits {
6157 typedef unibrow::ToLowercase UnibrowConverter;
6158
John Reck59135872010-11-02 12:39:01 -07006159 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01006160};
6161
6162
6163struct ToUpperTraits {
6164 typedef unibrow::ToUppercase UnibrowConverter;
6165
John Reck59135872010-11-02 12:39:01 -07006166 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01006167};
6168
6169} // namespace
6170
6171
6172template <typename ConvertTraits>
John Reck59135872010-11-02 12:39:01 -07006173MUST_USE_RESULT static MaybeObject* ConvertCase(
Steve Block6ded16b2010-05-10 14:33:55 +01006174 Arguments args,
Steve Block44f0eee2011-05-26 01:26:41 +01006175 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01006176 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006177 NoHandleAllocation ha;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006178 CONVERT_ARG_CHECKED(String, s, 0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006179 s = s->TryFlattenGetString();
Steve Blocka7e24c12009-10-30 11:49:00 +00006180
Steve Block6ded16b2010-05-10 14:33:55 +01006181 const int length = s->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00006182 // Assume that the string is not empty; we need this assumption later
Steve Block6ded16b2010-05-10 14:33:55 +01006183 if (length == 0) return s;
6184
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006185 // Simpler handling of ASCII strings.
Steve Block6ded16b2010-05-10 14:33:55 +01006186 //
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006187 // NOTE: This assumes that the upper/lower case of an ASCII
6188 // character is also ASCII. This is currently the case, but it
Steve Block6ded16b2010-05-10 14:33:55 +01006189 // might break in the future if we implement more context and locale
6190 // dependent upper/lower conversions.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006191 if (s->IsSeqAsciiString()) {
John Reck59135872010-11-02 12:39:01 -07006192 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01006193 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07006194 if (!maybe_o->ToObject(&o)) return maybe_o;
6195 }
Steve Block6ded16b2010-05-10 14:33:55 +01006196 SeqAsciiString* result = SeqAsciiString::cast(o);
John Reck59135872010-11-02 12:39:01 -07006197 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006198 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
Steve Block6ded16b2010-05-10 14:33:55 +01006199 return has_changed_character ? result : s;
6200 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006201
John Reck59135872010-11-02 12:39:01 -07006202 Object* answer;
Steve Block44f0eee2011-05-26 01:26:41 +01006203 { MaybeObject* maybe_answer =
6204 ConvertCaseHelper(isolate, s, length, length, mapping);
John Reck59135872010-11-02 12:39:01 -07006205 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6206 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006207 if (answer->IsSmi()) {
6208 // Retry with correct length.
John Reck59135872010-11-02 12:39:01 -07006209 { MaybeObject* maybe_answer =
Steve Block44f0eee2011-05-26 01:26:41 +01006210 ConvertCaseHelper(isolate,
6211 s, Smi::cast(answer)->value(), length, mapping);
John Reck59135872010-11-02 12:39:01 -07006212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6213 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006214 }
John Reck59135872010-11-02 12:39:01 -07006215 return answer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006216}
6217
6218
Ben Murdoch8b112d22011-06-08 16:22:53 +01006219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01006220 return ConvertCase<ToLowerTraits>(
6221 args, isolate, isolate->runtime_state()->to_lower_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00006222}
6223
6224
Ben Murdoch8b112d22011-06-08 16:22:53 +01006225RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01006226 return ConvertCase<ToUpperTraits>(
6227 args, isolate, isolate->runtime_state()->to_upper_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00006228}
6229
Steve Block6ded16b2010-05-10 14:33:55 +01006230
Steve Block3ce2e202009-11-05 08:53:23 +00006231static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006232 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
Steve Block3ce2e202009-11-05 08:53:23 +00006233}
6234
Steve Block6ded16b2010-05-10 14:33:55 +01006235
Ben Murdoch8b112d22011-06-08 16:22:53 +01006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
Steve Block3ce2e202009-11-05 08:53:23 +00006237 NoHandleAllocation ha;
6238 ASSERT(args.length() == 3);
6239
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006240 CONVERT_ARG_CHECKED(String, s, 0);
6241 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6242 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
Steve Block3ce2e202009-11-05 08:53:23 +00006243
Steve Block6ded16b2010-05-10 14:33:55 +01006244 s->TryFlatten();
Steve Block3ce2e202009-11-05 08:53:23 +00006245 int length = s->length();
6246
6247 int left = 0;
6248 if (trimLeft) {
6249 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6250 left++;
6251 }
6252 }
6253
6254 int right = length;
6255 if (trimRight) {
6256 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6257 right--;
6258 }
6259 }
Steve Blockd0582a62009-12-15 09:54:21 +00006260 return s->SubString(left, right);
Steve Block3ce2e202009-11-05 08:53:23 +00006261}
Steve Blocka7e24c12009-10-30 11:49:00 +00006262
Steve Block6ded16b2010-05-10 14:33:55 +01006263
Ben Murdoch8b112d22011-06-08 16:22:53 +01006264RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
Steve Block6ded16b2010-05-10 14:33:55 +01006265 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +01006266 HandleScope handle_scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006267 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6268 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
Steve Block6ded16b2010-05-10 14:33:55 +01006269 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6270
6271 int subject_length = subject->length();
6272 int pattern_length = pattern->length();
6273 RUNTIME_ASSERT(pattern_length > 0);
6274
Ben Murdoch589d6972011-11-30 16:04:58 +00006275 if (limit == 0xffffffffu) {
6276 Handle<Object> cached_answer(StringSplitCache::Lookup(
6277 isolate->heap()->string_split_cache(),
6278 *subject,
6279 *pattern));
6280 if (*cached_answer != Smi::FromInt(0)) {
6281 Handle<JSArray> result =
6282 isolate->factory()->NewJSArrayWithElements(
6283 Handle<FixedArray>::cast(cached_answer));
6284 return *result;
6285 }
6286 }
6287
Steve Block6ded16b2010-05-10 14:33:55 +01006288 // The limit can be very large (0xffffffffu), but since the pattern
6289 // isn't empty, we can never create more parts than ~half the length
6290 // of the subject.
6291
6292 if (!subject->IsFlat()) FlattenString(subject);
6293
6294 static const int kMaxInitialListCapacity = 16;
6295
Ben Murdoch257744e2011-11-30 15:57:28 +00006296 ZoneScope scope(isolate, DELETE_ON_EXIT);
Steve Block6ded16b2010-05-10 14:33:55 +01006297
6298 // Find (up to limit) indices of separator and end-of-string in subject
6299 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6300 ZoneList<int> indices(initial_capacity);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006301 if (!pattern->IsFlat()) FlattenString(pattern);
6302
Ben Murdoch589d6972011-11-30 16:04:58 +00006303 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006304
Steve Block6ded16b2010-05-10 14:33:55 +01006305 if (static_cast<uint32_t>(indices.length()) < limit) {
6306 indices.Add(subject_length);
6307 }
Steve Block6ded16b2010-05-10 14:33:55 +01006308
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006309 // The list indices now contains the end of each part to create.
Steve Block6ded16b2010-05-10 14:33:55 +01006310
6311 // Create JSArray of substrings separated by separator.
6312 int part_count = indices.length();
6313
Steve Block44f0eee2011-05-26 01:26:41 +01006314 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006315 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
6316 if (maybe_result->IsFailure()) return maybe_result;
Steve Block6ded16b2010-05-10 14:33:55 +01006317 result->set_length(Smi::FromInt(part_count));
6318
6319 ASSERT(result->HasFastElements());
6320
6321 if (part_count == 1 && indices.at(0) == subject_length) {
6322 FixedArray::cast(result->elements())->set(0, *subject);
6323 return *result;
6324 }
6325
6326 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6327 int part_start = 0;
6328 for (int i = 0; i < part_count; i++) {
6329 HandleScope local_loop_handle;
6330 int part_end = indices.at(i);
6331 Handle<String> substring =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006332 isolate->factory()->NewProperSubString(subject, part_start, part_end);
Steve Block6ded16b2010-05-10 14:33:55 +01006333 elements->set(i, *substring);
6334 part_start = part_end + pattern_length;
6335 }
6336
Ben Murdoch589d6972011-11-30 16:04:58 +00006337 if (limit == 0xffffffffu) {
6338 if (result->HasFastElements()) {
6339 StringSplitCache::Enter(isolate->heap(),
6340 isolate->heap()->string_split_cache(),
6341 *subject,
6342 *pattern,
6343 *elements);
6344 }
6345 }
6346
Steve Block6ded16b2010-05-10 14:33:55 +01006347 return *result;
6348}
6349
6350
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006351// Copies ASCII characters to the given fixed array looking up
Steve Block6ded16b2010-05-10 14:33:55 +01006352// one-char strings in the cache. Gives up on the first char that is
6353// not in the cache and fills the remainder with smi zeros. Returns
6354// the length of the successfully copied prefix.
Steve Block44f0eee2011-05-26 01:26:41 +01006355static int CopyCachedAsciiCharsToArray(Heap* heap,
6356 const char* chars,
Steve Block6ded16b2010-05-10 14:33:55 +01006357 FixedArray* elements,
6358 int length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006359 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +01006360 FixedArray* ascii_cache = heap->single_character_string_cache();
6361 Object* undefined = heap->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01006362 int i;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006363 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Block6ded16b2010-05-10 14:33:55 +01006364 for (i = 0; i < length; ++i) {
6365 Object* value = ascii_cache->get(chars[i]);
6366 if (value == undefined) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006367 elements->set(i, value, mode);
Steve Block6ded16b2010-05-10 14:33:55 +01006368 }
6369 if (i < length) {
6370 ASSERT(Smi::FromInt(0) == 0);
6371 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6372 }
6373#ifdef DEBUG
6374 for (int j = 0; j < length; ++j) {
6375 Object* element = elements->get(j);
6376 ASSERT(element == Smi::FromInt(0) ||
6377 (element->IsString() && String::cast(element)->LooksValid()));
6378 }
6379#endif
6380 return i;
6381}
6382
6383
6384// Converts a String to JSArray.
6385// For example, "foo" => ["f", "o", "o"].
Ben Murdoch8b112d22011-06-08 16:22:53 +01006386RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
Steve Block44f0eee2011-05-26 01:26:41 +01006387 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006388 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006389 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006390 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Steve Block6ded16b2010-05-10 14:33:55 +01006391
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006392 s = FlattenGetString(s);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006393 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
Steve Block6ded16b2010-05-10 14:33:55 +01006394
6395 Handle<FixedArray> elements;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006396 int position = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01006397 if (s->IsFlat() && s->IsAsciiRepresentation()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006398 // Try using cached chars where possible.
John Reck59135872010-11-02 12:39:01 -07006399 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006400 { MaybeObject* maybe_obj =
6401 isolate->heap()->AllocateUninitializedFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07006402 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6403 }
Steve Block44f0eee2011-05-26 01:26:41 +01006404 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006405 String::FlatContent content = s->GetFlatContent();
6406 if (content.IsAscii()) {
6407 Vector<const char> chars = content.ToAsciiVector();
6408 // Note, this will initialize all elements (not only the prefix)
6409 // to prevent GC from seeing partially initialized array.
6410 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6411 chars.start(),
6412 *elements,
6413 length);
6414 } else {
6415 MemsetPointer(elements->data_start(),
6416 isolate->heap()->undefined_value(),
6417 length);
Steve Block6ded16b2010-05-10 14:33:55 +01006418 }
6419 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006420 elements = isolate->factory()->NewFixedArray(length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006421 }
6422 for (int i = position; i < length; ++i) {
6423 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6424 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01006425 }
6426
6427#ifdef DEBUG
6428 for (int i = 0; i < length; ++i) {
6429 ASSERT(String::cast(elements->get(i))->length() == 1);
6430 }
6431#endif
6432
Steve Block44f0eee2011-05-26 01:26:41 +01006433 return *isolate->factory()->NewJSArrayWithElements(elements);
Steve Block6ded16b2010-05-10 14:33:55 +01006434}
6435
6436
Ben Murdoch8b112d22011-06-08 16:22:53 +01006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006440 CONVERT_ARG_CHECKED(String, value, 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006441 return value->ToObject();
6442}
6443
6444
Steve Block44f0eee2011-05-26 01:26:41 +01006445bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006446 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
Steve Block44f0eee2011-05-26 01:26:41 +01006447 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006448 return char_length == 0;
6449}
6450
6451
Ben Murdoch8b112d22011-06-08 16:22:53 +01006452RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
6455
6456 Object* number = args[0];
6457 RUNTIME_ASSERT(number->IsNumber());
6458
Steve Block44f0eee2011-05-26 01:26:41 +01006459 return isolate->heap()->NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00006460}
6461
6462
Ben Murdoch8b112d22011-06-08 16:22:53 +01006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
Steve Block6ded16b2010-05-10 14:33:55 +01006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
6467 Object* number = args[0];
6468 RUNTIME_ASSERT(number->IsNumber());
6469
Steve Block44f0eee2011-05-26 01:26:41 +01006470 return isolate->heap()->NumberToString(number, false);
Steve Block6ded16b2010-05-10 14:33:55 +01006471}
6472
6473
Ben Murdoch8b112d22011-06-08 16:22:53 +01006474RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006475 NoHandleAllocation ha;
6476 ASSERT(args.length() == 1);
6477
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006478 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01006479
6480 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6481 if (number > 0 && number <= Smi::kMaxValue) {
6482 return Smi::FromInt(static_cast<int>(number));
6483 }
Steve Block44f0eee2011-05-26 01:26:41 +01006484 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00006485}
6486
6487
Ben Murdoch8b112d22011-06-08 16:22:53 +01006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006492 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006493
6494 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6495 if (number > 0 && number <= Smi::kMaxValue) {
6496 return Smi::FromInt(static_cast<int>(number));
6497 }
6498
6499 double double_value = DoubleToInteger(number);
6500 // Map both -0 and +0 to +0.
6501 if (double_value == 0) double_value = 0;
6502
Steve Block44f0eee2011-05-26 01:26:41 +01006503 return isolate->heap()->NumberFromDouble(double_value);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006504}
6505
6506
Ben Murdoch8b112d22011-06-08 16:22:53 +01006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
Steve Block6ded16b2010-05-10 14:33:55 +01006511 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006512 return isolate->heap()->NumberFromUint32(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00006513}
6514
6515
Ben Murdoch8b112d22011-06-08 16:22:53 +01006516RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
6519
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006520 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01006521
6522 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6523 if (number > 0 && number <= Smi::kMaxValue) {
6524 return Smi::FromInt(static_cast<int>(number));
6525 }
Steve Block44f0eee2011-05-26 01:26:41 +01006526 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00006527}
6528
6529
6530// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6531// a small integer.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
6536 Object* obj = args[0];
6537 if (obj->IsSmi()) {
6538 return obj;
6539 }
6540 if (obj->IsHeapNumber()) {
6541 double value = HeapNumber::cast(obj)->value();
6542 int int_value = FastD2I(value);
6543 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6544 return Smi::FromInt(int_value);
6545 }
6546 }
Steve Block44f0eee2011-05-26 01:26:41 +01006547 return isolate->heap()->nan_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006548}
6549
6550
Ben Murdoch8b112d22011-06-08 16:22:53 +01006551RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01006554 return isolate->heap()->AllocateHeapNumber(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006555}
6556
6557
Ben Murdoch8b112d22011-06-08 16:22:53 +01006558RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006562 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6563 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006564 return isolate->heap()->NumberFromDouble(x + y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006565}
6566
6567
Ben Murdoch8b112d22011-06-08 16:22:53 +01006568RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6573 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006574 return isolate->heap()->NumberFromDouble(x - y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006575}
6576
6577
Ben Murdoch8b112d22011-06-08 16:22:53 +01006578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006579 NoHandleAllocation ha;
6580 ASSERT(args.length() == 2);
6581
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6583 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006584 return isolate->heap()->NumberFromDouble(x * y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006585}
6586
6587
Ben Murdoch8b112d22011-06-08 16:22:53 +01006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01006593 return isolate->heap()->NumberFromDouble(-x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006594}
6595
6596
Ben Murdoch8b112d22011-06-08 16:22:53 +01006597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 0);
6600
Steve Block44f0eee2011-05-26 01:26:41 +01006601 return isolate->heap()->NumberFromDouble(9876543210.0);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006602}
6603
6604
Ben Murdoch8b112d22011-06-08 16:22:53 +01006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
6608
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006609 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6610 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006611 return isolate->heap()->NumberFromDouble(x / y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006612}
6613
6614
Ben Murdoch8b112d22011-06-08 16:22:53 +01006615RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006616 NoHandleAllocation ha;
6617 ASSERT(args.length() == 2);
6618
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006619 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6620 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00006621
Steve Block3ce2e202009-11-05 08:53:23 +00006622 x = modulo(x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01006623 // NumberFromDouble may return a Smi instead of a Number object
Steve Block44f0eee2011-05-26 01:26:41 +01006624 return isolate->heap()->NumberFromDouble(x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006625}
6626
6627
Ben Murdoch8b112d22011-06-08 16:22:53 +01006628RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006631 CONVERT_ARG_CHECKED(String, str1, 0);
6632 CONVERT_ARG_CHECKED(String, str2, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006633 isolate->counters()->string_add_runtime()->Increment();
6634 return isolate->heap()->AllocateConsString(str1, str2);
Steve Blocka7e24c12009-10-30 11:49:00 +00006635}
6636
6637
Steve Block6ded16b2010-05-10 14:33:55 +01006638template <typename sinkchar>
Steve Blocka7e24c12009-10-30 11:49:00 +00006639static inline void StringBuilderConcatHelper(String* special,
6640 sinkchar* sink,
6641 FixedArray* fixed_array,
6642 int array_length) {
6643 int position = 0;
6644 for (int i = 0; i < array_length; i++) {
6645 Object* element = fixed_array->get(i);
6646 if (element->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006647 // Smi encoding of position and length.
Steve Blocka7e24c12009-10-30 11:49:00 +00006648 int encoded_slice = Smi::cast(element)->value();
Steve Blockd0582a62009-12-15 09:54:21 +00006649 int pos;
6650 int len;
6651 if (encoded_slice > 0) {
6652 // Position and length encoded in one smi.
6653 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6654 len = StringBuilderSubstringLength::decode(encoded_slice);
6655 } else {
6656 // Position and length encoded in two smis.
6657 Object* obj = fixed_array->get(++i);
6658 ASSERT(obj->IsSmi());
6659 pos = Smi::cast(obj)->value();
6660 len = -encoded_slice;
6661 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006662 String::WriteToFlat(special,
6663 sink + position,
6664 pos,
6665 pos + len);
6666 position += len;
6667 } else {
6668 String* string = String::cast(element);
6669 int element_length = string->length();
6670 String::WriteToFlat(string, sink + position, 0, element_length);
6671 position += element_length;
6672 }
6673 }
6674}
6675
6676
Ben Murdoch8b112d22011-06-08 16:22:53 +01006677RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006678 NoHandleAllocation ha;
Leon Clarkee46be812010-01-19 14:06:41 +00006679 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006680 CONVERT_ARG_CHECKED(JSArray, array, 0);
Leon Clarkee46be812010-01-19 14:06:41 +00006681 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006682 isolate->context()->mark_out_of_memory();
Leon Clarkee46be812010-01-19 14:06:41 +00006683 return Failure::OutOfMemoryException();
6684 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006685 int array_length = args.smi_at(1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006686 CONVERT_ARG_CHECKED(String, special, 2);
Steve Blockd0582a62009-12-15 09:54:21 +00006687
6688 // This assumption is used by the slice encoding in one or two smis.
6689 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6690
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006691 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
6692 if (maybe_result->IsFailure()) return maybe_result;
6693
Steve Blocka7e24c12009-10-30 11:49:00 +00006694 int special_length = special->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00006695 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006696 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00006697 }
6698 FixedArray* fixed_array = FixedArray::cast(array->elements());
6699 if (fixed_array->length() < array_length) {
6700 array_length = fixed_array->length();
6701 }
6702
6703 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006704 return isolate->heap()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 } else if (array_length == 1) {
6706 Object* first = fixed_array->get(0);
6707 if (first->IsString()) return first;
6708 }
6709
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006710 bool ascii = special->HasOnlyAsciiChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006711 int position = 0;
6712 for (int i = 0; i < array_length; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01006713 int increment = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006714 Object* elt = fixed_array->get(i);
6715 if (elt->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006716 // Smi encoding of position and length.
Steve Block6ded16b2010-05-10 14:33:55 +01006717 int smi_value = Smi::cast(elt)->value();
6718 int pos;
6719 int len;
6720 if (smi_value > 0) {
Steve Blockd0582a62009-12-15 09:54:21 +00006721 // Position and length encoded in one smi.
Steve Block6ded16b2010-05-10 14:33:55 +01006722 pos = StringBuilderSubstringPosition::decode(smi_value);
6723 len = StringBuilderSubstringLength::decode(smi_value);
Steve Blockd0582a62009-12-15 09:54:21 +00006724 } else {
6725 // Position and length encoded in two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01006726 len = -smi_value;
6727 // Get the position and check that it is a positive smi.
Steve Blockd0582a62009-12-15 09:54:21 +00006728 i++;
6729 if (i >= array_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006731 }
Steve Block6ded16b2010-05-10 14:33:55 +01006732 Object* next_smi = fixed_array->get(i);
6733 if (!next_smi->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006735 }
6736 pos = Smi::cast(next_smi)->value();
6737 if (pos < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006739 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006740 }
Steve Block6ded16b2010-05-10 14:33:55 +01006741 ASSERT(pos >= 0);
6742 ASSERT(len >= 0);
6743 if (pos > special_length || len > special_length - pos) {
Steve Block44f0eee2011-05-26 01:26:41 +01006744 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006745 }
6746 increment = len;
Steve Blocka7e24c12009-10-30 11:49:00 +00006747 } else if (elt->IsString()) {
6748 String* element = String::cast(elt);
6749 int element_length = element->length();
Leon Clarkee46be812010-01-19 14:06:41 +00006750 increment = element_length;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006751 if (ascii && !element->HasOnlyAsciiChars()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006752 ascii = false;
6753 }
6754 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006755 ASSERT(!elt->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01006756 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00006757 }
Leon Clarkee46be812010-01-19 14:06:41 +00006758 if (increment > String::kMaxLength - position) {
Steve Block44f0eee2011-05-26 01:26:41 +01006759 isolate->context()->mark_out_of_memory();
Steve Block3ce2e202009-11-05 08:53:23 +00006760 return Failure::OutOfMemoryException();
6761 }
Leon Clarkee46be812010-01-19 14:06:41 +00006762 position += increment;
Steve Blocka7e24c12009-10-30 11:49:00 +00006763 }
6764
6765 int length = position;
6766 Object* object;
6767
6768 if (ascii) {
Steve Block44f0eee2011-05-26 01:26:41 +01006769 { MaybeObject* maybe_object =
6770 isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07006771 if (!maybe_object->ToObject(&object)) return maybe_object;
6772 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006773 SeqAsciiString* answer = SeqAsciiString::cast(object);
6774 StringBuilderConcatHelper(special,
6775 answer->GetChars(),
6776 fixed_array,
6777 array_length);
6778 return answer;
6779 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006780 { MaybeObject* maybe_object =
6781 isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07006782 if (!maybe_object->ToObject(&object)) return maybe_object;
6783 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006784 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6785 StringBuilderConcatHelper(special,
6786 answer->GetChars(),
6787 fixed_array,
6788 array_length);
6789 return answer;
6790 }
6791}
6792
6793
Ben Murdoch8b112d22011-06-08 16:22:53 +01006794RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006795 NoHandleAllocation ha;
6796 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006797 CONVERT_ARG_CHECKED(JSArray, array, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006798 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006799 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006800 return Failure::OutOfMemoryException();
6801 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006802 int array_length = args.smi_at(1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006803 CONVERT_ARG_CHECKED(String, separator, 2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006804
6805 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006806 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006807 }
6808 FixedArray* fixed_array = FixedArray::cast(array->elements());
6809 if (fixed_array->length() < array_length) {
6810 array_length = fixed_array->length();
6811 }
6812
6813 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006814 return isolate->heap()->empty_string();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006815 } else if (array_length == 1) {
6816 Object* first = fixed_array->get(0);
6817 if (first->IsString()) return first;
6818 }
6819
6820 int separator_length = separator->length();
6821 int max_nof_separators =
6822 (String::kMaxLength + separator_length - 1) / separator_length;
6823 if (max_nof_separators < (array_length - 1)) {
Steve Block44f0eee2011-05-26 01:26:41 +01006824 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006825 return Failure::OutOfMemoryException();
6826 }
6827 int length = (array_length - 1) * separator_length;
6828 for (int i = 0; i < array_length; i++) {
6829 Object* element_obj = fixed_array->get(i);
6830 if (!element_obj->IsString()) {
6831 // TODO(1161): handle this case.
Steve Block44f0eee2011-05-26 01:26:41 +01006832 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006833 }
6834 String* element = String::cast(element_obj);
6835 int increment = element->length();
6836 if (increment > String::kMaxLength - length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006837 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006838 return Failure::OutOfMemoryException();
6839 }
6840 length += increment;
6841 }
6842
6843 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +01006844 { MaybeObject* maybe_object =
6845 isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006846 if (!maybe_object->ToObject(&object)) return maybe_object;
6847 }
6848 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6849
6850 uc16* sink = answer->GetChars();
6851#ifdef DEBUG
6852 uc16* end = sink + length;
6853#endif
6854
6855 String* first = String::cast(fixed_array->get(0));
6856 int first_length = first->length();
6857 String::WriteToFlat(first, sink, 0, first_length);
6858 sink += first_length;
6859
6860 for (int i = 1; i < array_length; i++) {
6861 ASSERT(sink + separator_length <= end);
6862 String::WriteToFlat(separator, sink, 0, separator_length);
6863 sink += separator_length;
6864
6865 String* element = String::cast(fixed_array->get(i));
6866 int element_length = element->length();
6867 ASSERT(sink + element_length <= end);
6868 String::WriteToFlat(element, sink, 0, element_length);
6869 sink += element_length;
6870 }
6871 ASSERT(sink == end);
6872
6873 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6874 return answer;
6875}
6876
Ben Murdoch257744e2011-11-30 15:57:28 +00006877template <typename Char>
6878static void JoinSparseArrayWithSeparator(FixedArray* elements,
6879 int elements_length,
6880 uint32_t array_length,
6881 String* separator,
6882 Vector<Char> buffer) {
6883 int previous_separator_position = 0;
6884 int separator_length = separator->length();
6885 int cursor = 0;
6886 for (int i = 0; i < elements_length; i += 2) {
6887 int position = NumberToInt32(elements->get(i));
6888 String* string = String::cast(elements->get(i + 1));
6889 int string_length = string->length();
6890 if (string->length() > 0) {
6891 while (previous_separator_position < position) {
6892 String::WriteToFlat<Char>(separator, &buffer[cursor],
6893 0, separator_length);
6894 cursor += separator_length;
6895 previous_separator_position++;
6896 }
6897 String::WriteToFlat<Char>(string, &buffer[cursor],
6898 0, string_length);
6899 cursor += string->length();
6900 }
6901 }
6902 if (separator_length > 0) {
6903 // Array length must be representable as a signed 32-bit number,
6904 // otherwise the total string length would have been too large.
6905 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6906 int last_array_index = static_cast<int>(array_length - 1);
6907 while (previous_separator_position < last_array_index) {
6908 String::WriteToFlat<Char>(separator, &buffer[cursor],
6909 0, separator_length);
6910 cursor += separator_length;
6911 previous_separator_position++;
6912 }
6913 }
6914 ASSERT(cursor <= buffer.length());
6915}
6916
6917
6918RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006921 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
6922 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6923 elements_array->HasFastSmiOnlyElements());
Ben Murdoch257744e2011-11-30 15:57:28 +00006924 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006925 CONVERT_ARG_CHECKED(String, separator, 2);
Ben Murdoch257744e2011-11-30 15:57:28 +00006926 // elements_array is fast-mode JSarray of alternating positions
6927 // (increasing order) and strings.
6928 // array_length is length of original array (used to add separators);
6929 // separator is string to put between elements. Assumed to be non-empty.
6930
6931 // Find total length of join result.
6932 int string_length = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006933 bool is_ascii = separator->IsAsciiRepresentation();
Ben Murdoch589d6972011-11-30 16:04:58 +00006934 int max_string_length;
6935 if (is_ascii) {
6936 max_string_length = SeqAsciiString::kMaxLength;
6937 } else {
6938 max_string_length = SeqTwoByteString::kMaxLength;
6939 }
Ben Murdoch257744e2011-11-30 15:57:28 +00006940 bool overflow = false;
6941 CONVERT_NUMBER_CHECKED(int, elements_length,
6942 Int32, elements_array->length());
6943 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6944 FixedArray* elements = FixedArray::cast(elements_array->elements());
6945 for (int i = 0; i < elements_length; i += 2) {
6946 RUNTIME_ASSERT(elements->get(i)->IsNumber());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006947 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6948 String* string = String::cast(elements->get(i + 1));
Ben Murdoch257744e2011-11-30 15:57:28 +00006949 int length = string->length();
6950 if (is_ascii && !string->IsAsciiRepresentation()) {
6951 is_ascii = false;
6952 max_string_length = SeqTwoByteString::kMaxLength;
6953 }
6954 if (length > max_string_length ||
6955 max_string_length - length < string_length) {
6956 overflow = true;
6957 break;
6958 }
6959 string_length += length;
6960 }
6961 int separator_length = separator->length();
6962 if (!overflow && separator_length > 0) {
6963 if (array_length <= 0x7fffffffu) {
6964 int separator_count = static_cast<int>(array_length) - 1;
6965 int remaining_length = max_string_length - string_length;
6966 if ((remaining_length / separator_length) >= separator_count) {
6967 string_length += separator_length * (array_length - 1);
6968 } else {
6969 // Not room for the separators within the maximal string length.
6970 overflow = true;
6971 }
6972 } else {
6973 // Nonempty separator and at least 2^31-1 separators necessary
6974 // means that the string is too large to create.
6975 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6976 overflow = true;
6977 }
6978 }
6979 if (overflow) {
6980 // Throw OutOfMemory exception for creating too large a string.
6981 V8::FatalProcessOutOfMemory("Array join result too large.");
6982 }
6983
6984 if (is_ascii) {
6985 MaybeObject* result_allocation =
6986 isolate->heap()->AllocateRawAsciiString(string_length);
6987 if (result_allocation->IsFailure()) return result_allocation;
6988 SeqAsciiString* result_string =
6989 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6990 JoinSparseArrayWithSeparator<char>(elements,
6991 elements_length,
6992 array_length,
6993 separator,
6994 Vector<char>(result_string->GetChars(),
6995 string_length));
6996 return result_string;
6997 } else {
6998 MaybeObject* result_allocation =
6999 isolate->heap()->AllocateRawTwoByteString(string_length);
7000 if (result_allocation->IsFailure()) return result_allocation;
7001 SeqTwoByteString* result_string =
7002 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7003 JoinSparseArrayWithSeparator<uc16>(elements,
7004 elements_length,
7005 array_length,
7006 separator,
7007 Vector<uc16>(result_string->GetChars(),
7008 string_length));
7009 return result_string;
7010 }
7011}
7012
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007013
Ben Murdoch8b112d22011-06-08 16:22:53 +01007014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 2);
7017
7018 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7019 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007020 return isolate->heap()->NumberFromInt32(x | y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007021}
7022
7023
Ben Murdoch8b112d22011-06-08 16:22:53 +01007024RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007025 NoHandleAllocation ha;
7026 ASSERT(args.length() == 2);
7027
7028 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7029 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007030 return isolate->heap()->NumberFromInt32(x & y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007031}
7032
7033
Ben Murdoch8b112d22011-06-08 16:22:53 +01007034RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007035 NoHandleAllocation ha;
7036 ASSERT(args.length() == 2);
7037
7038 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7039 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007040 return isolate->heap()->NumberFromInt32(x ^ y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007041}
7042
7043
Ben Murdoch8b112d22011-06-08 16:22:53 +01007044RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 1);
7047
7048 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01007049 return isolate->heap()->NumberFromInt32(~x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007050}
7051
7052
Ben Murdoch8b112d22011-06-08 16:22:53 +01007053RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007054 NoHandleAllocation ha;
7055 ASSERT(args.length() == 2);
7056
7057 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7058 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007059 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007060}
7061
7062
Ben Murdoch8b112d22011-06-08 16:22:53 +01007063RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007064 NoHandleAllocation ha;
7065 ASSERT(args.length() == 2);
7066
7067 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7068 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007069 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007070}
7071
7072
Ben Murdoch8b112d22011-06-08 16:22:53 +01007073RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007074 NoHandleAllocation ha;
7075 ASSERT(args.length() == 2);
7076
7077 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7078 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007079 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007080}
7081
7082
Ben Murdoch8b112d22011-06-08 16:22:53 +01007083RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007084 NoHandleAllocation ha;
7085 ASSERT(args.length() == 2);
7086
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7088 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007089 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7090 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7091 if (x == y) return Smi::FromInt(EQUAL);
7092 Object* result;
7093 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7094 result = Smi::FromInt(EQUAL);
7095 } else {
7096 result = Smi::FromInt(NOT_EQUAL);
7097 }
7098 return result;
7099}
7100
7101
Ben Murdoch8b112d22011-06-08 16:22:53 +01007102RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 2);
7105
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007106 CONVERT_ARG_CHECKED(String, x, 0);
7107 CONVERT_ARG_CHECKED(String, y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007108
7109 bool not_equal = !x->Equals(y);
7110 // This is slightly convoluted because the value that signifies
7111 // equality is 0 and inequality is 1 so we have to negate the result
7112 // from String::Equals.
7113 ASSERT(not_equal == 0 || not_equal == 1);
7114 STATIC_CHECK(EQUAL == 0);
7115 STATIC_CHECK(NOT_EQUAL == 1);
7116 return Smi::FromInt(not_equal);
7117}
7118
7119
Ben Murdoch8b112d22011-06-08 16:22:53 +01007120RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007121 NoHandleAllocation ha;
7122 ASSERT(args.length() == 3);
7123
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007124 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7125 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007126 if (isnan(x) || isnan(y)) return args[2];
7127 if (x == y) return Smi::FromInt(EQUAL);
7128 if (isless(x, y)) return Smi::FromInt(LESS);
7129 return Smi::FromInt(GREATER);
7130}
7131
7132
7133// Compare two Smis as if they were converted to strings and then
7134// compared lexicographically.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007135RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007136 NoHandleAllocation ha;
7137 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007138 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7139 CONVERT_SMI_ARG_CHECKED(y_value, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007140
7141 // If the integers are equal so are the string representations.
7142 if (x_value == y_value) return Smi::FromInt(EQUAL);
7143
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007144 // If one of the integers is zero the normal integer order is the
Steve Blocka7e24c12009-10-30 11:49:00 +00007145 // same as the lexicographic order of the string representations.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007146 if (x_value == 0 || y_value == 0)
7147 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
Steve Blocka7e24c12009-10-30 11:49:00 +00007148
7149 // If only one of the integers is negative the negative number is
7150 // smallest because the char code of '-' is less than the char code
7151 // of any digit. Otherwise, we make both values positive.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007152
7153 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7154 // architectures using 32-bit Smis.
7155 uint32_t x_scaled = x_value;
7156 uint32_t y_scaled = y_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007157 if (x_value < 0 || y_value < 0) {
7158 if (y_value >= 0) return Smi::FromInt(LESS);
7159 if (x_value >= 0) return Smi::FromInt(GREATER);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007160 x_scaled = -x_value;
7161 y_scaled = -y_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007162 }
7163
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007164 static const uint32_t kPowersOf10[] = {
7165 1, 10, 100, 1000, 10*1000, 100*1000,
7166 1000*1000, 10*1000*1000, 100*1000*1000,
7167 1000*1000*1000
7168 };
Steve Block44f0eee2011-05-26 01:26:41 +01007169
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007170 // If the integers have the same number of decimal digits they can be
7171 // compared directly as the numeric order is the same as the
7172 // lexicographic order. If one integer has fewer digits, it is scaled
7173 // by some power of 10 to have the same number of digits as the longer
7174 // integer. If the scaled integers are equal it means the shorter
7175 // integer comes first in the lexicographic order.
Steve Block44f0eee2011-05-26 01:26:41 +01007176
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007177 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7178 int x_log2 = IntegerLog2(x_scaled);
7179 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7180 x_log10 -= x_scaled < kPowersOf10[x_log10];
7181
7182 int y_log2 = IntegerLog2(y_scaled);
7183 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7184 y_log10 -= y_scaled < kPowersOf10[y_log10];
7185
7186 int tie = EQUAL;
7187
7188 if (x_log10 < y_log10) {
7189 // X has fewer digits. We would like to simply scale up X but that
7190 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7191 // be scaled up to 9_000_000_000. So we scale up by the next
7192 // smallest power and scale down Y to drop one digit. It is OK to
7193 // drop one digit from the longer integer since the final digit is
7194 // past the length of the shorter integer.
7195 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7196 y_scaled /= 10;
7197 tie = LESS;
7198 } else if (y_log10 < x_log10) {
7199 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7200 x_scaled /= 10;
7201 tie = GREATER;
Steve Blocka7e24c12009-10-30 11:49:00 +00007202 }
7203
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007204 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7205 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7206 return Smi::FromInt(tie);
Steve Blocka7e24c12009-10-30 11:49:00 +00007207}
7208
7209
Steve Block44f0eee2011-05-26 01:26:41 +01007210static Object* StringInputBufferCompare(RuntimeState* state,
7211 String* x,
7212 String* y) {
7213 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7214 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
Steve Block6ded16b2010-05-10 14:33:55 +01007215 bufx.Reset(x);
7216 bufy.Reset(y);
7217 while (bufx.has_more() && bufy.has_more()) {
7218 int d = bufx.GetNext() - bufy.GetNext();
7219 if (d < 0) return Smi::FromInt(LESS);
7220 else if (d > 0) return Smi::FromInt(GREATER);
7221 }
7222
7223 // x is (non-trivial) prefix of y:
7224 if (bufy.has_more()) return Smi::FromInt(LESS);
7225 // y is prefix of x:
7226 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7227}
7228
7229
7230static Object* FlatStringCompare(String* x, String* y) {
7231 ASSERT(x->IsFlat());
7232 ASSERT(y->IsFlat());
7233 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7234 int prefix_length = x->length();
7235 if (y->length() < prefix_length) {
7236 prefix_length = y->length();
7237 equal_prefix_result = Smi::FromInt(GREATER);
7238 } else if (y->length() > prefix_length) {
7239 equal_prefix_result = Smi::FromInt(LESS);
7240 }
7241 int r;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007242 String::FlatContent x_content = x->GetFlatContent();
7243 String::FlatContent y_content = y->GetFlatContent();
7244 if (x_content.IsAscii()) {
7245 Vector<const char> x_chars = x_content.ToAsciiVector();
7246 if (y_content.IsAscii()) {
7247 Vector<const char> y_chars = y_content.ToAsciiVector();
Steve Block6ded16b2010-05-10 14:33:55 +01007248 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7249 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007250 Vector<const uc16> y_chars = y_content.ToUC16Vector();
Steve Block6ded16b2010-05-10 14:33:55 +01007251 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7252 }
7253 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007254 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7255 if (y_content.IsAscii()) {
7256 Vector<const char> y_chars = y_content.ToAsciiVector();
Steve Block6ded16b2010-05-10 14:33:55 +01007257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7258 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007259 Vector<const uc16> y_chars = y_content.ToUC16Vector();
Steve Block6ded16b2010-05-10 14:33:55 +01007260 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7261 }
7262 }
7263 Object* result;
7264 if (r == 0) {
7265 result = equal_prefix_result;
7266 } else {
7267 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7268 }
Steve Block44f0eee2011-05-26 01:26:41 +01007269 ASSERT(result ==
7270 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
Steve Block6ded16b2010-05-10 14:33:55 +01007271 return result;
7272}
7273
7274
Ben Murdoch8b112d22011-06-08 16:22:53 +01007275RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007276 NoHandleAllocation ha;
7277 ASSERT(args.length() == 2);
7278
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007279 CONVERT_ARG_CHECKED(String, x, 0);
7280 CONVERT_ARG_CHECKED(String, y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007281
Steve Block44f0eee2011-05-26 01:26:41 +01007282 isolate->counters()->string_compare_runtime()->Increment();
Leon Clarkee46be812010-01-19 14:06:41 +00007283
Steve Blocka7e24c12009-10-30 11:49:00 +00007284 // A few fast case tests before we flatten.
7285 if (x == y) return Smi::FromInt(EQUAL);
7286 if (y->length() == 0) {
7287 if (x->length() == 0) return Smi::FromInt(EQUAL);
7288 return Smi::FromInt(GREATER);
7289 } else if (x->length() == 0) {
7290 return Smi::FromInt(LESS);
7291 }
7292
7293 int d = x->Get(0) - y->Get(0);
7294 if (d < 0) return Smi::FromInt(LESS);
7295 else if (d > 0) return Smi::FromInt(GREATER);
7296
John Reck59135872010-11-02 12:39:01 -07007297 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007298 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
John Reck59135872010-11-02 12:39:01 -07007299 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7300 }
Steve Block44f0eee2011-05-26 01:26:41 +01007301 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
John Reck59135872010-11-02 12:39:01 -07007302 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7303 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007304
Steve Block6ded16b2010-05-10 14:33:55 +01007305 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
Steve Block44f0eee2011-05-26 01:26:41 +01007306 : StringInputBufferCompare(isolate->runtime_state(), x, y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007307}
7308
7309
Ben Murdoch8b112d22011-06-08 16:22:53 +01007310RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007313 isolate->counters()->math_acos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007314
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007316 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007317}
7318
7319
Ben Murdoch8b112d22011-06-08 16:22:53 +01007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007323 isolate->counters()->math_asin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007324
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007326 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007327}
7328
7329
Ben Murdoch8b112d22011-06-08 16:22:53 +01007330RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007331 NoHandleAllocation ha;
7332 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007333 isolate->counters()->math_atan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007334
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007335 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007336 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007337}
7338
7339
Steve Block44f0eee2011-05-26 01:26:41 +01007340static const double kPiDividedBy4 = 0.78539816339744830962;
7341
7342
Ben Murdoch8b112d22011-06-08 16:22:53 +01007343RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007344 NoHandleAllocation ha;
7345 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01007346 isolate->counters()->math_atan2()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007347
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007348 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7349 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007350 double result;
7351 if (isinf(x) && isinf(y)) {
7352 // Make sure that the result in case of two infinite arguments
7353 // is a multiple of Pi / 4. The sign of the result is determined
7354 // by the first argument (x) and the sign of the second argument
7355 // determines the multiplier: one or three.
Steve Blocka7e24c12009-10-30 11:49:00 +00007356 int multiplier = (x < 0) ? -1 : 1;
7357 if (y < 0) multiplier *= 3;
7358 result = multiplier * kPiDividedBy4;
7359 } else {
7360 result = atan2(x, y);
7361 }
Steve Block44f0eee2011-05-26 01:26:41 +01007362 return isolate->heap()->AllocateHeapNumber(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007363}
7364
7365
Ben Murdoch8b112d22011-06-08 16:22:53 +01007366RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007369 isolate->counters()->math_ceil()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007370
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007372 return isolate->heap()->NumberFromDouble(ceiling(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007373}
7374
7375
Ben Murdoch8b112d22011-06-08 16:22:53 +01007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007379 isolate->counters()->math_cos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007380
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007382 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007383}
7384
7385
Ben Murdoch8b112d22011-06-08 16:22:53 +01007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007389 isolate->counters()->math_exp()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007390
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007392 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007393}
7394
7395
Ben Murdoch8b112d22011-06-08 16:22:53 +01007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007399 isolate->counters()->math_floor()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007400
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007402 return isolate->heap()->NumberFromDouble(floor(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007403}
7404
7405
Ben Murdoch8b112d22011-06-08 16:22:53 +01007406RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007407 NoHandleAllocation ha;
7408 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007409 isolate->counters()->math_log()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007410
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007411 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007412 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007413}
7414
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007415// Slow version of Math.pow. We check for fast paths for special cases.
7416// Used if SSE2/VFP3 is not available.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007417RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007418 NoHandleAllocation ha;
7419 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01007420 isolate->counters()->math_pow()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007421
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007422 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00007423
7424 // If the second argument is a smi, it is much faster to call the
7425 // custom powi() function than the generic pow().
7426 if (args[1]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007427 int y = args.smi_at(1);
Steve Block44f0eee2011-05-26 01:26:41 +01007428 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00007429 }
7430
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007431 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007432 int y_int = static_cast<int>(y);
7433 double result;
7434 if (y == y_int) {
7435 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7436 } else if (y == 0.5) {
7437 result = (isinf(x)) ? V8_INFINITY
7438 : fast_sqrt(x + 0.0); // Convert -0 to +0.
7439 } else if (y == -0.5) {
7440 result = (isinf(x)) ? 0
7441 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
7442 } else {
7443 result = power_double_double(x, y);
7444 }
7445 if (isnan(result)) return isolate->heap()->nan_value();
7446 return isolate->heap()->AllocateHeapNumber(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007447}
7448
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007449// Fast version of Math.pow if we know that y is not an integer and y is not
7450// -0.5 or 0.5. Used as slow case from full codegen.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007451RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
Steve Block6ded16b2010-05-10 14:33:55 +01007452 NoHandleAllocation ha;
7453 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007454 isolate->counters()->math_pow()->Increment();
7455
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007456 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7457 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block6ded16b2010-05-10 14:33:55 +01007458 if (y == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007459 return Smi::FromInt(1);
Steve Block6ded16b2010-05-10 14:33:55 +01007460 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007461 double result = power_double_double(x, y);
7462 if (isnan(result)) return isolate->heap()->nan_value();
7463 return isolate->heap()->AllocateHeapNumber(result);
Steve Block6ded16b2010-05-10 14:33:55 +01007464 }
7465}
Steve Blocka7e24c12009-10-30 11:49:00 +00007466
Steve Block6ded16b2010-05-10 14:33:55 +01007467
Ben Murdoch8b112d22011-06-08 16:22:53 +01007468RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007469 NoHandleAllocation ha;
7470 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007471 isolate->counters()->math_round()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007472
Steve Block6ded16b2010-05-10 14:33:55 +01007473 if (!args[0]->IsHeapNumber()) {
7474 // Must be smi. Return the argument unchanged for all the other types
7475 // to make fuzz-natives test happy.
7476 return args[0];
7477 }
7478
7479 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7480
7481 double value = number->value();
7482 int exponent = number->get_exponent();
7483 int sign = number->get_sign();
7484
Ben Murdoch257744e2011-11-30 15:57:28 +00007485 if (exponent < -1) {
7486 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7487 if (sign) return isolate->heap()->minus_zero_value();
7488 return Smi::FromInt(0);
7489 }
7490
7491 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7492 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007493 // argument holds for 32-bit smis).
Ben Murdoch257744e2011-11-30 15:57:28 +00007494 if (!sign && exponent < kSmiValueSize - 2) {
Steve Block6ded16b2010-05-10 14:33:55 +01007495 return Smi::FromInt(static_cast<int>(value + 0.5));
7496 }
7497
7498 // If the magnitude is big enough, there's no place for fraction part. If we
7499 // try to add 0.5 to this number, 1.0 will be added instead.
7500 if (exponent >= 52) {
7501 return number;
7502 }
7503
Steve Block44f0eee2011-05-26 01:26:41 +01007504 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007505
7506 // Do not call NumberFromDouble() to avoid extra checks.
Steve Block44f0eee2011-05-26 01:26:41 +01007507 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
Steve Blocka7e24c12009-10-30 11:49:00 +00007508}
7509
7510
Ben Murdoch8b112d22011-06-08 16:22:53 +01007511RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007512 NoHandleAllocation ha;
7513 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007514 isolate->counters()->math_sin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007515
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007516 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007517 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007518}
7519
7520
Ben Murdoch8b112d22011-06-08 16:22:53 +01007521RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007522 NoHandleAllocation ha;
7523 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007524 isolate->counters()->math_sqrt()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007525
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007526 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007527 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007528}
7529
7530
Ben Murdoch8b112d22011-06-08 16:22:53 +01007531RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007532 NoHandleAllocation ha;
7533 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007534 isolate->counters()->math_tan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007535
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007536 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007537 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007538}
7539
7540
Ben Murdoch85b71792012-04-11 18:30:58 +01007541RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
7542 NoHandleAllocation ha;
Ben Murdoch85b71792012-04-11 18:30:58 +01007543 ASSERT(args.length() == 2);
7544
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007545 CONVERT_SMI_ARG_CHECKED(year, 0);
7546 CONVERT_SMI_ARG_CHECKED(month, 1);
Ben Murdoch85b71792012-04-11 18:30:58 +01007547
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007548 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
7549}
Ben Murdoch85b71792012-04-11 18:30:58 +01007550
Ben Murdoch85b71792012-04-11 18:30:58 +01007551
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007552RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7553 HandleScope scope(isolate);
7554 ASSERT(args.length() == 3);
Ben Murdoch85b71792012-04-11 18:30:58 +01007555
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007556 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7557 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7558 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
7559
7560 DateCache* date_cache = isolate->date_cache();
7561
7562 Object* value = NULL;
7563 bool is_value_nan = false;
7564 if (isnan(time)) {
7565 value = isolate->heap()->nan_value();
7566 is_value_nan = true;
7567 } else if (!is_utc &&
7568 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7569 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7570 value = isolate->heap()->nan_value();
7571 is_value_nan = true;
7572 } else {
7573 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7574 if (time < -DateCache::kMaxTimeInMs ||
7575 time > DateCache::kMaxTimeInMs) {
7576 value = isolate->heap()->nan_value();
7577 is_value_nan = true;
7578 } else {
7579 MaybeObject* maybe_result =
7580 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7581 if (!maybe_result->ToObject(&value)) return maybe_result;
7582 }
7583 }
7584 date->SetValue(value, is_value_nan);
Ben Murdoch84774f42012-05-17 10:59:30 +01007585 return value;
Steve Block6ded16b2010-05-10 14:33:55 +01007586}
7587
7588
Ben Murdoch8b112d22011-06-08 16:22:53 +01007589RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007590 HandleScope scope(isolate);
7591 ASSERT(args.length() == 3);
7592
7593 Handle<JSFunction> callee = args.at<JSFunction>(0);
7594 Object** parameters = reinterpret_cast<Object**>(args[1]);
7595 const int argument_count = Smi::cast(args[2])->value();
7596
7597 Handle<JSObject> result =
7598 isolate->factory()->NewArgumentsObject(callee, argument_count);
7599 // Allocate the elements if needed.
7600 int parameter_count = callee->shared()->formal_parameter_count();
7601 if (argument_count > 0) {
7602 if (parameter_count > 0) {
7603 int mapped_count = Min(argument_count, parameter_count);
7604 Handle<FixedArray> parameter_map =
7605 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7606 parameter_map->set_map(
7607 isolate->heap()->non_strict_arguments_elements_map());
7608
7609 Handle<Map> old_map(result->map());
7610 Handle<Map> new_map =
7611 isolate->factory()->CopyMapDropTransitions(old_map);
Ben Murdoch589d6972011-11-30 16:04:58 +00007612 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007613
7614 result->set_map(*new_map);
7615 result->set_elements(*parameter_map);
7616
7617 // Store the context and the arguments array at the beginning of the
7618 // parameter map.
7619 Handle<Context> context(isolate->context());
7620 Handle<FixedArray> arguments =
7621 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7622 parameter_map->set(0, *context);
7623 parameter_map->set(1, *arguments);
7624
7625 // Loop over the actual parameters backwards.
7626 int index = argument_count - 1;
7627 while (index >= mapped_count) {
7628 // These go directly in the arguments array and have no
7629 // corresponding slot in the parameter map.
7630 arguments->set(index, *(parameters - index - 1));
7631 --index;
7632 }
7633
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007634 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007635 while (index >= 0) {
7636 // Detect duplicate names to the right in the parameter list.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007637 Handle<String> name(scope_info->ParameterName(index));
7638 int context_local_count = scope_info->ContextLocalCount();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007639 bool duplicate = false;
7640 for (int j = index + 1; j < parameter_count; ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007641 if (scope_info->ParameterName(j) == *name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007642 duplicate = true;
7643 break;
7644 }
7645 }
7646
7647 if (duplicate) {
7648 // This goes directly in the arguments array with a hole in the
7649 // parameter map.
7650 arguments->set(index, *(parameters - index - 1));
7651 parameter_map->set_the_hole(index + 2);
7652 } else {
7653 // The context index goes in the parameter map with a hole in the
7654 // arguments array.
7655 int context_index = -1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007656 for (int j = 0; j < context_local_count; ++j) {
7657 if (scope_info->ContextLocalName(j) == *name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007658 context_index = j;
7659 break;
7660 }
7661 }
7662 ASSERT(context_index >= 0);
7663 arguments->set_the_hole(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007664 parameter_map->set(index + 2, Smi::FromInt(
7665 Context::MIN_CONTEXT_SLOTS + context_index));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007666 }
7667
7668 --index;
7669 }
7670 } else {
7671 // If there is no aliasing, the arguments object elements are not
7672 // special in any way.
7673 Handle<FixedArray> elements =
7674 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7675 result->set_elements(*elements);
7676 for (int i = 0; i < argument_count; ++i) {
7677 elements->set(i, *(parameters - i - 1));
7678 }
7679 }
7680 }
7681 return *result;
7682}
7683
7684
7685RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007686 NoHandleAllocation ha;
7687 ASSERT(args.length() == 3);
7688
7689 JSFunction* callee = JSFunction::cast(args[0]);
7690 Object** parameters = reinterpret_cast<Object**>(args[1]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007691 const int length = args.smi_at(2);
Steve Blocka7e24c12009-10-30 11:49:00 +00007692
John Reck59135872010-11-02 12:39:01 -07007693 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01007694 { MaybeObject* maybe_result =
7695 isolate->heap()->AllocateArgumentsObject(callee, length);
John Reck59135872010-11-02 12:39:01 -07007696 if (!maybe_result->ToObject(&result)) return maybe_result;
7697 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007698 // Allocate the elements if needed.
7699 if (length > 0) {
7700 // Allocate the fixed array.
John Reck59135872010-11-02 12:39:01 -07007701 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007702 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07007703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7704 }
Leon Clarke4515c472010-02-03 11:58:03 +00007705
7706 AssertNoAllocation no_gc;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007707 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007708 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00007709 array->set_length(length);
Leon Clarke4515c472010-02-03 11:58:03 +00007710
7711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007712 for (int i = 0; i < length; i++) {
7713 array->set(i, *--parameters, mode);
7714 }
Steve Blockd0582a62009-12-15 09:54:21 +00007715 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00007716 }
7717 return result;
7718}
7719
7720
Ben Murdoch8b112d22011-06-08 16:22:53 +01007721RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
Steve Block44f0eee2011-05-26 01:26:41 +01007722 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007723 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007724 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7725 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7726 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00007727
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007728 // The caller ensures that we pretenure closures that are assigned
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007729 // directly to properties.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007730 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +00007731 Handle<JSFunction> result =
Steve Block44f0eee2011-05-26 01:26:41 +01007732 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7733 context,
7734 pretenure_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00007735 return *result;
7736}
7737
Ben Murdoch8b112d22011-06-08 16:22:53 +01007738
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007739// Find the arguments of the JavaScript function invocation that called
7740// into C++ code. Collect these in a newly allocated array of handles (possibly
7741// prefixed by a number of empty handles).
7742static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7743 int prefix_argc,
7744 int* total_argc) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007745 // Find frame containing arguments passed to the caller.
7746 JavaScriptFrameIterator it;
7747 JavaScriptFrame* frame = it.frame();
7748 List<JSFunction*> functions(2);
7749 frame->GetFunctions(&functions);
7750 if (functions.length() > 1) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007751 int inlined_jsframe_index = functions.length() - 1;
7752 JSFunction* inlined_function = functions[inlined_jsframe_index];
7753 Vector<SlotRef> args_slots =
7754 SlotRef::ComputeSlotMappingForArguments(
7755 frame,
7756 inlined_jsframe_index,
7757 inlined_function->shared()->formal_parameter_count());
Ben Murdochc7cc0282012-03-05 14:35:55 +00007758
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007759 int args_count = args_slots.length();
7760
7761 *total_argc = prefix_argc + args_count;
7762 SmartArrayPointer<Handle<Object> > param_data(
7763 NewArray<Handle<Object> >(*total_argc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01007764 for (int i = 0; i < args_count; i++) {
7765 Handle<Object> val = args_slots[i].GetValue();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007766 param_data[prefix_argc + i] = val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007767 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007768
7769 args_slots.Dispose();
7770
Ben Murdoch8b112d22011-06-08 16:22:53 +01007771 return param_data;
7772 } else {
7773 it.AdvanceToArgumentsFrame();
7774 frame = it.frame();
7775 int args_count = frame->ComputeParametersCount();
7776
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007777 *total_argc = prefix_argc + args_count;
7778 SmartArrayPointer<Handle<Object> > param_data(
7779 NewArray<Handle<Object> >(*total_argc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01007780 for (int i = 0; i < args_count; i++) {
7781 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007782 param_data[prefix_argc + i] = val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007783 }
7784 return param_data;
7785 }
7786}
7787
7788
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007789RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7790 HandleScope scope(isolate);
7791 ASSERT(args.length() == 4);
7792 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
7793 RUNTIME_ASSERT(args[3]->IsNumber());
7794 Handle<Object> bindee = args.at<Object>(1);
7795
7796 // TODO(lrn): Create bound function in C++ code from premade shared info.
7797 bound_function->shared()->set_bound(true);
7798 // Get all arguments of calling function (Function.prototype.bind).
7799 int argc = 0;
7800 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7801 // Don't count the this-arg.
7802 if (argc > 0) {
7803 ASSERT(*arguments[0] == args[2]);
7804 argc--;
7805 } else {
7806 ASSERT(args[2]->IsUndefined());
7807 }
7808 // Initialize array of bindings (function, this, and any existing arguments
7809 // if the function was already bound).
7810 Handle<FixedArray> new_bindings;
7811 int i;
7812 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7813 Handle<FixedArray> old_bindings(
7814 JSFunction::cast(*bindee)->function_bindings());
7815 new_bindings =
7816 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7817 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7818 i = 0;
7819 for (int n = old_bindings->length(); i < n; i++) {
7820 new_bindings->set(i, old_bindings->get(i));
7821 }
7822 } else {
7823 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7824 new_bindings = isolate->factory()->NewFixedArray(array_size);
7825 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7826 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7827 i = 2;
7828 }
7829 // Copy arguments, skipping the first which is "this_arg".
7830 for (int j = 0; j < argc; j++, i++) {
7831 new_bindings->set(i, *arguments[j + 1]);
7832 }
7833 new_bindings->set_map_no_write_barrier(
7834 isolate->heap()->fixed_cow_array_map());
7835 bound_function->set_function_bindings(*new_bindings);
7836
7837 // Update length.
7838 Handle<String> length_symbol = isolate->factory()->length_symbol();
7839 Handle<Object> new_length(args.at<Object>(3));
7840 PropertyAttributes attr =
7841 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7842 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7843 return *bound_function;
7844}
7845
7846
7847RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7848 HandleScope handles(isolate);
7849 ASSERT(args.length() == 1);
7850 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
7851 if (callable->IsJSFunction()) {
7852 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7853 if (function->shared()->bound()) {
7854 Handle<FixedArray> bindings(function->function_bindings());
7855 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7856 return *isolate->factory()->NewJSArrayWithElements(bindings);
7857 }
7858 }
7859 return isolate->heap()->undefined_value();
7860}
7861
7862
Ben Murdoch8b112d22011-06-08 16:22:53 +01007863RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
Steve Block44f0eee2011-05-26 01:26:41 +01007864 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007865 ASSERT(args.length() == 1);
Steve Block1e0659c2011-05-24 12:43:12 +01007866 // First argument is a function to use as a constructor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007867 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
7868 RUNTIME_ASSERT(function->shared()->bound());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007869
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007870 // The argument is a bound function. Extract its bound arguments
7871 // and callable.
7872 Handle<FixedArray> bound_args =
7873 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7874 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7875 Handle<Object> bound_function(
7876 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7877 ASSERT(!bound_function->IsJSFunction() ||
7878 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007879
Ben Murdoch8b112d22011-06-08 16:22:53 +01007880 int total_argc = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007881 SmartArrayPointer<Handle<Object> > param_data =
7882 GetCallerArguments(bound_argc, &total_argc);
Steve Block1e0659c2011-05-24 12:43:12 +01007883 for (int i = 0; i < bound_argc; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007884 param_data[i] = Handle<Object>(bound_args->get(
7885 JSFunction::kBoundArgumentsStartIndex + i));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007886 }
7887
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007888 if (!bound_function->IsJSFunction()) {
7889 bool exception_thrown;
7890 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7891 &exception_thrown);
7892 if (exception_thrown) return Failure::Exception();
7893 }
7894 ASSERT(bound_function->IsJSFunction());
7895
Ben Murdochbb769b22010-08-11 14:56:33 +01007896 bool exception = false;
Steve Block1e0659c2011-05-24 12:43:12 +01007897 Handle<Object> result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007898 Execution::New(Handle<JSFunction>::cast(bound_function),
7899 total_argc, *param_data, &exception);
Ben Murdochbb769b22010-08-11 14:56:33 +01007900 if (exception) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007901 return Failure::Exception();
Ben Murdochbb769b22010-08-11 14:56:33 +01007902 }
7903 ASSERT(!result.is_null());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007904 return *result;
7905}
7906
Steve Blocka7e24c12009-10-30 11:49:00 +00007907
Steve Block44f0eee2011-05-26 01:26:41 +01007908static void TrySettingInlineConstructStub(Isolate* isolate,
7909 Handle<JSFunction> function) {
7910 Handle<Object> prototype = isolate->factory()->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00007911 if (function->has_instance_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007912 prototype = Handle<Object>(function->instance_prototype(), isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00007913 }
7914 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007915 ConstructStubCompiler compiler(isolate);
7916 Handle<Code> code = compiler.CompileConstructStub(function);
7917 function->shared()->set_construct_stub(*code);
Steve Blocka7e24c12009-10-30 11:49:00 +00007918 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007919}
7920
7921
Ben Murdoch8b112d22011-06-08 16:22:53 +01007922RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
Steve Block44f0eee2011-05-26 01:26:41 +01007923 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007924 ASSERT(args.length() == 1);
7925
7926 Handle<Object> constructor = args.at<Object>(0);
7927
7928 // If the constructor isn't a proper function we throw a type error.
7929 if (!constructor->IsJSFunction()) {
7930 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7931 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007932 isolate->factory()->NewTypeError("not_constructor", arguments);
7933 return isolate->Throw(*type_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00007934 }
7935
7936 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
Steve Block6ded16b2010-05-10 14:33:55 +01007937
7938 // If function should not have prototype, construction is not allowed. In this
7939 // case generated code bailouts here, since function has no initial_map.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007940 if (!function->should_have_prototype() && !function->shared()->bound()) {
Steve Block6ded16b2010-05-10 14:33:55 +01007941 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7942 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007943 isolate->factory()->NewTypeError("not_constructor", arguments);
7944 return isolate->Throw(*type_error);
Steve Block6ded16b2010-05-10 14:33:55 +01007945 }
7946
Steve Blocka7e24c12009-10-30 11:49:00 +00007947#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01007948 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00007949 // Handle stepping into constructors if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01007950 if (debug->StepInActive()) {
7951 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007952 }
7953#endif
7954
7955 if (function->has_initial_map()) {
7956 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
7957 // The 'Function' function ignores the receiver object when
7958 // called using 'new' and creates a new JSFunction object that
7959 // is returned. The receiver object is only used for error
7960 // reporting if an error occurs when constructing the new
Steve Block44f0eee2011-05-26 01:26:41 +01007961 // JSFunction. FACTORY->NewJSObject() should not be used to
Steve Blocka7e24c12009-10-30 11:49:00 +00007962 // allocate JSFunctions since it does not properly initialize
7963 // the shared part of the function. Since the receiver is
7964 // ignored anyway, we use the global object as the receiver
7965 // instead of a new JSFunction object. This way, errors are
7966 // reported the same way whether or not 'Function' is called
7967 // using 'new'.
Steve Block44f0eee2011-05-26 01:26:41 +01007968 return isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00007969 }
7970 }
7971
Ben Murdochb0fe1622011-05-05 13:52:32 +01007972 // The function should be compiled for the optimization hints to be
7973 // available. We cannot use EnsureCompiled because that forces a
7974 // compilation through the shared function info which makes it
7975 // impossible for us to optimize.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007976 if (!function->is_compiled()) {
7977 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7978 }
Ben Murdoch85b71792012-04-11 18:30:58 +01007979
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007980 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007981 if (!function->has_initial_map() &&
7982 shared->IsInobjectSlackTrackingInProgress()) {
7983 // The tracking is already in progress for another function. We can only
7984 // track one initial_map at a time, so we force the completion before the
7985 // function is called as a constructor for the first time.
7986 shared->CompleteInobjectSlackTracking();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007987 }
7988
7989 bool first_allocation = !shared->live_objects_may_exist();
Steve Block44f0eee2011-05-26 01:26:41 +01007990 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7991 RETURN_IF_EMPTY_HANDLE(isolate, result);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007992 // Delay setting the stub if inobject slack tracking is in progress.
7993 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007994 TrySettingInlineConstructStub(isolate, function);
Steve Blocka7e24c12009-10-30 11:49:00 +00007995 }
7996
Steve Block44f0eee2011-05-26 01:26:41 +01007997 isolate->counters()->constructed_objects()->Increment();
7998 isolate->counters()->constructed_objects_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007999
8000 return *result;
8001}
8002
8003
Ben Murdoch8b112d22011-06-08 16:22:53 +01008004RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
Steve Block44f0eee2011-05-26 01:26:41 +01008005 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008006 ASSERT(args.length() == 1);
8007
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008009 function->shared()->CompleteInobjectSlackTracking();
Steve Block44f0eee2011-05-26 01:26:41 +01008010 TrySettingInlineConstructStub(isolate, function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008011
Steve Block44f0eee2011-05-26 01:26:41 +01008012 return isolate->heap()->undefined_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008013}
8014
8015
Ben Murdoch8b112d22011-06-08 16:22:53 +01008016RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01008017 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008018 ASSERT(args.length() == 1);
8019
8020 Handle<JSFunction> function = args.at<JSFunction>(0);
8021#ifdef DEBUG
Iain Merrick75681382010-08-19 15:07:18 +01008022 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008023 PrintF("[lazy: ");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008024 function->PrintName();
Steve Blocka7e24c12009-10-30 11:49:00 +00008025 PrintF("]\n");
8026 }
8027#endif
8028
Ben Murdoch589d6972011-11-30 16:04:58 +00008029 // Compile the target function.
Steve Blocka7e24c12009-10-30 11:49:00 +00008030 ASSERT(!function->is_compiled());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008031 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008032 return Failure::Exception();
8033 }
8034
Ben Murdochb0fe1622011-05-05 13:52:32 +01008035 // All done. Return the compiled code.
8036 ASSERT(function->is_compiled());
Steve Blocka7e24c12009-10-30 11:49:00 +00008037 return function->code();
8038}
8039
8040
Ben Murdoch8b112d22011-06-08 16:22:53 +01008041RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01008042 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008043 ASSERT(args.length() == 1);
8044 Handle<JSFunction> function = args.at<JSFunction>(0);
Ben Murdoch589d6972011-11-30 16:04:58 +00008045
8046 // If the function is not compiled ignore the lazy
8047 // recompilation. This can happen if the debugger is activated and
8048 // the function is returned to the not compiled state.
8049 if (!function->shared()->is_compiled()) {
8050 function->ReplaceCode(function->shared()->code());
8051 return function->code();
8052 }
8053
Ben Murdochb0fe1622011-05-05 13:52:32 +01008054 // If the function is not optimizable or debugger is active continue using the
8055 // code from the full compiler.
8056 if (!function->shared()->code()->optimizable() ||
Ben Murdoch257744e2011-11-30 15:57:28 +00008057 isolate->DebuggerHasBreakPoints()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01008058 if (FLAG_trace_opt) {
8059 PrintF("[failed to optimize ");
8060 function->PrintName();
8061 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8062 function->shared()->code()->optimizable() ? "T" : "F",
Ben Murdoch257744e2011-11-30 15:57:28 +00008063 isolate->DebuggerHasBreakPoints() ? "T" : "F");
Ben Murdochb8e0da22011-05-16 14:20:40 +01008064 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008065 function->ReplaceCode(function->shared()->code());
8066 return function->code();
8067 }
Ben Murdoch8f9999f2012-04-23 10:39:17 +01008068 function->shared()->code()->set_profiler_ticks(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008069 if (JSFunction::CompileOptimized(function,
8070 AstNode::kNoNumber,
8071 CLEAR_EXCEPTION)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008072 return function->code();
8073 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01008074 if (FLAG_trace_opt) {
8075 PrintF("[failed to optimize ");
8076 function->PrintName();
8077 PrintF(": optimized compilation failed]\n");
8078 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008079 function->ReplaceCode(function->shared()->code());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008080 return function->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008081}
8082
8083
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008084class ActivationsFinder : public ThreadVisitor {
8085 public:
8086 explicit ActivationsFinder(JSFunction* function)
8087 : function_(function), has_activations_(false) {}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008088
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008089 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8090 if (has_activations_) return;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008091
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008092 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8093 JavaScriptFrame* frame = it.frame();
8094 if (frame->is_optimized() && frame->function() == function_) {
8095 has_activations_ = true;
8096 return;
8097 }
8098 }
8099 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008100
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008101 bool has_activations() { return has_activations_; }
8102
8103 private:
8104 JSFunction* function_;
8105 bool has_activations_;
8106};
8107
8108
8109static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8110 JavaScriptFrame* frame) {
Steve Block44f0eee2011-05-26 01:26:41 +01008111 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008112 Handle<Object> arguments;
8113 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
Steve Block44f0eee2011-05-26 01:26:41 +01008114 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008115 if (arguments.is_null()) {
8116 // FunctionGetArguments can't throw an exception, so cast away the
8117 // doubt with an assert.
8118 arguments = Handle<Object>(
8119 Accessors::FunctionGetArguments(*function,
8120 NULL)->ToObjectUnchecked());
Steve Block44f0eee2011-05-26 01:26:41 +01008121 ASSERT(*arguments != isolate->heap()->null_value());
8122 ASSERT(*arguments != isolate->heap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008123 }
8124 frame->SetExpression(i, *arguments);
8125 }
8126 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008127}
8128
8129
8130RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8131 HandleScope scope(isolate);
8132 ASSERT(args.length() == 1);
8133 RUNTIME_ASSERT(args[0]->IsSmi());
8134 Deoptimizer::BailoutType type =
8135 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8136 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8137 ASSERT(isolate->heap()->IsAllocationAllowed());
8138 int jsframes = deoptimizer->jsframe_count();
8139
8140 deoptimizer->MaterializeHeapNumbers();
8141 delete deoptimizer;
8142
8143 JavaScriptFrameIterator it(isolate);
8144 for (int i = 0; i < jsframes - 1; i++) {
8145 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8146 it.Advance();
8147 }
8148
8149 JavaScriptFrame* frame = it.frame();
8150 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8151 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8152 MaterializeArgumentsObjectInFrame(isolate, frame);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008153
Ben Murdochb0fe1622011-05-05 13:52:32 +01008154 if (type == Deoptimizer::EAGER) {
8155 RUNTIME_ASSERT(function->IsOptimized());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008156 }
8157
8158 // Avoid doing too much work when running with --always-opt and keep
8159 // the optimized code around.
8160 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
Steve Block44f0eee2011-05-26 01:26:41 +01008161 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008162 }
8163
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008164 // Find other optimized activations of the function.
8165 bool has_other_activations = false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008166 while (!it.done()) {
8167 JavaScriptFrame* frame = it.frame();
8168 if (frame->is_optimized() && frame->function() == *function) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008169 has_other_activations = true;
8170 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008171 }
8172 it.Advance();
8173 }
8174
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008175 if (!has_other_activations) {
8176 ActivationsFinder activations_finder(*function);
8177 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8178 has_other_activations = activations_finder.has_activations();
8179 }
8180
8181 if (!has_other_activations) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008182 if (FLAG_trace_deopt) {
8183 PrintF("[removing optimized code for: ");
8184 function->PrintName();
8185 PrintF("]\n");
8186 }
8187 function->ReplaceCode(function->shared()->code());
Ben Murdoch589d6972011-11-30 16:04:58 +00008188 } else {
8189 Deoptimizer::DeoptimizeFunction(*function);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008190 }
Steve Block44f0eee2011-05-26 01:26:41 +01008191 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008192}
8193
8194
Ben Murdoch8b112d22011-06-08 16:22:53 +01008195RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
Steve Block44f0eee2011-05-26 01:26:41 +01008196 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008197 delete deoptimizer;
Steve Block44f0eee2011-05-26 01:26:41 +01008198 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008199}
8200
8201
Ben Murdoch8b112d22011-06-08 16:22:53 +01008202RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01008203 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008204 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008205 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01008206 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008207
8208 Deoptimizer::DeoptimizeFunction(*function);
8209
Steve Block44f0eee2011-05-26 01:26:41 +01008210 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008211}
8212
8213
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008214RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8215#if defined(USE_SIMULATOR)
8216 return isolate->heap()->true_value();
8217#else
8218 return isolate->heap()->false_value();
8219#endif
8220}
8221
8222
Ben Murdoch8b112d22011-06-08 16:22:53 +01008223RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8224 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008225 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8226 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8227
Ben Murdoch8b112d22011-06-08 16:22:53 +01008228 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8229 function->MarkForLazyRecompilation();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008230
8231 Code* unoptimized = function->shared()->code();
8232 if (args.length() == 2 &&
8233 unoptimized->kind() == Code::FUNCTION) {
8234 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8235 CHECK(type->IsEqualTo(CStrVector("osr")));
8236 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8237 unoptimized->set_allow_osr_at_loop_nesting_level(
8238 Code::kMaxLoopNestingMarker);
8239 }
8240
Ben Murdoch8b112d22011-06-08 16:22:53 +01008241 return isolate->heap()->undefined_value();
8242}
8243
8244
Ben Murdoch257744e2011-11-30 15:57:28 +00008245RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8246 HandleScope scope(isolate);
8247 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008248 // The least significant bit (after untagging) indicates whether the
8249 // function is currently optimized, regardless of reason.
Ben Murdoch257744e2011-11-30 15:57:28 +00008250 if (!V8::UseCrankshaft()) {
8251 return Smi::FromInt(4); // 4 == "never".
8252 }
8253 if (FLAG_always_opt) {
8254 return Smi::FromInt(3); // 3 == "always".
8255 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008256 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdoch257744e2011-11-30 15:57:28 +00008257 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8258 : Smi::FromInt(2); // 2 == "no".
8259}
8260
8261
8262RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8263 HandleScope scope(isolate);
8264 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008265 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdoch257744e2011-11-30 15:57:28 +00008266 return Smi::FromInt(function->shared()->opt_count());
8267}
8268
8269
Ben Murdoch8b112d22011-06-08 16:22:53 +01008270RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
Steve Block44f0eee2011-05-26 01:26:41 +01008271 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008272 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008273 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008274
8275 // We're not prepared to handle a function with arguments object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008276 ASSERT(!function->shared()->uses_arguments());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008277
8278 // We have hit a back edge in an unoptimized frame for a function that was
8279 // selected for on-stack replacement. Find the unoptimized code object.
Steve Block44f0eee2011-05-26 01:26:41 +01008280 Handle<Code> unoptimized(function->shared()->code(), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008281 // Keep track of whether we've succeeded in optimizing.
8282 bool succeeded = unoptimized->optimizable();
8283 if (succeeded) {
8284 // If we are trying to do OSR when there are already optimized
8285 // activations of the function, it means (a) the function is directly or
8286 // indirectly recursive and (b) an optimized invocation has been
8287 // deoptimized so that we are currently in an unoptimized activation.
8288 // Check for optimized activations of this function.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008289 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008290 while (succeeded && !it.done()) {
8291 JavaScriptFrame* frame = it.frame();
8292 succeeded = !frame->is_optimized() || frame->function() != *function;
8293 it.Advance();
8294 }
8295 }
8296
8297 int ast_id = AstNode::kNoNumber;
8298 if (succeeded) {
8299 // The top JS function is this one, the PC is somewhere in the
8300 // unoptimized code.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008301 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008302 JavaScriptFrame* frame = it.frame();
8303 ASSERT(frame->function() == *function);
Ben Murdoch8b112d22011-06-08 16:22:53 +01008304 ASSERT(frame->LookupCode() == *unoptimized);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008305 ASSERT(unoptimized->contains(frame->pc()));
8306
8307 // Use linear search of the unoptimized code's stack check table to find
8308 // the AST id matching the PC.
8309 Address start = unoptimized->instruction_start();
8310 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
Steve Block1e0659c2011-05-24 12:43:12 +01008311 Address table_cursor = start + unoptimized->stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008312 uint32_t table_length = Memory::uint32_at(table_cursor);
8313 table_cursor += kIntSize;
8314 for (unsigned i = 0; i < table_length; ++i) {
8315 // Table entries are (AST id, pc offset) pairs.
8316 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8317 if (pc_offset == target_pc_offset) {
8318 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8319 break;
8320 }
8321 table_cursor += 2 * kIntSize;
8322 }
8323 ASSERT(ast_id != AstNode::kNoNumber);
8324 if (FLAG_trace_osr) {
8325 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8326 function->PrintName();
8327 PrintF("]\n");
8328 }
8329
8330 // Try to compile the optimized code. A true return value from
8331 // CompileOptimized means that compilation succeeded, not necessarily
8332 // that optimization succeeded.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008333 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008334 function->IsOptimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008335 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8336 function->code()->deoptimization_data());
8337 if (data->OsrPcOffset()->value() >= 0) {
8338 if (FLAG_trace_osr) {
8339 PrintF("[on-stack replacement offset %d in optimized code]\n",
8340 data->OsrPcOffset()->value());
8341 }
8342 ASSERT(data->OsrAstId()->value() == ast_id);
8343 } else {
8344 // We may never generate the desired OSR entry if we emit an
8345 // early deoptimize.
8346 succeeded = false;
8347 }
8348 } else {
8349 succeeded = false;
8350 }
8351 }
8352
8353 // Revert to the original stack checks in the original unoptimized code.
8354 if (FLAG_trace_osr) {
8355 PrintF("[restoring original stack checks in ");
8356 function->PrintName();
8357 PrintF("]\n");
8358 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008359 Handle<Code> check_code;
8360#if defined(V8_TARGET_ARCH_IA32) || \
8361 defined(V8_TARGET_ARCH_ARM) || \
8362 defined(V8_TARGET_ARCH_MIPS)
8363 if (FLAG_count_based_interrupts) {
8364 InterruptStub interrupt_stub;
8365 check_code = interrupt_stub.GetCode();
8366 } else // NOLINT
8367#endif
8368 { // NOLINT
8369 StackCheckStub check_stub;
8370 check_code = check_stub.GetCode();
8371 }
Steve Block44f0eee2011-05-26 01:26:41 +01008372 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
Steve Block1e0659c2011-05-24 12:43:12 +01008373 Deoptimizer::RevertStackCheckCode(*unoptimized,
8374 *check_code,
8375 *replacement_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008376
8377 // Allow OSR only at nesting level zero again.
8378 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8379
8380 // If the optimization attempt succeeded, return the AST id tagged as a
8381 // smi. This tells the builtin that we need to translate the unoptimized
8382 // frame to an optimized one.
8383 if (succeeded) {
8384 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8385 return Smi::FromInt(ast_id);
8386 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008387 if (function->IsMarkedForLazyRecompilation()) {
8388 function->ReplaceCode(function->shared()->code());
8389 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008390 return Smi::FromInt(-1);
8391 }
8392}
8393
8394
Ben Murdoch589d6972011-11-30 16:04:58 +00008395RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8396 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8397 return isolate->heap()->undefined_value();
8398}
8399
8400
Ben Murdochdb1b4382012-04-26 19:03:50 +01008401RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8402 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8403 return isolate->heap()->nan_value();
8404}
8405
8406
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008407RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8408 HandleScope scope(isolate);
8409 ASSERT(args.length() >= 2);
8410 int argc = args.length() - 2;
8411 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8412 Object* receiver = args[0];
8413
8414 // If there are too many arguments, allocate argv via malloc.
8415 const int argv_small_size = 10;
8416 Handle<Object> argv_small_buffer[argv_small_size];
8417 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8418 Handle<Object>* argv = argv_small_buffer;
8419 if (argc > argv_small_size) {
8420 argv = new Handle<Object>[argc];
8421 if (argv == NULL) return isolate->StackOverflow();
8422 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8423 }
8424
8425 for (int i = 0; i < argc; ++i) {
8426 MaybeObject* maybe = args[1 + i];
8427 Object* object;
8428 if (!maybe->To<Object>(&object)) return maybe;
8429 argv[i] = Handle<Object>(object);
8430 }
8431
8432 bool threw;
8433 Handle<JSReceiver> hfun(fun);
8434 Handle<Object> hreceiver(receiver);
8435 Handle<Object> result =
8436 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8437
8438 if (threw) return Failure::Exception();
8439 return *result;
8440}
8441
8442
Ben Murdoch589d6972011-11-30 16:04:58 +00008443RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8444 HandleScope scope(isolate);
8445 ASSERT(args.length() == 5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008446 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
8447 Handle<Object> receiver = args.at<Object>(1);
8448 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
8449 CONVERT_SMI_ARG_CHECKED(offset, 3);
8450 CONVERT_SMI_ARG_CHECKED(argc, 4);
Ben Murdoch589d6972011-11-30 16:04:58 +00008451 ASSERT(offset >= 0);
8452 ASSERT(argc >= 0);
8453
8454 // If there are too many arguments, allocate argv via malloc.
8455 const int argv_small_size = 10;
8456 Handle<Object> argv_small_buffer[argv_small_size];
8457 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8458 Handle<Object>* argv = argv_small_buffer;
8459 if (argc > argv_small_size) {
8460 argv = new Handle<Object>[argc];
8461 if (argv == NULL) return isolate->StackOverflow();
8462 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8463 }
8464
8465 for (int i = 0; i < argc; ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008466 argv[i] = Object::GetElement(arguments, offset + i);
Ben Murdoch589d6972011-11-30 16:04:58 +00008467 }
8468
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008469 bool threw;
8470 Handle<Object> result =
8471 Execution::Call(fun, receiver, argc, argv, &threw, true);
Ben Murdoch589d6972011-11-30 16:04:58 +00008472
8473 if (threw) return Failure::Exception();
8474 return *result;
8475}
8476
8477
Ben Murdoch8b112d22011-06-08 16:22:53 +01008478RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008479 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008480 ASSERT(args.length() == 1);
8481 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8482 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8483}
8484
8485
Ben Murdoch8b112d22011-06-08 16:22:53 +01008486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008487 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008488 ASSERT(args.length() == 1);
8489 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8490 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8491}
8492
8493
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008494RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008495 NoHandleAllocation ha;
8496 ASSERT(args.length() == 1);
8497
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008498 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8499 int length = function->shared()->scope_info()->ContextLength();
John Reck59135872010-11-02 12:39:01 -07008500 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01008501 { MaybeObject* maybe_result =
8502 isolate->heap()->AllocateFunctionContext(length, function);
John Reck59135872010-11-02 12:39:01 -07008503 if (!maybe_result->ToObject(&result)) return maybe_result;
8504 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008505
Steve Block44f0eee2011-05-26 01:26:41 +01008506 isolate->set_context(Context::cast(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00008507
8508 return result; // non-failure
8509}
8510
John Reck59135872010-11-02 12:39:01 -07008511
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8513 NoHandleAllocation ha;
8514 ASSERT(args.length() == 2);
8515 JSObject* extension_object;
8516 if (args[0]->IsJSObject()) {
8517 extension_object = JSObject::cast(args[0]);
8518 } else {
8519 // Convert the object to a proper JavaScript object.
8520 MaybeObject* maybe_js_object = args[0]->ToObject();
8521 if (!maybe_js_object->To(&extension_object)) {
8522 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8523 HandleScope scope(isolate);
8524 Handle<Object> handle = args.at<Object>(0);
8525 Handle<Object> result =
8526 isolate->factory()->NewTypeError("with_expression",
8527 HandleVector(&handle, 1));
8528 return isolate->Throw(*result);
8529 } else {
John Reck59135872010-11-02 12:39:01 -07008530 return maybe_js_object;
8531 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008532 }
8533 }
8534
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008535 JSFunction* function;
8536 if (args[1]->IsSmi()) {
8537 // A smi sentinel indicates a context nested inside global code rather
8538 // than some function. There is a canonical empty function that can be
8539 // gotten from the global context.
8540 function = isolate->context()->global_context()->closure();
8541 } else {
8542 function = JSFunction::cast(args[1]);
John Reck59135872010-11-02 12:39:01 -07008543 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008544
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008545 Context* context;
8546 MaybeObject* maybe_context =
8547 isolate->heap()->AllocateWithContext(function,
8548 isolate->context(),
8549 extension_object);
8550 if (!maybe_context->To(&context)) return maybe_context;
Steve Block44f0eee2011-05-26 01:26:41 +01008551 isolate->set_context(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008552 return context;
Steve Blocka7e24c12009-10-30 11:49:00 +00008553}
8554
8555
Ben Murdoch8b112d22011-06-08 16:22:53 +01008556RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008557 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008558 ASSERT(args.length() == 3);
8559 String* name = String::cast(args[0]);
8560 Object* thrown_object = args[1];
8561 JSFunction* function;
8562 if (args[2]->IsSmi()) {
8563 // A smi sentinel indicates a context nested inside global code rather
8564 // than some function. There is a canonical empty function that can be
8565 // gotten from the global context.
8566 function = isolate->context()->global_context()->closure();
8567 } else {
8568 function = JSFunction::cast(args[2]);
8569 }
8570 Context* context;
8571 MaybeObject* maybe_context =
8572 isolate->heap()->AllocateCatchContext(function,
8573 isolate->context(),
8574 name,
8575 thrown_object);
8576 if (!maybe_context->To(&context)) return maybe_context;
8577 isolate->set_context(context);
8578 return context;
Steve Blocka7e24c12009-10-30 11:49:00 +00008579}
8580
8581
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8583 NoHandleAllocation ha;
8584 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008585 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008586 JSFunction* function;
8587 if (args[1]->IsSmi()) {
8588 // A smi sentinel indicates a context nested inside global code rather
8589 // than some function. There is a canonical empty function that can be
8590 // gotten from the global context.
8591 function = isolate->context()->global_context()->closure();
8592 } else {
8593 function = JSFunction::cast(args[1]);
8594 }
8595 Context* context;
8596 MaybeObject* maybe_context =
8597 isolate->heap()->AllocateBlockContext(function,
8598 isolate->context(),
8599 scope_info);
8600 if (!maybe_context->To(&context)) return maybe_context;
8601 isolate->set_context(context);
8602 return context;
8603}
8604
8605
Ben Murdoch8b112d22011-06-08 16:22:53 +01008606RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01008607 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008608 ASSERT(args.length() == 2);
8609
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008610 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8611 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00008612
8613 int index;
8614 PropertyAttributes attributes;
8615 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008616 BindingFlags binding_flags;
8617 Handle<Object> holder = context->Lookup(name,
8618 flags,
8619 &index,
8620 &attributes,
8621 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008622
Steve Block1e0659c2011-05-24 12:43:12 +01008623 // If the slot was not found the result is true.
8624 if (holder.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008625 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008626 }
8627
Steve Block1e0659c2011-05-24 12:43:12 +01008628 // If the slot was found in a context, it should be DONT_DELETE.
8629 if (holder->IsContext()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008630 return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +01008631 }
8632
8633 // The slot was found in a JSObject, either a context extension object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008634 // the global object, or the subject of a with. Try to delete it
8635 // (respecting DONT_DELETE).
Steve Block1e0659c2011-05-24 12:43:12 +01008636 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008637 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00008638}
8639
8640
8641// A mechanism to return a pair of Object pointers in registers (if possible).
8642// How this is achieved is calling convention-dependent.
8643// All currently supported x86 compiles uses calling conventions that are cdecl
8644// variants where a 64-bit value is returned in two 32-bit registers
8645// (edx:eax on ia32, r1:r0 on ARM).
8646// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8647// In Win64 calling convention, a struct of two pointers is returned in memory,
8648// allocated by the caller, and passed as a pointer in a hidden first parameter.
8649#ifdef V8_HOST_ARCH_64_BIT
8650struct ObjectPair {
John Reck59135872010-11-02 12:39:01 -07008651 MaybeObject* x;
8652 MaybeObject* y;
Steve Blocka7e24c12009-10-30 11:49:00 +00008653};
8654
John Reck59135872010-11-02 12:39:01 -07008655static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008656 ObjectPair result = {x, y};
8657 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8658 // In Win64 they are assigned to a hidden first argument.
8659 return result;
8660}
8661#else
8662typedef uint64_t ObjectPair;
John Reck59135872010-11-02 12:39:01 -07008663static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008664 return reinterpret_cast<uint32_t>(x) |
8665 (reinterpret_cast<ObjectPair>(y) << 32);
8666}
8667#endif
8668
8669
Steve Block44f0eee2011-05-26 01:26:41 +01008670static inline MaybeObject* Unhole(Heap* heap,
8671 MaybeObject* x,
John Reck59135872010-11-02 12:39:01 -07008672 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008673 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8674 USE(attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01008675 return x->IsTheHole() ? heap->undefined_value() : x;
Steve Blocka7e24c12009-10-30 11:49:00 +00008676}
8677
8678
Ben Murdoch257744e2011-11-30 15:57:28 +00008679static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8680 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008681 ASSERT(!holder->IsGlobalObject());
Steve Block44f0eee2011-05-26 01:26:41 +01008682 Context* top = isolate->context();
Steve Blocka7e24c12009-10-30 11:49:00 +00008683 // Get the context extension function.
8684 JSFunction* context_extension_function =
8685 top->global_context()->context_extension_function();
8686 // If the holder isn't a context extension object, we just return it
8687 // as the receiver. This allows arguments objects to be used as
8688 // receivers, but only if they are put in the context scope chain
8689 // explicitly via a with-statement.
8690 Object* constructor = holder->map()->constructor();
8691 if (constructor != context_extension_function) return holder;
Ben Murdoch257744e2011-11-30 15:57:28 +00008692 // Fall back to using the global object as the implicit receiver if
8693 // the property turns out to be a local variable allocated in a
8694 // context extension object - introduced via eval. Implicit global
8695 // receivers are indicated with the hole value.
8696 return isolate->heap()->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008697}
8698
8699
Steve Block44f0eee2011-05-26 01:26:41 +01008700static ObjectPair LoadContextSlotHelper(Arguments args,
8701 Isolate* isolate,
8702 bool throw_error) {
8703 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008704 ASSERT_EQ(2, args.length());
8705
8706 if (!args[0]->IsContext() || !args[1]->IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008707 return MakePair(isolate->ThrowIllegalOperation(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008708 }
8709 Handle<Context> context = args.at<Context>(0);
8710 Handle<String> name = args.at<String>(1);
8711
8712 int index;
8713 PropertyAttributes attributes;
8714 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008715 BindingFlags binding_flags;
8716 Handle<Object> holder = context->Lookup(name,
8717 flags,
8718 &index,
8719 &attributes,
8720 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008721
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008722 // If the index is non-negative, the slot has been found in a context.
Steve Blocka7e24c12009-10-30 11:49:00 +00008723 if (index >= 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008724 ASSERT(holder->IsContext());
8725 // If the "property" we were looking for is a local variable, the
8726 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
Ben Murdoch257744e2011-11-30 15:57:28 +00008727 //
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008728 // Use the hole as the receiver to signal that the receiver is implicit
8729 // and that the global receiver should be used (as distinguished from an
8730 // explicit receiver that happens to be a global object).
Ben Murdoch257744e2011-11-30 15:57:28 +00008731 Handle<Object> receiver = isolate->factory()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008732 Object* value = Context::cast(*holder)->get(index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008733 // Check for uninitialized bindings.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008734 switch (binding_flags) {
8735 case MUTABLE_CHECK_INITIALIZED:
8736 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8737 if (value->IsTheHole()) {
8738 Handle<Object> reference_error =
8739 isolate->factory()->NewReferenceError("not_defined",
8740 HandleVector(&name, 1));
8741 return MakePair(isolate->Throw(*reference_error), NULL);
8742 }
8743 // FALLTHROUGH
8744 case MUTABLE_IS_INITIALIZED:
8745 case IMMUTABLE_IS_INITIALIZED:
8746 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8747 ASSERT(!value->IsTheHole());
8748 return MakePair(value, *receiver);
8749 case IMMUTABLE_CHECK_INITIALIZED:
8750 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8751 case MISSING_BINDING:
8752 UNREACHABLE();
8753 return MakePair(NULL, NULL);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008754 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008755 }
8756
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008757 // Otherwise, if the slot was found the holder is a context extension
8758 // object, subject of a with, or a global object. We read the named
8759 // property from it.
8760 if (!holder.is_null()) {
8761 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8762 ASSERT(object->HasProperty(*name));
Ben Murdoch85b71792012-04-11 18:30:58 +01008763 // GetProperty below can cause GC.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008764 Handle<Object> receiver_handle(object->IsGlobalObject()
8765 ? GlobalObject::cast(*object)->global_receiver()
8766 : ComputeReceiverForNonGlobal(isolate, *object));
Ben Murdoch85b71792012-04-11 18:30:58 +01008767
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008768 // No need to unhole the value here. This is taken care of by the
Steve Blocka7e24c12009-10-30 11:49:00 +00008769 // GetProperty function.
John Reck59135872010-11-02 12:39:01 -07008770 MaybeObject* value = object->GetProperty(*name);
Ben Murdoch257744e2011-11-30 15:57:28 +00008771 return MakePair(value, *receiver_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +00008772 }
8773
8774 if (throw_error) {
8775 // The property doesn't exist - throw exception.
8776 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01008777 isolate->factory()->NewReferenceError("not_defined",
8778 HandleVector(&name, 1));
8779 return MakePair(isolate->Throw(*reference_error), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008780 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00008781 // The property doesn't exist - return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +01008782 return MakePair(isolate->heap()->undefined_value(),
8783 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008784 }
8785}
8786
8787
Ben Murdoch8b112d22011-06-08 16:22:53 +01008788RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01008789 return LoadContextSlotHelper(args, isolate, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00008790}
8791
8792
Ben Murdoch8b112d22011-06-08 16:22:53 +01008793RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01008794 return LoadContextSlotHelper(args, isolate, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00008795}
8796
8797
Ben Murdoch8b112d22011-06-08 16:22:53 +01008798RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01008799 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008800 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00008801
Steve Block44f0eee2011-05-26 01:26:41 +01008802 Handle<Object> value(args[0], isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008803 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8804 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
8805 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8806 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8807 ? kNonStrictMode : kStrictMode;
Steve Blocka7e24c12009-10-30 11:49:00 +00008808
8809 int index;
8810 PropertyAttributes attributes;
8811 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008812 BindingFlags binding_flags;
8813 Handle<Object> holder = context->Lookup(name,
8814 flags,
8815 &index,
8816 &attributes,
8817 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008818
8819 if (index >= 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008820 // The property was found in a context slot.
8821 Handle<Context> context = Handle<Context>::cast(holder);
8822 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8823 context->get(index)->IsTheHole()) {
8824 Handle<Object> error =
8825 isolate->factory()->NewReferenceError("not_defined",
8826 HandleVector(&name, 1));
8827 return isolate->Throw(*error);
8828 }
8829 // Ignore if read_only variable.
8830 if ((attributes & READ_ONLY) == 0) {
8831 // Context is a fixed array and set cannot fail.
8832 context->set(index, *value);
8833 } else if (strict_mode == kStrictMode) {
8834 // Setting read only property in strict mode.
8835 Handle<Object> error =
8836 isolate->factory()->NewTypeError("strict_cannot_assign",
8837 HandleVector(&name, 1));
8838 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00008839 }
8840 return *value;
8841 }
8842
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008843 // Slow case: The property is not in a context slot. It is either in a
8844 // context extension object, a property of the subject of a with, or a
8845 // property of the global object.
8846 Handle<JSObject> object;
Steve Blocka7e24c12009-10-30 11:49:00 +00008847
8848 if (!holder.is_null()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008849 // The property exists on the holder.
8850 object = Handle<JSObject>::cast(holder);
Steve Blocka7e24c12009-10-30 11:49:00 +00008851 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008852 // The property was not found.
Steve Blocka7e24c12009-10-30 11:49:00 +00008853 ASSERT(attributes == ABSENT);
Ben Murdoch8b112d22011-06-08 16:22:53 +01008854
8855 if (strict_mode == kStrictMode) {
8856 // Throw in strict mode (assignment to undefined variable).
8857 Handle<Object> error =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008858 isolate->factory()->NewReferenceError(
8859 "not_defined", HandleVector(&name, 1));
Ben Murdoch8b112d22011-06-08 16:22:53 +01008860 return isolate->Throw(*error);
8861 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008862 // In non-strict mode, the property is added to the global object.
Steve Blocka7e24c12009-10-30 11:49:00 +00008863 attributes = NONE;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008864 object = Handle<JSObject>(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00008865 }
8866
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008867 // Set the property if it's not read only or doesn't yet exist.
Steve Blocka7e24c12009-10-30 11:49:00 +00008868 if ((attributes & READ_ONLY) == 0 ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008869 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008870 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01008871 isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008872 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008873 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
8874 // Setting read only property in strict mode.
8875 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01008876 isolate->factory()->NewTypeError(
8877 "strict_cannot_assign", HandleVector(&name, 1));
8878 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00008879 }
8880 return *value;
8881}
8882
8883
Ben Murdoch8b112d22011-06-08 16:22:53 +01008884RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
Steve Block44f0eee2011-05-26 01:26:41 +01008885 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008886 ASSERT(args.length() == 1);
8887
Steve Block44f0eee2011-05-26 01:26:41 +01008888 return isolate->Throw(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00008889}
8890
8891
Ben Murdoch8b112d22011-06-08 16:22:53 +01008892RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
Steve Block44f0eee2011-05-26 01:26:41 +01008893 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008894 ASSERT(args.length() == 1);
8895
Steve Block44f0eee2011-05-26 01:26:41 +01008896 return isolate->ReThrow(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00008897}
8898
8899
Ben Murdoch8b112d22011-06-08 16:22:53 +01008900RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
Steve Blockd0582a62009-12-15 09:54:21 +00008901 ASSERT_EQ(0, args.length());
Steve Block44f0eee2011-05-26 01:26:41 +01008902 return isolate->PromoteScheduledException();
Steve Blockd0582a62009-12-15 09:54:21 +00008903}
8904
8905
Ben Murdoch8b112d22011-06-08 16:22:53 +01008906RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01008907 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008908 ASSERT(args.length() == 1);
8909
Steve Block44f0eee2011-05-26 01:26:41 +01008910 Handle<Object> name(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008911 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01008912 isolate->factory()->NewReferenceError("not_defined",
8913 HandleVector(&name, 1));
8914 return isolate->Throw(*reference_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00008915}
8916
8917
Ben Murdoch8b112d22011-06-08 16:22:53 +01008918RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
Ben Murdochf87a2032010-10-22 12:50:53 +01008919 ASSERT(args.length() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008920
8921 // First check if this is a real stack overflow.
Steve Block44f0eee2011-05-26 01:26:41 +01008922 if (isolate->stack_guard()->IsStackOverflow()) {
8923 NoHandleAllocation na;
8924 return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +00008925 }
8926
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008927 return Execution::HandleStackGuardInterrupt(isolate);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01008928}
8929
8930
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008931RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8932 ASSERT(args.length() == 0);
8933 return Execution::HandleStackGuardInterrupt(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008934}
8935
8936
Steve Blocka7e24c12009-10-30 11:49:00 +00008937static int StackSize() {
8938 int n = 0;
8939 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8940 return n;
8941}
8942
8943
8944static void PrintTransition(Object* result) {
8945 // indentation
8946 { const int nmax = 80;
8947 int n = StackSize();
8948 if (n <= nmax)
8949 PrintF("%4d:%*s", n, n, "");
8950 else
8951 PrintF("%4d:%*s", n, nmax, "...");
8952 }
8953
8954 if (result == NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008955 JavaScriptFrame::PrintTop(stdout, true, false);
8956 PrintF(" {\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008957 } else {
8958 // function result
8959 PrintF("} -> ");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008960 result->ShortPrint();
Steve Blocka7e24c12009-10-30 11:49:00 +00008961 PrintF("\n");
8962 }
8963}
8964
8965
Ben Murdoch8b112d22011-06-08 16:22:53 +01008966RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008967 ASSERT(args.length() == 0);
8968 NoHandleAllocation ha;
8969 PrintTransition(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01008970 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008971}
8972
8973
Ben Murdoch8b112d22011-06-08 16:22:53 +01008974RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008975 NoHandleAllocation ha;
8976 PrintTransition(args[0]);
8977 return args[0]; // return TOS
8978}
8979
8980
Ben Murdoch8b112d22011-06-08 16:22:53 +01008981RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008982 NoHandleAllocation ha;
8983 ASSERT(args.length() == 1);
8984
8985#ifdef DEBUG
8986 if (args[0]->IsString()) {
8987 // If we have a string, assume it's a code "marker"
8988 // and print some interesting cpu debugging info.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008989 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008990 JavaScriptFrame* frame = it.frame();
8991 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8992 frame->fp(), frame->sp(), frame->caller_sp());
8993 } else {
8994 PrintF("DebugPrint: ");
8995 }
8996 args[0]->Print();
Steve Blockd0582a62009-12-15 09:54:21 +00008997 if (args[0]->IsHeapObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01008998 PrintF("\n");
Steve Blockd0582a62009-12-15 09:54:21 +00008999 HeapObject::cast(args[0])->map()->Print();
9000 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009001#else
9002 // ShortPrint is available in release mode. Print is not.
9003 args[0]->ShortPrint();
9004#endif
9005 PrintF("\n");
9006 Flush();
9007
9008 return args[0]; // return TOS
9009}
9010
9011
Ben Murdoch8b112d22011-06-08 16:22:53 +01009012RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009013 ASSERT(args.length() == 0);
9014 NoHandleAllocation ha;
Steve Block44f0eee2011-05-26 01:26:41 +01009015 isolate->PrintStack();
9016 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009017}
9018
9019
Ben Murdoch8b112d22011-06-08 16:22:53 +01009020RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009021 NoHandleAllocation ha;
9022 ASSERT(args.length() == 0);
9023
9024 // According to ECMA-262, section 15.9.1, page 117, the precision of
9025 // the number in a Date object representing a particular instant in
9026 // time is milliseconds. Therefore, we floor the result of getting
9027 // the OS time.
9028 double millis = floor(OS::TimeCurrentMillis());
Steve Block44f0eee2011-05-26 01:26:41 +01009029 return isolate->heap()->NumberFromDouble(millis);
Steve Blocka7e24c12009-10-30 11:49:00 +00009030}
9031
9032
Ben Murdoch8b112d22011-06-08 16:22:53 +01009033RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
Steve Block44f0eee2011-05-26 01:26:41 +01009034 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009035 ASSERT(args.length() == 2);
9036
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009037 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009038 FlattenString(str);
9039
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009040 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
9041
9042 MaybeObject* maybe_result_array =
9043 output->EnsureCanContainHeapObjectElements();
9044 if (maybe_result_array->IsFailure()) return maybe_result_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00009045 RUNTIME_ASSERT(output->HasFastElements());
9046
9047 AssertNoAllocation no_allocation;
9048
9049 FixedArray* output_array = FixedArray::cast(output->elements());
9050 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9051 bool result;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009052 String::FlatContent str_content = str->GetFlatContent();
9053 if (str_content.IsAscii()) {
9054 result = DateParser::Parse(str_content.ToAsciiVector(),
Ben Murdoch8b112d22011-06-08 16:22:53 +01009055 output_array,
9056 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00009057 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009058 ASSERT(str_content.IsTwoByte());
9059 result = DateParser::Parse(str_content.ToUC16Vector(),
Ben Murdoch8b112d22011-06-08 16:22:53 +01009060 output_array,
9061 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00009062 }
9063
9064 if (result) {
9065 return *output;
9066 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009067 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009068 }
9069}
9070
9071
Ben Murdoch8b112d22011-06-08 16:22:53 +01009072RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009073 NoHandleAllocation ha;
9074 ASSERT(args.length() == 1);
9075
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009076 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009077 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9078 const char* zone = OS::LocalTimezone(static_cast<double>(time));
Steve Block44f0eee2011-05-26 01:26:41 +01009079 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
Steve Blocka7e24c12009-10-30 11:49:00 +00009080}
9081
9082
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009083RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009084 NoHandleAllocation ha;
9085 ASSERT(args.length() == 1);
9086
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009088 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9089
9090 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
Steve Blocka7e24c12009-10-30 11:49:00 +00009091}
9092
9093
Ben Murdoch8b112d22011-06-08 16:22:53 +01009094RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009095 ASSERT(args.length() == 1);
9096 Object* global = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01009097 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009098 return JSGlobalObject::cast(global)->global_receiver();
9099}
9100
9101
Ben Murdoch8b112d22011-06-08 16:22:53 +01009102RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
Steve Block44f0eee2011-05-26 01:26:41 +01009103 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009104 ASSERT_EQ(1, args.length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009105 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009106
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009107 source = Handle<String>(source->TryFlattenGetString());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009108 // Optimized fast case where we only have ASCII characters.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009109 Handle<Object> result;
9110 if (source->IsSeqAsciiString()) {
9111 result = JsonParser<true>::Parse(source);
9112 } else {
9113 result = JsonParser<false>::Parse(source);
9114 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009115 if (result.is_null()) {
9116 // Syntax error or stack overflow in scanner.
Steve Block44f0eee2011-05-26 01:26:41 +01009117 ASSERT(isolate->has_pending_exception());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009118 return Failure::Exception();
9119 }
9120 return *result;
9121}
9122
9123
Ben Murdoch257744e2011-11-30 15:57:28 +00009124bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9125 Handle<Context> context) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009126 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9127 // Check with callback if set.
9128 AllowCodeGenerationFromStringsCallback callback =
9129 isolate->allow_code_gen_callback();
9130 if (callback == NULL) {
9131 // No callback set and code generation disallowed.
9132 return false;
9133 } else {
9134 // Callback set. Let it decide if code generation is allowed.
9135 VMState state(isolate, EXTERNAL);
9136 return callback(v8::Utils::ToLocal(context));
Ben Murdoch257744e2011-11-30 15:57:28 +00009137 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009138}
9139
9140
Ben Murdoch8b112d22011-06-08 16:22:53 +01009141RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
Steve Block44f0eee2011-05-26 01:26:41 +01009142 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009143 ASSERT_EQ(1, args.length());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009144 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009145
Ben Murdoch257744e2011-11-30 15:57:28 +00009146 // Extract global context.
Steve Block44f0eee2011-05-26 01:26:41 +01009147 Handle<Context> context(isolate->context()->global_context());
Ben Murdoch257744e2011-11-30 15:57:28 +00009148
9149 // Check if global context allows code generation from
9150 // strings. Throw an exception if it doesn't.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009151 if (context->allow_code_gen_from_strings()->IsFalse() &&
9152 !CodeGenerationFromStringsAllowed(isolate, context)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009153 return isolate->Throw(*isolate->factory()->NewError(
9154 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9155 }
9156
9157 // Compile source string in the global context.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009158 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9159 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +01009160 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00009161 Handle<JSFunction> fun =
Steve Block44f0eee2011-05-26 01:26:41 +01009162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9163 context,
9164 NOT_TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009165 return *fun;
9166}
9167
9168
Steve Block44f0eee2011-05-26 01:26:41 +01009169static ObjectPair CompileGlobalEval(Isolate* isolate,
9170 Handle<String> source,
Steve Block1e0659c2011-05-24 12:43:12 +01009171 Handle<Object> receiver,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009172 LanguageMode language_mode,
9173 int scope_position) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009174 Handle<Context> context = Handle<Context>(isolate->context());
9175 Handle<Context> global_context = Handle<Context>(context->global_context());
9176
9177 // Check if global context allows code generation from
9178 // strings. Throw an exception if it doesn't.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009179 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9180 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009181 isolate->Throw(*isolate->factory()->NewError(
9182 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9183 return MakePair(Failure::Exception(), NULL);
9184 }
9185
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009186 // Deal with a normal eval call with a string argument. Compile it
9187 // and return the compiled function bound in the local context.
9188 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9189 source,
Steve Block44f0eee2011-05-26 01:26:41 +01009190 Handle<Context>(isolate->context()),
Ben Murdoch257744e2011-11-30 15:57:28 +00009191 context->IsGlobalContext(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009192 language_mode,
9193 scope_position);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009194 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01009195 Handle<JSFunction> compiled =
9196 isolate->factory()->NewFunctionFromSharedFunctionInfo(
Ben Murdoch257744e2011-11-30 15:57:28 +00009197 shared, context, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009198 return MakePair(*compiled, *receiver);
9199}
9200
9201
Ben Murdoch8b112d22011-06-08 16:22:53 +01009202RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009203 ASSERT(args.length() == 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00009204
Steve Block44f0eee2011-05-26 01:26:41 +01009205 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009206 Handle<Object> callee = args.at<Object>(0);
Leon Clarkee46be812010-01-19 14:06:41 +00009207
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009208 // If "eval" didn't refer to the original GlobalEval, it's not a
9209 // direct call to eval.
9210 // (And even if it is, but the first argument isn't a string, just let
9211 // execution default to an indirect call to eval, which will also return
9212 // the first argument without doing anything).
Steve Block44f0eee2011-05-26 01:26:41 +01009213 if (*callee != isolate->global_context()->global_eval_fun() ||
Leon Clarkee46be812010-01-19 14:06:41 +00009214 !args[1]->IsString()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009215 return MakePair(*callee, isolate->heap()->the_hole_value());
Leon Clarkee46be812010-01-19 14:06:41 +00009216 }
9217
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009218 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9219 ASSERT(args[4]->IsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +01009220 return CompileGlobalEval(isolate,
9221 args.at<String>(1),
Steve Block1e0659c2011-05-24 12:43:12 +01009222 args.at<Object>(2),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009223 language_mode,
9224 args.smi_at(4));
Steve Blocka7e24c12009-10-30 11:49:00 +00009225}
9226
9227
Ben Murdoch8b112d22011-06-08 16:22:53 +01009228RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009229 // This utility adjusts the property attributes for newly created Function
9230 // object ("new Function(...)") by changing the map.
9231 // All it does is changing the prototype property to enumerable
9232 // as specified in ECMA262, 15.3.5.2.
Steve Block44f0eee2011-05-26 01:26:41 +01009233 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009234 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009235 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009236
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009237 Handle<Map> map = func->shared()->is_classic_mode()
9238 ? isolate->function_instance_map()
9239 : isolate->strict_mode_function_instance_map();
Steve Block44f0eee2011-05-26 01:26:41 +01009240
9241 ASSERT(func->map()->instance_type() == map->instance_type());
9242 ASSERT(func->map()->instance_size() == map->instance_size());
9243 func->set_map(*map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009244 return *func;
9245}
9246
9247
Ben Murdoch8b112d22011-06-08 16:22:53 +01009248RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
Ben Murdochbb769b22010-08-11 14:56:33 +01009249 // Allocate a block of memory in NewSpace (filled with a filler).
9250 // Use as fallback for allocation in generated code when NewSpace
9251 // is full.
9252 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009253 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
Ben Murdochbb769b22010-08-11 14:56:33 +01009254 int size = size_smi->value();
9255 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9256 RUNTIME_ASSERT(size > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009257 Heap* heap = isolate->heap();
9258 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
Ben Murdochbb769b22010-08-11 14:56:33 +01009259 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
John Reck59135872010-11-02 12:39:01 -07009260 Object* allocation;
Steve Block44f0eee2011-05-26 01:26:41 +01009261 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
John Reck59135872010-11-02 12:39:01 -07009262 if (maybe_allocation->ToObject(&allocation)) {
Steve Block44f0eee2011-05-26 01:26:41 +01009263 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
John Reck59135872010-11-02 12:39:01 -07009264 }
9265 return maybe_allocation;
Ben Murdochbb769b22010-08-11 14:56:33 +01009266 }
Ben Murdochbb769b22010-08-11 14:56:33 +01009267}
9268
9269
Ben Murdochb0fe1622011-05-05 13:52:32 +01009270// Push an object unto an array of objects if it is not already in the
Steve Blocka7e24c12009-10-30 11:49:00 +00009271// array. Returns true if the element was pushed on the stack and
9272// false otherwise.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009273RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009274 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009275 CONVERT_ARG_CHECKED(JSArray, array, 0);
9276 CONVERT_ARG_CHECKED(JSObject, element, 1);
9277 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009278 int length = Smi::cast(array->length())->value();
9279 FixedArray* elements = FixedArray::cast(array->elements());
9280 for (int i = 0; i < length; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009281 if (elements->get(i) == element) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009282 }
John Reck59135872010-11-02 12:39:01 -07009283 Object* obj;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009284 // Strict not needed. Used for cycle detection in Array join implementation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009285 { MaybeObject* maybe_obj =
9286 array->SetFastElement(length, element, kNonStrictMode, true);
John Reck59135872010-11-02 12:39:01 -07009287 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9288 }
Steve Block44f0eee2011-05-26 01:26:41 +01009289 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009290}
9291
9292
9293/**
9294 * A simple visitor visits every element of Array's.
9295 * The backend storage can be a fixed array for fast elements case,
9296 * or a dictionary for sparse array. Since Dictionary is a subtype
9297 * of FixedArray, the class can be used by both fast and slow cases.
9298 * The second parameter of the constructor, fast_elements, specifies
9299 * whether the storage is a FixedArray or Dictionary.
9300 *
9301 * An index limit is used to deal with the situation that a result array
9302 * length overflows 32-bit non-negative integer.
9303 */
9304class ArrayConcatVisitor {
9305 public:
Steve Block44f0eee2011-05-26 01:26:41 +01009306 ArrayConcatVisitor(Isolate* isolate,
9307 Handle<FixedArray> storage,
Steve Blocka7e24c12009-10-30 11:49:00 +00009308 bool fast_elements) :
Steve Block44f0eee2011-05-26 01:26:41 +01009309 isolate_(isolate),
9310 storage_(Handle<FixedArray>::cast(
9311 isolate->global_handles()->Create(*storage))),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009312 index_offset_(0u),
9313 fast_elements_(fast_elements) { }
9314
9315 ~ArrayConcatVisitor() {
9316 clear_storage();
9317 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009318
9319 void visit(uint32_t i, Handle<Object> elm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009320 if (i >= JSObject::kMaxElementCount - index_offset_) return;
Leon Clarkee46be812010-01-19 14:06:41 +00009321 uint32_t index = index_offset_ + i;
Steve Blocka7e24c12009-10-30 11:49:00 +00009322
9323 if (fast_elements_) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009324 if (index < static_cast<uint32_t>(storage_->length())) {
9325 storage_->set(index, *elm);
9326 return;
9327 }
9328 // Our initial estimate of length was foiled, possibly by
9329 // getters on the arrays increasing the length of later arrays
9330 // during iteration.
9331 // This shouldn't happen in anything but pathological cases.
9332 SetDictionaryMode(index);
9333 // Fall-through to dictionary mode.
Steve Blocka7e24c12009-10-30 11:49:00 +00009334 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009335 ASSERT(!fast_elements_);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009336 Handle<SeededNumberDictionary> dict(
9337 SeededNumberDictionary::cast(*storage_));
9338 Handle<SeededNumberDictionary> result =
Steve Block44f0eee2011-05-26 01:26:41 +01009339 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009340 if (!result.is_identical_to(dict)) {
9341 // Dictionary needed to grow.
9342 clear_storage();
9343 set_storage(*result);
9344 }
9345}
Steve Blocka7e24c12009-10-30 11:49:00 +00009346
9347 void increase_index_offset(uint32_t delta) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009348 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9349 index_offset_ = JSObject::kMaxElementCount;
Leon Clarkee46be812010-01-19 14:06:41 +00009350 } else {
9351 index_offset_ += delta;
9352 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009353 }
9354
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009355 Handle<JSArray> ToArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01009356 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009357 Handle<Object> length =
Steve Block44f0eee2011-05-26 01:26:41 +01009358 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009359 Handle<Map> map;
9360 if (fast_elements_) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009361 map = isolate_->factory()->GetElementsTransitionMap(array,
9362 FAST_ELEMENTS);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009363 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009364 map = isolate_->factory()->GetElementsTransitionMap(array,
9365 DICTIONARY_ELEMENTS);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009366 }
9367 array->set_map(*map);
9368 array->set_length(*length);
9369 array->set_elements(*storage_);
9370 return array;
9371 }
Leon Clarkee46be812010-01-19 14:06:41 +00009372
Steve Blocka7e24c12009-10-30 11:49:00 +00009373 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009374 // Convert storage to dictionary mode.
9375 void SetDictionaryMode(uint32_t index) {
9376 ASSERT(fast_elements_);
9377 Handle<FixedArray> current_storage(*storage_);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009378 Handle<SeededNumberDictionary> slow_storage(
9379 isolate_->factory()->NewSeededNumberDictionary(
9380 current_storage->length()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009381 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9382 for (uint32_t i = 0; i < current_length; i++) {
9383 HandleScope loop_scope;
9384 Handle<Object> element(current_storage->get(i));
9385 if (!element->IsTheHole()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009386 Handle<SeededNumberDictionary> new_storage =
Steve Block44f0eee2011-05-26 01:26:41 +01009387 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009388 if (!new_storage.is_identical_to(slow_storage)) {
9389 slow_storage = loop_scope.CloseAndEscape(new_storage);
9390 }
9391 }
9392 }
9393 clear_storage();
9394 set_storage(*slow_storage);
9395 fast_elements_ = false;
9396 }
9397
9398 inline void clear_storage() {
Steve Block44f0eee2011-05-26 01:26:41 +01009399 isolate_->global_handles()->Destroy(
9400 Handle<Object>::cast(storage_).location());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009401 }
9402
9403 inline void set_storage(FixedArray* storage) {
Steve Block44f0eee2011-05-26 01:26:41 +01009404 storage_ = Handle<FixedArray>::cast(
9405 isolate_->global_handles()->Create(storage));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009406 }
9407
Steve Block44f0eee2011-05-26 01:26:41 +01009408 Isolate* isolate_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009409 Handle<FixedArray> storage_; // Always a global handle.
9410 // Index after last seen index. Always less than or equal to
9411 // JSObject::kMaxElementCount.
Steve Blocka7e24c12009-10-30 11:49:00 +00009412 uint32_t index_offset_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009413 bool fast_elements_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009414};
9415
9416
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009417static uint32_t EstimateElementCount(Handle<JSArray> array) {
9418 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9419 int element_count = 0;
9420 switch (array->GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009421 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009422 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009423 // Fast elements can't have lengths that are not representable by
9424 // a 32-bit signed integer.
9425 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9426 int fast_length = static_cast<int>(length);
9427 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9428 for (int i = 0; i < fast_length; i++) {
9429 if (!elements->get(i)->IsTheHole()) element_count++;
Steve Blocka7e24c12009-10-30 11:49:00 +00009430 }
Steve Block3ce2e202009-11-05 08:53:23 +00009431 break;
9432 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009433 case FAST_DOUBLE_ELEMENTS:
9434 // TODO(1810): Decide if it's worthwhile to implement this.
9435 UNREACHABLE();
9436 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00009437 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009438 Handle<SeededNumberDictionary> dictionary(
9439 SeededNumberDictionary::cast(array->elements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009440 int capacity = dictionary->Capacity();
9441 for (int i = 0; i < capacity; i++) {
9442 Handle<Object> key(dictionary->KeyAt(i));
9443 if (dictionary->IsKey(*key)) {
9444 element_count++;
9445 }
9446 }
9447 break;
9448 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009449 case NON_STRICT_ARGUMENTS_ELEMENTS:
9450 case EXTERNAL_BYTE_ELEMENTS:
9451 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9452 case EXTERNAL_SHORT_ELEMENTS:
9453 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9454 case EXTERNAL_INT_ELEMENTS:
9455 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9456 case EXTERNAL_FLOAT_ELEMENTS:
9457 case EXTERNAL_DOUBLE_ELEMENTS:
9458 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009459 // External arrays are always dense.
9460 return length;
9461 }
9462 // As an estimate, we assume that the prototype doesn't contain any
9463 // inherited elements.
9464 return element_count;
9465}
9466
9467
9468
9469template<class ExternalArrayClass, class ElementType>
Steve Block44f0eee2011-05-26 01:26:41 +01009470static void IterateExternalArrayElements(Isolate* isolate,
9471 Handle<JSObject> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009472 bool elements_are_ints,
9473 bool elements_are_guaranteed_smis,
9474 ArrayConcatVisitor* visitor) {
9475 Handle<ExternalArrayClass> array(
9476 ExternalArrayClass::cast(receiver->elements()));
9477 uint32_t len = static_cast<uint32_t>(array->length());
9478
9479 ASSERT(visitor != NULL);
9480 if (elements_are_ints) {
9481 if (elements_are_guaranteed_smis) {
9482 for (uint32_t j = 0; j < len; j++) {
9483 HandleScope loop_scope;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009484 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009485 visitor->visit(j, e);
9486 }
9487 } else {
9488 for (uint32_t j = 0; j < len; j++) {
9489 HandleScope loop_scope;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009490 int64_t val = static_cast<int64_t>(array->get_scalar(j));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009491 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9492 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9493 visitor->visit(j, e);
9494 } else {
9495 Handle<Object> e =
Steve Block44f0eee2011-05-26 01:26:41 +01009496 isolate->factory()->NewNumber(static_cast<ElementType>(val));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009497 visitor->visit(j, e);
9498 }
9499 }
9500 }
9501 } else {
9502 for (uint32_t j = 0; j < len; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009503 HandleScope loop_scope(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009504 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009505 visitor->visit(j, e);
9506 }
9507 }
9508}
9509
9510
9511// Used for sorting indices in a List<uint32_t>.
9512static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9513 uint32_t a = *ap;
9514 uint32_t b = *bp;
9515 return (a == b) ? 0 : (a < b) ? -1 : 1;
9516}
9517
9518
9519static void CollectElementIndices(Handle<JSObject> object,
9520 uint32_t range,
9521 List<uint32_t>* indices) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009522 ElementsKind kind = object->GetElementsKind();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009523 switch (kind) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009524 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009525 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009526 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9527 uint32_t length = static_cast<uint32_t>(elements->length());
9528 if (range < length) length = range;
9529 for (uint32_t i = 0; i < length; i++) {
9530 if (!elements->get(i)->IsTheHole()) {
9531 indices->Add(i);
9532 }
9533 }
9534 break;
9535 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009536 case FAST_DOUBLE_ELEMENTS: {
9537 // TODO(1810): Decide if it's worthwhile to implement this.
9538 UNREACHABLE();
9539 break;
9540 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009541 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009542 Handle<SeededNumberDictionary> dict(
9543 SeededNumberDictionary::cast(object->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009544 uint32_t capacity = dict->Capacity();
9545 for (uint32_t j = 0; j < capacity; j++) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009546 HandleScope loop_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +00009547 Handle<Object> k(dict->KeyAt(j));
9548 if (dict->IsKey(*k)) {
9549 ASSERT(k->IsNumber());
9550 uint32_t index = static_cast<uint32_t>(k->Number());
9551 if (index < range) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009552 indices->Add(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009553 }
9554 }
9555 }
9556 break;
9557 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009558 default: {
9559 int dense_elements_length;
9560 switch (kind) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009561 case EXTERNAL_PIXEL_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009562 dense_elements_length =
9563 ExternalPixelArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009564 break;
9565 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009566 case EXTERNAL_BYTE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009567 dense_elements_length =
9568 ExternalByteArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009569 break;
9570 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009571 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009572 dense_elements_length =
9573 ExternalUnsignedByteArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009574 break;
9575 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009576 case EXTERNAL_SHORT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009577 dense_elements_length =
9578 ExternalShortArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009579 break;
9580 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009581 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009582 dense_elements_length =
9583 ExternalUnsignedShortArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009584 break;
9585 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009586 case EXTERNAL_INT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009587 dense_elements_length =
9588 ExternalIntArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009589 break;
9590 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009591 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009592 dense_elements_length =
9593 ExternalUnsignedIntArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009594 break;
9595 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009596 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009597 dense_elements_length =
9598 ExternalFloatArray::cast(object->elements())->length();
9599 break;
9600 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009601 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009602 dense_elements_length =
9603 ExternalDoubleArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009604 break;
9605 }
9606 default:
9607 UNREACHABLE();
9608 dense_elements_length = 0;
9609 break;
9610 }
9611 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9612 if (range <= length) {
9613 length = range;
9614 // We will add all indices, so we might as well clear it first
9615 // and avoid duplicates.
9616 indices->Clear();
9617 }
9618 for (uint32_t i = 0; i < length; i++) {
9619 indices->Add(i);
9620 }
9621 if (length == range) return; // All indices accounted for already.
9622 break;
9623 }
9624 }
9625
9626 Handle<Object> prototype(object->GetPrototype());
9627 if (prototype->IsJSObject()) {
9628 // The prototype will usually have no inherited element indices,
9629 // but we have to check.
9630 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9631 }
9632}
9633
9634
9635/**
9636 * A helper function that visits elements of a JSArray in numerical
9637 * order.
9638 *
9639 * The visitor argument called for each existing element in the array
9640 * with the element index and the element's value.
9641 * Afterwards it increments the base-index of the visitor by the array
9642 * length.
9643 * Returns false if any access threw an exception, otherwise true.
9644 */
Steve Block44f0eee2011-05-26 01:26:41 +01009645static bool IterateElements(Isolate* isolate,
9646 Handle<JSArray> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009647 ArrayConcatVisitor* visitor) {
9648 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9649 switch (receiver->GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009650 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009651 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009652 // Run through the elements FixedArray and use HasElement and GetElement
9653 // to check the prototype for missing elements.
9654 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9655 int fast_length = static_cast<int>(length);
9656 ASSERT(fast_length <= elements->length());
9657 for (int j = 0; j < fast_length; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009658 HandleScope loop_scope(isolate);
9659 Handle<Object> element_value(elements->get(j), isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009660 if (!element_value->IsTheHole()) {
9661 visitor->visit(j, element_value);
9662 } else if (receiver->HasElement(j)) {
9663 // Call GetElement on receiver, not its prototype, or getters won't
9664 // have the correct receiver.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009665 element_value = Object::GetElement(receiver, j);
9666 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009667 visitor->visit(j, element_value);
9668 }
9669 }
9670 break;
9671 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009672 case FAST_DOUBLE_ELEMENTS: {
9673 // TODO(1810): Decide if it's worthwhile to implement this.
9674 UNREACHABLE();
9675 break;
9676 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009677 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009678 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009679 List<uint32_t> indices(dict->Capacity() / 2);
9680 // Collect all indices in the object and the prototypes less
9681 // than length. This might introduce duplicates in the indices list.
9682 CollectElementIndices(receiver, length, &indices);
9683 indices.Sort(&compareUInt32);
9684 int j = 0;
9685 int n = indices.length();
9686 while (j < n) {
9687 HandleScope loop_scope;
9688 uint32_t index = indices[j];
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009689 Handle<Object> element = Object::GetElement(receiver, index);
9690 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009691 visitor->visit(index, element);
9692 // Skip to next different index (i.e., omit duplicates).
9693 do {
9694 j++;
9695 } while (j < n && indices[j] == index);
9696 }
9697 break;
9698 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009699 case EXTERNAL_PIXEL_ELEMENTS: {
Steve Block44f0eee2011-05-26 01:26:41 +01009700 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9701 receiver->elements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009702 for (uint32_t j = 0; j < length; j++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009703 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009704 visitor->visit(j, e);
9705 }
9706 break;
9707 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009708 case EXTERNAL_BYTE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009709 IterateExternalArrayElements<ExternalByteArray, int8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009710 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009711 break;
9712 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009713 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009714 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009715 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009716 break;
9717 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009718 case EXTERNAL_SHORT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009719 IterateExternalArrayElements<ExternalShortArray, int16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009720 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009721 break;
9722 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009723 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009724 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009725 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009726 break;
9727 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009728 case EXTERNAL_INT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009729 IterateExternalArrayElements<ExternalIntArray, int32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009730 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009731 break;
9732 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009733 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009734 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01009735 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009736 break;
9737 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009738 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009739 IterateExternalArrayElements<ExternalFloatArray, float>(
Steve Block44f0eee2011-05-26 01:26:41 +01009740 isolate, receiver, false, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009741 break;
9742 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009743 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009744 IterateExternalArrayElements<ExternalDoubleArray, double>(
9745 isolate, receiver, false, false, visitor);
9746 break;
9747 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009748 default:
9749 UNREACHABLE();
9750 break;
9751 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009752 visitor->increase_index_offset(length);
9753 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009754}
9755
9756
9757/**
9758 * Array::concat implementation.
9759 * See ECMAScript 262, 15.4.4.4.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009760 * TODO(581): Fix non-compliance for very large concatenations and update to
Leon Clarkee46be812010-01-19 14:06:41 +00009761 * following the ECMAScript 5 specification.
Steve Blocka7e24c12009-10-30 11:49:00 +00009762 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01009763RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009764 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01009765 HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009766
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009767 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009768 int argument_count = static_cast<int>(arguments->length()->Number());
9769 RUNTIME_ASSERT(arguments->HasFastElements());
9770 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009771
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009772 // Pass 1: estimate the length and number of elements of the result.
9773 // The actual length can be larger if any of the arguments have getters
9774 // that mutate other arguments (but will otherwise be precise).
9775 // The number of elements is precise if there are no inherited elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00009776
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009777 uint32_t estimate_result_length = 0;
9778 uint32_t estimate_nof_elements = 0;
9779 {
9780 for (int i = 0; i < argument_count; i++) {
9781 HandleScope loop_scope;
9782 Handle<Object> obj(elements->get(i));
9783 uint32_t length_estimate;
9784 uint32_t element_estimate;
9785 if (obj->IsJSArray()) {
9786 Handle<JSArray> array(Handle<JSArray>::cast(obj));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009787 // TODO(1810): Find out if it's worthwhile to properly support
9788 // arbitrary ElementsKinds. For now, pessimistically transition to
9789 // FAST_ELEMENTS.
9790 if (array->HasFastDoubleElements()) {
9791 array = Handle<JSArray>::cast(
9792 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
9793 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009794 length_estimate =
9795 static_cast<uint32_t>(array->length()->Number());
9796 element_estimate =
9797 EstimateElementCount(array);
9798 } else {
9799 length_estimate = 1;
9800 element_estimate = 1;
9801 }
9802 // Avoid overflows by capping at kMaxElementCount.
9803 if (JSObject::kMaxElementCount - estimate_result_length <
9804 length_estimate) {
9805 estimate_result_length = JSObject::kMaxElementCount;
9806 } else {
9807 estimate_result_length += length_estimate;
9808 }
9809 if (JSObject::kMaxElementCount - estimate_nof_elements <
9810 element_estimate) {
9811 estimate_nof_elements = JSObject::kMaxElementCount;
9812 } else {
9813 estimate_nof_elements += element_estimate;
Steve Blocka7e24c12009-10-30 11:49:00 +00009814 }
9815 }
9816 }
9817
Steve Blocka7e24c12009-10-30 11:49:00 +00009818 // If estimated number of elements is more than half of length, a
9819 // fixed array (fast case) is more time and space-efficient than a
9820 // dictionary.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009821 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00009822
9823 Handle<FixedArray> storage;
9824 if (fast_case) {
9825 // The backing storage array must have non-existing elements to
9826 // preserve holes across concat operations.
Steve Block44f0eee2011-05-26 01:26:41 +01009827 storage = isolate->factory()->NewFixedArrayWithHoles(
9828 estimate_result_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00009829 } else {
9830 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9831 uint32_t at_least_space_for = estimate_nof_elements +
9832 (estimate_nof_elements >> 2);
9833 storage = Handle<FixedArray>::cast(
Ben Murdochc7cc0282012-03-05 14:35:55 +00009834 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
Steve Blocka7e24c12009-10-30 11:49:00 +00009835 }
9836
Steve Block44f0eee2011-05-26 01:26:41 +01009837 ArrayConcatVisitor visitor(isolate, storage, fast_case);
Steve Blocka7e24c12009-10-30 11:49:00 +00009838
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009839 for (int i = 0; i < argument_count; i++) {
9840 Handle<Object> obj(elements->get(i));
9841 if (obj->IsJSArray()) {
9842 Handle<JSArray> array = Handle<JSArray>::cast(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01009843 if (!IterateElements(isolate, array, &visitor)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009844 return Failure::Exception();
9845 }
9846 } else {
9847 visitor.visit(0, obj);
9848 visitor.increase_index_offset(1);
9849 }
9850 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009851
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009852 return *visitor.ToArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00009853}
9854
9855
9856// This will not allocate (flatten the string), but it may run
9857// very slowly for very deeply nested ConsStrings. For debugging use only.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009858RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009859 NoHandleAllocation ha;
9860 ASSERT(args.length() == 1);
9861
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009862 CONVERT_ARG_CHECKED(String, string, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009863 StringInputBuffer buffer(string);
9864 while (buffer.has_more()) {
9865 uint16_t character = buffer.GetNext();
9866 PrintF("%c", character);
9867 }
9868 return string;
9869}
9870
9871// Moves all own elements of an object, that are below a limit, to positions
9872// starting at zero. All undefined values are placed after non-undefined values,
9873// and are followed by non-existing element. Does not change the length
9874// property.
9875// Returns the number of non-undefined elements collected.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009876RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009877 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009878 CONVERT_ARG_CHECKED(JSObject, object, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009879 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9880 return object->PrepareElementsForSort(limit);
9881}
9882
9883
9884// Move contents of argument 0 (an array) to argument 1 (an array)
Ben Murdoch8b112d22011-06-08 16:22:53 +01009885RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009886 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009887 CONVERT_ARG_CHECKED(JSArray, from, 0);
9888 CONVERT_ARG_CHECKED(JSArray, to, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009889 FixedArrayBase* new_elements = from->elements();
John Reck59135872010-11-02 12:39:01 -07009890 MaybeObject* maybe_new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009891 ElementsKind elements_kind;
Steve Block44f0eee2011-05-26 01:26:41 +01009892 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9893 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009894 elements_kind = FAST_ELEMENTS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009895 } else if (new_elements->map() ==
9896 isolate->heap()->fixed_double_array_map()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009897 elements_kind = FAST_DOUBLE_ELEMENTS;
Steve Block8defd9f2010-07-08 12:39:36 +01009898 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009899 elements_kind = DICTIONARY_ELEMENTS;
Steve Block8defd9f2010-07-08 12:39:36 +01009900 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009901 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
John Reck59135872010-11-02 12:39:01 -07009902 Object* new_map;
9903 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
Steve Block8defd9f2010-07-08 12:39:36 +01009904 to->set_map(Map::cast(new_map));
9905 to->set_elements(new_elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00009906 to->set_length(from->length());
John Reck59135872010-11-02 12:39:01 -07009907 Object* obj;
9908 { MaybeObject* maybe_obj = from->ResetElements();
9909 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9910 }
Leon Clarke4515c472010-02-03 11:58:03 +00009911 from->set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00009912 return to;
9913}
9914
9915
Steve Block59151502010-09-22 15:07:15 +01009916// How many elements does this object/array have?
Ben Murdoch8b112d22011-06-08 16:22:53 +01009917RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009918 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009919 CONVERT_ARG_CHECKED(JSObject, object, 0);
Steve Block59151502010-09-22 15:07:15 +01009920 HeapObject* elements = object->elements();
Steve Blocka7e24c12009-10-30 11:49:00 +00009921 if (elements->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009922 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9923 return Smi::FromInt(result);
Steve Block59151502010-09-22 15:07:15 +01009924 } else if (object->IsJSArray()) {
9925 return JSArray::cast(object)->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009926 } else {
Steve Block59151502010-09-22 15:07:15 +01009927 return Smi::FromInt(FixedArray::cast(elements)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009928 }
9929}
9930
9931
9932// Returns an array that tells you where in the [0, length) interval an array
Steve Block59151502010-09-22 15:07:15 +01009933// might have elements. Can either return keys (positive integers) or
9934// intervals (pair of a negative integer (-start-1) followed by a
9935// positive (length)) or undefined values.
9936// Intervals can span over some keys that are not in the object.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009937RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009938 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01009939 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009940 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009941 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
9942 if (array->elements()->IsDictionary()) {
9943 // Create an array and get all the keys into it, then remove all the
9944 // keys that are not integers in the range 0 to length-1.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009945 bool threw = false;
9946 Handle<FixedArray> keys =
9947 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9948 if (threw) return Failure::Exception();
9949
Steve Blocka7e24c12009-10-30 11:49:00 +00009950 int keys_length = keys->length();
9951 for (int i = 0; i < keys_length; i++) {
9952 Object* key = keys->get(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009953 uint32_t index = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009954 if (!key->ToArrayIndex(&index) || index >= length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009955 // Zap invalid keys.
9956 keys->set_undefined(i);
9957 }
9958 }
Steve Block44f0eee2011-05-26 01:26:41 +01009959 return *isolate->factory()->NewJSArrayWithElements(keys);
Steve Blocka7e24c12009-10-30 11:49:00 +00009960 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009961 ASSERT(array->HasFastElements() ||
9962 array->HasFastSmiOnlyElements() ||
9963 array->HasFastDoubleElements());
Steve Block44f0eee2011-05-26 01:26:41 +01009964 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009965 // -1 means start of array.
Leon Clarke4515c472010-02-03 11:58:03 +00009966 single_interval->set(0, Smi::FromInt(-1));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009967 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009968 uint32_t actual_length =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009969 static_cast<uint32_t>(elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009970 uint32_t min_length = actual_length < length ? actual_length : length;
9971 Handle<Object> length_object =
Steve Block44f0eee2011-05-26 01:26:41 +01009972 isolate->factory()->NewNumber(static_cast<double>(min_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009973 single_interval->set(1, *length_object);
Steve Block44f0eee2011-05-26 01:26:41 +01009974 return *isolate->factory()->NewJSArrayWithElements(single_interval);
Steve Blocka7e24c12009-10-30 11:49:00 +00009975 }
9976}
9977
9978
Ben Murdoch8b112d22011-06-08 16:22:53 +01009979RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009980 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009981 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9982 CONVERT_ARG_CHECKED(String, name, 1);
9983 CONVERT_SMI_ARG_CHECKED(flag, 2);
9984 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
9985 return obj->LookupAccessor(name, component);
Steve Blocka7e24c12009-10-30 11:49:00 +00009986}
9987
9988
9989#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01009990RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009991 ASSERT(args.length() == 0);
9992 return Execution::DebugBreakHelper();
9993}
9994
9995
9996// Helper functions for wrapping and unwrapping stack frame ids.
9997static Smi* WrapFrameId(StackFrame::Id id) {
9998 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
9999 return Smi::FromInt(id >> 2);
10000}
10001
10002
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010003static StackFrame::Id UnwrapFrameId(int wrapped) {
10004 return static_cast<StackFrame::Id>(wrapped << 2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010005}
10006
10007
10008// Adds a JavaScript function as a debug event listener.
10009// args[0]: debug event listener function to set or null or undefined for
10010// clearing the event listener function
10011// args[1]: object supplied during callback
Ben Murdoch8b112d22011-06-08 16:22:53 +010010012RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010013 ASSERT(args.length() == 2);
10014 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10015 args[0]->IsUndefined() ||
10016 args[0]->IsNull());
10017 Handle<Object> callback = args.at<Object>(0);
10018 Handle<Object> data = args.at<Object>(1);
Steve Block44f0eee2011-05-26 01:26:41 +010010019 isolate->debugger()->SetEventListener(callback, data);
Steve Blocka7e24c12009-10-30 11:49:00 +000010020
Steve Block44f0eee2011-05-26 01:26:41 +010010021 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010022}
10023
10024
Ben Murdoch8b112d22011-06-08 16:22:53 +010010025RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010026 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010027 isolate->stack_guard()->DebugBreak();
10028 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010029}
10030
10031
Steve Block44f0eee2011-05-26 01:26:41 +010010032static MaybeObject* DebugLookupResultValue(Heap* heap,
10033 Object* receiver,
10034 String* name,
John Reck59135872010-11-02 12:39:01 -070010035 LookupResult* result,
10036 bool* caught_exception) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010037 Object* value;
10038 switch (result->type()) {
10039 case NORMAL:
10040 value = result->holder()->GetNormalizedProperty(result);
10041 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010042 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010043 }
10044 return value;
10045 case FIELD:
10046 value =
10047 JSObject::cast(
10048 result->holder())->FastPropertyAt(result->GetFieldIndex());
10049 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010050 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010051 }
10052 return value;
10053 case CONSTANT_FUNCTION:
10054 return result->GetConstantFunction();
10055 case CALLBACKS: {
10056 Object* structure = result->GetCallbackObject();
Ben Murdoch257744e2011-11-30 15:57:28 +000010057 if (structure->IsForeign() || structure->IsAccessorInfo()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010058 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10059 receiver, structure, name);
John Reck59135872010-11-02 12:39:01 -070010060 if (!maybe_value->ToObject(&value)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010061 if (maybe_value->IsRetryAfterGC()) return maybe_value;
John Reck59135872010-11-02 12:39:01 -070010062 ASSERT(maybe_value->IsException());
Steve Block44f0eee2011-05-26 01:26:41 +010010063 maybe_value = heap->isolate()->pending_exception();
10064 heap->isolate()->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000010065 if (caught_exception != NULL) {
10066 *caught_exception = true;
10067 }
John Reck59135872010-11-02 12:39:01 -070010068 return maybe_value;
Steve Blocka7e24c12009-10-30 11:49:00 +000010069 }
10070 return value;
10071 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010072 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010073 }
10074 }
10075 case INTERCEPTOR:
10076 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +000010077 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +000010078 case CONSTANT_TRANSITION:
10079 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +010010080 return heap->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010081 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +000010082 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010083 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010084 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010085 UNREACHABLE(); // keep the compiler happy
Steve Block44f0eee2011-05-26 01:26:41 +010010086 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010087}
10088
10089
10090// Get debugger related details for an object property.
10091// args[0]: object holding property
10092// args[1]: name of the property
10093//
10094// The array returned contains the following information:
10095// 0: Property value
10096// 1: Property details
10097// 2: Property value is exception
10098// 3: Getter function if defined
10099// 4: Setter function if defined
10100// Items 2-4 are only filled if the property has either a getter or a setter
10101// defined through __defineGetter__ and/or __defineSetter__.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010102RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010103 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010104
10105 ASSERT(args.length() == 2);
10106
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010107 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10108 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010109
10110 // Make sure to set the current context to the context before the debugger was
10111 // entered (if the debugger is entered). The reason for switching context here
10112 // is that for some property lookups (accessors and interceptors) callbacks
10113 // into the embedding application can occour, and the embedding application
10114 // could have the assumption that its own global context is the current
10115 // context and not some internal debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +010010116 SaveContext save(isolate);
10117 if (isolate->debug()->InDebugger()) {
10118 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000010119 }
10120
10121 // Skip the global proxy as it has no properties and always delegates to the
10122 // real global object.
10123 if (obj->IsJSGlobalProxy()) {
10124 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10125 }
10126
10127
10128 // Check if the name is trivially convertible to an index and get the element
10129 // if so.
10130 uint32_t index;
10131 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +010010132 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
John Reck59135872010-11-02 12:39:01 -070010133 Object* element_or_char;
10134 { MaybeObject* maybe_element_or_char =
Steve Block44f0eee2011-05-26 01:26:41 +010010135 Runtime::GetElementOrCharAt(isolate, obj, index);
John Reck59135872010-11-02 12:39:01 -070010136 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10137 return maybe_element_or_char;
10138 }
10139 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010140 details->set(0, element_or_char);
Steve Blocka7e24c12009-10-30 11:49:00 +000010141 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +010010142 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010143 }
10144
10145 // Find the number of objects making up this.
10146 int length = LocalPrototypeChainLength(*obj);
10147
10148 // Try local lookup on each of the objects.
10149 Handle<JSObject> jsproto = obj;
10150 for (int i = 0; i < length; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010151 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010152 jsproto->LocalLookup(*name, &result);
10153 if (result.IsProperty()) {
10154 // LookupResult is not GC safe as it holds raw object pointers.
10155 // GC can happen later in this code so put the required fields into
10156 // local variables using handles when required for later use.
10157 PropertyType result_type = result.type();
10158 Handle<Object> result_callback_obj;
10159 if (result_type == CALLBACKS) {
Steve Block44f0eee2011-05-26 01:26:41 +010010160 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10161 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010162 }
10163 Smi* property_details = result.GetPropertyDetails().AsSmi();
10164 // DebugLookupResultValue can cause GC so details from LookupResult needs
10165 // to be copied to handles before this.
10166 bool caught_exception = false;
John Reck59135872010-11-02 12:39:01 -070010167 Object* raw_value;
10168 { MaybeObject* maybe_raw_value =
Steve Block44f0eee2011-05-26 01:26:41 +010010169 DebugLookupResultValue(isolate->heap(), *obj, *name,
10170 &result, &caught_exception);
John Reck59135872010-11-02 12:39:01 -070010171 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10172 }
Steve Block44f0eee2011-05-26 01:26:41 +010010173 Handle<Object> value(raw_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010174
10175 // If the callback object is a fixed array then it contains JavaScript
10176 // getter and/or setter.
10177 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010178 result_callback_obj->IsAccessorPair();
Steve Blocka7e24c12009-10-30 11:49:00 +000010179 Handle<FixedArray> details =
Steve Block44f0eee2011-05-26 01:26:41 +010010180 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010181 details->set(0, *value);
10182 details->set(1, property_details);
10183 if (hasJavaScriptAccessors) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010184 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010185 details->set(2, isolate->heap()->ToBoolean(caught_exception));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010186 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10187 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
Steve Blocka7e24c12009-10-30 11:49:00 +000010188 }
10189
Steve Block44f0eee2011-05-26 01:26:41 +010010190 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010191 }
10192 if (i < length - 1) {
10193 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10194 }
10195 }
10196
Steve Block44f0eee2011-05-26 01:26:41 +010010197 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010198}
10199
10200
Ben Murdoch8b112d22011-06-08 16:22:53 +010010201RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
Steve Block44f0eee2011-05-26 01:26:41 +010010202 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010203
10204 ASSERT(args.length() == 2);
10205
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010206 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10207 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010208
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010209 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010210 obj->Lookup(*name, &result);
10211 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010212 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010213 }
Steve Block44f0eee2011-05-26 01:26:41 +010010214 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010215}
10216
10217
Steve Blocka7e24c12009-10-30 11:49:00 +000010218// Return the property type calculated from the property details.
10219// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010220RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010221 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010222 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10223 return Smi::FromInt(static_cast<int>(details.type()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010224}
10225
10226
10227// Return the property attribute calculated from the property details.
10228// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010229RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010230 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010231 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10232 return Smi::FromInt(static_cast<int>(details.attributes()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010233}
10234
10235
10236// Return the property insertion index calculated from the property details.
10237// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010238RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010239 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010240 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10241 return Smi::FromInt(details.index());
Steve Blocka7e24c12009-10-30 11:49:00 +000010242}
10243
10244
Steve Blocka7e24c12009-10-30 11:49:00 +000010245// Return property value from named interceptor.
10246// args[0]: object
10247// args[1]: property name
Ben Murdoch8b112d22011-06-08 16:22:53 +010010248RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
Steve Block44f0eee2011-05-26 01:26:41 +010010249 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010250 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010251 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010252 RUNTIME_ASSERT(obj->HasNamedInterceptor());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010253 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010254
10255 PropertyAttributes attributes;
10256 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
10257}
10258
10259
10260// Return element value from indexed interceptor.
10261// args[0]: object
10262// args[1]: index
Ben Murdoch8b112d22011-06-08 16:22:53 +010010263RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
Steve Block44f0eee2011-05-26 01:26:41 +010010264 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010265 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010266 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000010267 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10268 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10269
10270 return obj->GetElementWithInterceptor(*obj, index);
10271}
10272
10273
Ben Murdoch8b112d22011-06-08 16:22:53 +010010274RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010275 ASSERT(args.length() >= 1);
10276 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
10277 // Check that the break id is valid.
Steve Block44f0eee2011-05-26 01:26:41 +010010278 if (isolate->debug()->break_id() == 0 ||
10279 break_id != isolate->debug()->break_id()) {
10280 return isolate->Throw(
10281 isolate->heap()->illegal_execution_state_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010282 }
10283
Steve Block44f0eee2011-05-26 01:26:41 +010010284 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010285}
10286
10287
Ben Murdoch8b112d22011-06-08 16:22:53 +010010288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010010289 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010290 ASSERT(args.length() == 1);
10291
10292 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010293 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010294 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10295 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010296 if (!maybe_result->ToObject(&result)) return maybe_result;
10297 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010298
10299 // Count all frames which are relevant to debugging stack trace.
10300 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010301 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +000010302 if (id == StackFrame::NO_ID) {
10303 // If there is no JavaScript stack frame count is 0.
10304 return Smi::FromInt(0);
10305 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010306
10307 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10308 n += it.frame()->GetInlineCount();
10309 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010310 return Smi::FromInt(n);
10311}
10312
10313
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010314class FrameInspector {
10315 public:
10316 FrameInspector(JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010317 int inlined_jsframe_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010318 Isolate* isolate)
10319 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10320 // Calculate the deoptimized frame.
10321 if (frame->is_optimized()) {
10322 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010323 frame, inlined_jsframe_index, isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010324 }
10325 has_adapted_arguments_ = frame_->has_adapted_arguments();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010326 is_bottommost_ = inlined_jsframe_index == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010327 is_optimized_ = frame_->is_optimized();
10328 }
10329
10330 ~FrameInspector() {
10331 // Get rid of the calculated deoptimized frame if any.
10332 if (deoptimized_frame_ != NULL) {
10333 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10334 isolate_);
10335 }
10336 }
10337
10338 int GetParametersCount() {
10339 return is_optimized_
10340 ? deoptimized_frame_->parameters_count()
10341 : frame_->ComputeParametersCount();
10342 }
10343 int expression_count() { return deoptimized_frame_->expression_count(); }
10344 Object* GetFunction() {
10345 return is_optimized_
10346 ? deoptimized_frame_->GetFunction()
10347 : frame_->function();
10348 }
10349 Object* GetParameter(int index) {
10350 return is_optimized_
10351 ? deoptimized_frame_->GetParameter(index)
10352 : frame_->GetParameter(index);
10353 }
10354 Object* GetExpression(int index) {
10355 return is_optimized_
10356 ? deoptimized_frame_->GetExpression(index)
10357 : frame_->GetExpression(index);
10358 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010359 int GetSourcePosition() {
10360 return is_optimized_
10361 ? deoptimized_frame_->GetSourcePosition()
10362 : frame_->LookupCode()->SourcePosition(frame_->pc());
10363 }
10364 bool IsConstructor() {
10365 return is_optimized_ && !is_bottommost_
10366 ? deoptimized_frame_->HasConstructStub()
10367 : frame_->IsConstructor();
10368 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010369
10370 // To inspect all the provided arguments the frame might need to be
10371 // replaced with the arguments frame.
10372 void SetArgumentsFrame(JavaScriptFrame* frame) {
10373 ASSERT(has_adapted_arguments_);
10374 frame_ = frame;
10375 is_optimized_ = frame_->is_optimized();
10376 ASSERT(!is_optimized_);
10377 }
10378
10379 private:
10380 JavaScriptFrame* frame_;
10381 DeoptimizedFrameInfo* deoptimized_frame_;
10382 Isolate* isolate_;
10383 bool is_optimized_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010384 bool is_bottommost_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010385 bool has_adapted_arguments_;
10386
10387 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10388};
10389
10390
Steve Blocka7e24c12009-10-30 11:49:00 +000010391static const int kFrameDetailsFrameIdIndex = 0;
10392static const int kFrameDetailsReceiverIndex = 1;
10393static const int kFrameDetailsFunctionIndex = 2;
10394static const int kFrameDetailsArgumentCountIndex = 3;
10395static const int kFrameDetailsLocalCountIndex = 4;
10396static const int kFrameDetailsSourcePositionIndex = 5;
10397static const int kFrameDetailsConstructCallIndex = 6;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010398static const int kFrameDetailsAtReturnIndex = 7;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010399static const int kFrameDetailsFlagsIndex = 8;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010400static const int kFrameDetailsFirstDynamicIndex = 9;
Steve Blocka7e24c12009-10-30 11:49:00 +000010401
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010402
10403static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10404 JavaScriptFrame* frame) {
10405 SaveContext* save = isolate->save_context();
10406 while (save != NULL && !save->IsBelowFrame(frame)) {
10407 save = save->prev();
10408 }
10409 ASSERT(save != NULL);
10410 return save;
10411}
10412
10413
Steve Blocka7e24c12009-10-30 11:49:00 +000010414// Return an array with frame details
10415// args[0]: number: break id
10416// args[1]: number: frame index
10417//
10418// The array returned contains the following information:
10419// 0: Frame id
10420// 1: Receiver
10421// 2: Function
10422// 3: Argument count
10423// 4: Local count
10424// 5: Source position
10425// 6: Constructor call
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010426// 7: Is at return
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010427// 8: Flags
Steve Blocka7e24c12009-10-30 11:49:00 +000010428// Arguments name, value
10429// Locals name, value
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010430// Return value if any
Ben Murdoch8b112d22011-06-08 16:22:53 +010010431RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010432 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010433 ASSERT(args.length() == 2);
10434
10435 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010436 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010437 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10438 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010439 if (!maybe_check->ToObject(&check)) return maybe_check;
10440 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010441 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +010010442 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010443
10444 // Find the relevant frame with the requested index.
Steve Block44f0eee2011-05-26 01:26:41 +010010445 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +000010446 if (id == StackFrame::NO_ID) {
10447 // If there are no JavaScript stack frames return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +010010448 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010449 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010450
Steve Blocka7e24c12009-10-30 11:49:00 +000010451 int count = 0;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010452 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000010453 for (; !it.done(); it.Advance()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010454 if (index < count + it.frame()->GetInlineCount()) break;
10455 count += it.frame()->GetInlineCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010456 }
Steve Block44f0eee2011-05-26 01:26:41 +010010457 if (it.done()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010458
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010459 bool is_optimized = it.frame()->is_optimized();
10460
10461 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10462 if (is_optimized) {
10463 inlined_jsframe_index =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010464 it.frame()->GetInlineCount() - (index - count) - 1;
10465 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010466 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010467
Steve Blocka7e24c12009-10-30 11:49:00 +000010468 // Traverse the saved contexts chain to find the active context for the
10469 // selected frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010470 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
Steve Blocka7e24c12009-10-30 11:49:00 +000010471
10472 // Get the frame id.
Steve Block44f0eee2011-05-26 01:26:41 +010010473 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010474
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010475 // Find source position in unoptimized code.
10476 int position = frame_inspector.GetSourcePosition();
Steve Blocka7e24c12009-10-30 11:49:00 +000010477
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010478 // Check for constructor frame.
10479 bool constructor = frame_inspector.IsConstructor();
Steve Blocka7e24c12009-10-30 11:49:00 +000010480
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010481 // Get scope info and read from it for local variable information.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010482 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010483 Handle<SharedFunctionInfo> shared(function->shared());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010484 Handle<ScopeInfo> scope_info(shared->scope_info());
10485 ASSERT(*scope_info != ScopeInfo::Empty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010486
Steve Blocka7e24c12009-10-30 11:49:00 +000010487 // Get the locals names and values into a temporary array.
10488 //
10489 // TODO(1240907): Hide compiler-introduced stack variables
10490 // (e.g. .result)? For users of the debugger, they will probably be
10491 // confusing.
Steve Block44f0eee2011-05-26 01:26:41 +010010492 Handle<FixedArray> locals =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010493 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010494
Ben Murdochb0fe1622011-05-05 13:52:32 +010010495 // Fill in the values of the locals.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010496 int i = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010497 for (; i < scope_info->StackLocalCount(); ++i) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010498 // Use the value from the stack.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010499 locals->set(i * 2, scope_info->LocalName(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010500 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
10501 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010502 if (i < scope_info->LocalCount()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010503 // Get the context containing declarations.
10504 Handle<Context> context(
10505 Context::cast(it.frame()->context())->declaration_context());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010506 for (; i < scope_info->LocalCount(); ++i) {
10507 Handle<String> name(scope_info->LocalName(i));
10508 VariableMode mode;
10509 InitializationFlag init_flag;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010510 locals->set(i * 2, *name);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010511 locals->set(i * 2 + 1, context->get(
10512 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
Steve Blocka7e24c12009-10-30 11:49:00 +000010513 }
10514 }
10515
Ben Murdochb0fe1622011-05-05 13:52:32 +010010516 // Check whether this frame is positioned at return. If not top
10517 // frame or if the frame is optimized it cannot be at a return.
10518 bool at_return = false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010519 if (!is_optimized && index == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +010010520 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010521 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010522
10523 // If positioned just before return find the value to be returned and add it
10524 // to the frame information.
Steve Block44f0eee2011-05-26 01:26:41 +010010525 Handle<Object> return_value = isolate->factory()->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010526 if (at_return) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010527 StackFrameIterator it2(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010528 Address internal_frame_sp = NULL;
10529 while (!it2.done()) {
10530 if (it2.frame()->is_internal()) {
10531 internal_frame_sp = it2.frame()->sp();
10532 } else {
10533 if (it2.frame()->is_java_script()) {
10534 if (it2.frame()->id() == it.frame()->id()) {
10535 // The internal frame just before the JavaScript frame contains the
10536 // value to return on top. A debug break at return will create an
10537 // internal frame to store the return value (eax/rax/r0) before
10538 // entering the debug break exit frame.
10539 if (internal_frame_sp != NULL) {
10540 return_value =
Steve Block44f0eee2011-05-26 01:26:41 +010010541 Handle<Object>(Memory::Object_at(internal_frame_sp),
10542 isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010543 break;
10544 }
10545 }
10546 }
10547
10548 // Indicate that the previous frame was not an internal frame.
10549 internal_frame_sp = NULL;
10550 }
10551 it2.Advance();
10552 }
10553 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010554
10555 // Now advance to the arguments adapter frame (if any). It contains all
10556 // the provided parameters whereas the function frame always have the number
10557 // of arguments matching the functions parameters. The rest of the
10558 // information (except for what is collected above) is the same.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010559 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010560 it.AdvanceToArgumentsFrame();
10561 frame_inspector.SetArgumentsFrame(it.frame());
10562 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010563
10564 // Find the number of arguments to fill. At least fill the number of
10565 // parameters for the function and fill more if more parameters are provided.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010566 int argument_count = scope_info->ParameterCount();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010567 if (argument_count < frame_inspector.GetParametersCount()) {
10568 argument_count = frame_inspector.GetParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010569 }
10570
10571 // Calculate the size of the result.
10572 int details_size = kFrameDetailsFirstDynamicIndex +
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010573 2 * (argument_count + scope_info->LocalCount()) +
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010574 (at_return ? 1 : 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010575 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +000010576
10577 // Add the frame id.
10578 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10579
10580 // Add the function (same as in function frame).
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010581 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000010582
10583 // Add the arguments count.
10584 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10585
10586 // Add the locals count
10587 details->set(kFrameDetailsLocalCountIndex,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010588 Smi::FromInt(scope_info->LocalCount()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010589
10590 // Add the source position.
10591 if (position != RelocInfo::kNoPosition) {
10592 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10593 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010594 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010595 }
10596
10597 // Add the constructor information.
Steve Block44f0eee2011-05-26 01:26:41 +010010598 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
Steve Blocka7e24c12009-10-30 11:49:00 +000010599
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010600 // Add the at return information.
Steve Block44f0eee2011-05-26 01:26:41 +010010601 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010602
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010603 // Add flags to indicate information on whether this frame is
10604 // bit 0: invoked in the debugger context.
10605 // bit 1: optimized frame.
10606 // bit 2: inlined in optimized frame
10607 int flags = 0;
10608 if (*save->context() == *isolate->debug()->debug_context()) {
10609 flags |= 1 << 0;
10610 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010611 if (is_optimized) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010612 flags |= 1 << 1;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010613 flags |= inlined_jsframe_index << 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010614 }
10615 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +000010616
10617 // Fill the dynamic part.
10618 int details_index = kFrameDetailsFirstDynamicIndex;
10619
10620 // Add arguments name and value.
10621 for (int i = 0; i < argument_count; i++) {
10622 // Name of the argument.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010623 if (i < scope_info->ParameterCount()) {
10624 details->set(details_index++, scope_info->ParameterName(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010625 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010626 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010627 }
10628
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010629 // Parameter value.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010630 if (i < frame_inspector.GetParametersCount()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010631 // Get the value from the stack.
10632 details->set(details_index++, frame_inspector.GetParameter(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010633 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010634 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010635 }
10636 }
10637
10638 // Add locals name and value from the temporary copy from the function frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010639 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010640 details->set(details_index++, locals->get(i));
10641 }
10642
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010643 // Add the value being returned.
10644 if (at_return) {
10645 details->set(details_index++, *return_value);
10646 }
10647
Steve Blocka7e24c12009-10-30 11:49:00 +000010648 // Add the receiver (same as in function frame).
10649 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10650 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
Steve Block44f0eee2011-05-26 01:26:41 +010010651 Handle<Object> receiver(it.frame()->receiver(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010652 if (!receiver->IsJSObject() &&
10653 shared->is_classic_mode() &&
10654 !shared->native()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010655 // If the receiver is not a JSObject and the function is not a
10656 // builtin or strict-mode we have hit an optimization where a
10657 // value object is not converted into a wrapped JS objects. To
10658 // hide this optimization from the debugger, we wrap the receiver
Steve Blocka7e24c12009-10-30 11:49:00 +000010659 // by creating correct wrapper object based on the calling frame's
10660 // global context.
10661 it.Advance();
10662 Handle<Context> calling_frames_global_context(
10663 Context::cast(Context::cast(it.frame()->context())->global_context()));
Steve Block44f0eee2011-05-26 01:26:41 +010010664 receiver =
10665 isolate->factory()->ToObject(receiver, calling_frames_global_context);
Steve Blocka7e24c12009-10-30 11:49:00 +000010666 }
10667 details->set(kFrameDetailsReceiverIndex, *receiver);
10668
10669 ASSERT_EQ(details_size, details_index);
Steve Block44f0eee2011-05-26 01:26:41 +010010670 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010671}
10672
10673
10674// Copy all the context locals into an object used to materialize a scope.
Steve Block1e0659c2011-05-24 12:43:12 +010010675static bool CopyContextLocalsToScopeObject(
Steve Block44f0eee2011-05-26 01:26:41 +010010676 Isolate* isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010677 Handle<ScopeInfo> scope_info,
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010678 Handle<Context> context,
10679 Handle<JSObject> scope_object) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010680 // Fill all context locals to the context extension.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010681 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10682 VariableMode mode;
10683 InitializationFlag init_flag;
10684 int context_index = scope_info->ContextSlotIndex(
10685 scope_info->ContextLocalName(i), &mode, &init_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +000010686
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010687 RETURN_IF_EMPTY_HANDLE_VALUE(
10688 isolate,
10689 SetProperty(scope_object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010690 Handle<String>(scope_info->ContextLocalName(i)),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010691 Handle<Object>(context->get(context_index), isolate),
10692 NONE,
10693 kNonStrictMode),
10694 false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010695 }
Steve Block1e0659c2011-05-24 12:43:12 +010010696
10697 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000010698}
10699
10700
10701// Create a plain JSObject which materializes the local scope for the specified
10702// frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010703static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010704 Isolate* isolate,
10705 JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010706 FrameInspector* frame_inspector) {
10707 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010708 Handle<SharedFunctionInfo> shared(function->shared());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010709 Handle<ScopeInfo> scope_info(shared->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000010710
10711 // Allocate and initialize a JSObject with all the arguments, stack locals
10712 // heap locals and extension properties of the debugged function.
Steve Block44f0eee2011-05-26 01:26:41 +010010713 Handle<JSObject> local_scope =
10714 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +000010715
10716 // First fill all parameters.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010717 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
10718 Handle<Object> value(
10719 i < frame_inspector->GetParametersCount() ?
10720 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10721
Steve Block1e0659c2011-05-24 12:43:12 +010010722 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +010010723 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +010010724 SetProperty(local_scope,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010725 Handle<String>(scope_info->ParameterName(i)),
10726 value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010727 NONE,
10728 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010010729 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000010730 }
10731
10732 // Second fill all stack locals.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010733 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
Steve Block1e0659c2011-05-24 12:43:12 +010010734 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +010010735 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +010010736 SetProperty(local_scope,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010737 Handle<String>(scope_info->StackLocalName(i)),
10738 Handle<Object>(frame_inspector->GetExpression(i)),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010739 NONE,
10740 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010010741 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000010742 }
10743
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010744 if (scope_info->HasContext()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010745 // Third fill all context locals.
10746 Handle<Context> frame_context(Context::cast(frame->context()));
10747 Handle<Context> function_context(frame_context->declaration_context());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010748 if (!CopyContextLocalsToScopeObject(
10749 isolate, scope_info, function_context, local_scope)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010750 return Handle<JSObject>();
10751 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010752
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010753 // Finally copy any properties from the function context extension.
10754 // These will be variables introduced by eval.
10755 if (function_context->closure() == *function) {
10756 if (function_context->has_extension() &&
10757 !function_context->IsGlobalContext()) {
10758 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010759 bool threw = false;
10760 Handle<FixedArray> keys =
10761 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10762 if (threw) return Handle<JSObject>();
10763
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010764 for (int i = 0; i < keys->length(); i++) {
10765 // Names of variables introduced by eval are strings.
10766 ASSERT(keys->get(i)->IsString());
10767 Handle<String> key(String::cast(keys->get(i)));
10768 RETURN_IF_EMPTY_HANDLE_VALUE(
10769 isolate,
10770 SetProperty(local_scope,
10771 key,
10772 GetProperty(ext, key),
10773 NONE,
10774 kNonStrictMode),
10775 Handle<JSObject>());
10776 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010777 }
10778 }
10779 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010780
Steve Blocka7e24c12009-10-30 11:49:00 +000010781 return local_scope;
10782}
10783
10784
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010785static Handle<JSObject> MaterializeLocalScope(
10786 Isolate* isolate,
10787 JavaScriptFrame* frame,
10788 int inlined_jsframe_index) {
10789 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10790 return MaterializeLocalScopeWithFrameInspector(isolate,
10791 frame,
10792 &frame_inspector);
10793}
10794
10795
Steve Blocka7e24c12009-10-30 11:49:00 +000010796// Create a plain JSObject which materializes the closure content for the
10797// context.
Steve Block44f0eee2011-05-26 01:26:41 +010010798static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10799 Handle<Context> context) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010800 ASSERT(context->IsFunctionContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000010801
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010802 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010803 Handle<ScopeInfo> scope_info(shared->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000010804
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010805 // Allocate and initialize a JSObject with all the content of this function
Steve Blocka7e24c12009-10-30 11:49:00 +000010806 // closure.
Steve Block44f0eee2011-05-26 01:26:41 +010010807 Handle<JSObject> closure_scope =
10808 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +000010809
Steve Blocka7e24c12009-10-30 11:49:00 +000010810 // Fill all context locals to the context extension.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010811 if (!CopyContextLocalsToScopeObject(
10812 isolate, scope_info, context, closure_scope)) {
Steve Block1e0659c2011-05-24 12:43:12 +010010813 return Handle<JSObject>();
10814 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010815
10816 // Finally copy any properties from the function context extension. This will
10817 // be variables introduced by eval.
10818 if (context->has_extension()) {
10819 Handle<JSObject> ext(JSObject::cast(context->extension()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010820 bool threw = false;
10821 Handle<FixedArray> keys =
10822 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10823 if (threw) return Handle<JSObject>();
10824
Steve Blocka7e24c12009-10-30 11:49:00 +000010825 for (int i = 0; i < keys->length(); i++) {
10826 // Names of variables introduced by eval are strings.
10827 ASSERT(keys->get(i)->IsString());
10828 Handle<String> key(String::cast(keys->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +010010829 RETURN_IF_EMPTY_HANDLE_VALUE(
10830 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010831 SetProperty(closure_scope,
10832 key,
10833 GetProperty(ext, key),
10834 NONE,
10835 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010010836 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000010837 }
10838 }
10839
10840 return closure_scope;
10841}
10842
10843
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010844// Create a plain JSObject which materializes the scope for the specified
10845// catch context.
10846static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10847 Handle<Context> context) {
10848 ASSERT(context->IsCatchContext());
10849 Handle<String> name(String::cast(context->extension()));
10850 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10851 Handle<JSObject> catch_scope =
10852 isolate->factory()->NewJSObject(isolate->object_function());
10853 RETURN_IF_EMPTY_HANDLE_VALUE(
10854 isolate,
10855 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10856 Handle<JSObject>());
10857 return catch_scope;
10858}
10859
10860
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010861// Create a plain JSObject which materializes the block scope for the specified
10862// block context.
10863static Handle<JSObject> MaterializeBlockScope(
10864 Isolate* isolate,
10865 Handle<Context> context) {
10866 ASSERT(context->IsBlockContext());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010867 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010868
10869 // Allocate and initialize a JSObject with all the arguments, stack locals
10870 // heap locals and extension properties of the debugged function.
10871 Handle<JSObject> block_scope =
10872 isolate->factory()->NewJSObject(isolate->object_function());
10873
10874 // Fill all context locals.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010875 if (!CopyContextLocalsToScopeObject(
10876 isolate, scope_info, context, block_scope)) {
10877 return Handle<JSObject>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010878 }
10879
10880 return block_scope;
10881}
10882
10883
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010884// Create a plain JSObject which materializes the module scope for the specified
10885// module context.
10886static Handle<JSObject> MaterializeModuleScope(
10887 Isolate* isolate,
10888 Handle<Context> context) {
10889 ASSERT(context->IsModuleContext());
10890 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10891
10892 // Allocate and initialize a JSObject with all the members of the debugged
10893 // module.
10894 Handle<JSObject> module_scope =
10895 isolate->factory()->NewJSObject(isolate->object_function());
10896
10897 // Fill all context locals.
10898 if (!CopyContextLocalsToScopeObject(
10899 isolate, scope_info, context, module_scope)) {
10900 return Handle<JSObject>();
10901 }
10902
10903 return module_scope;
10904}
10905
10906
10907// Iterate over the actual scopes visible from a stack frame. The iteration
10908// proceeds from the innermost visible nested scope outwards. All scopes are
Steve Blocka7e24c12009-10-30 11:49:00 +000010909// backed by an actual context except the local scope, which is inserted
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010910// "artificially" in the context chain.
Steve Blocka7e24c12009-10-30 11:49:00 +000010911class ScopeIterator {
10912 public:
10913 enum ScopeType {
10914 ScopeTypeGlobal = 0,
10915 ScopeTypeLocal,
10916 ScopeTypeWith,
10917 ScopeTypeClosure,
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010918 ScopeTypeCatch,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010919 ScopeTypeBlock,
10920 ScopeTypeModule
Steve Blocka7e24c12009-10-30 11:49:00 +000010921 };
10922
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010923 ScopeIterator(Isolate* isolate,
10924 JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010925 int inlined_jsframe_index)
Steve Block44f0eee2011-05-26 01:26:41 +010010926 : isolate_(isolate),
10927 frame_(frame),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010928 inlined_jsframe_index_(inlined_jsframe_index),
Steve Blocka7e24c12009-10-30 11:49:00 +000010929 function_(JSFunction::cast(frame->function())),
10930 context_(Context::cast(frame->context())),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010931 nested_scope_chain_(4) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010932
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010933 // Catch the case when the debugger stops in an internal function.
10934 Handle<SharedFunctionInfo> shared_info(function_->shared());
10935 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10936 if (shared_info->script() == isolate->heap()->undefined_value()) {
10937 while (context_->closure() == *function_) {
10938 context_ = Handle<Context>(context_->previous(), isolate_);
10939 }
10940 return;
10941 }
10942
10943 // Get the debug info (create it if it does not exist).
10944 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10945 // Return if ensuring debug info failed.
10946 return;
10947 }
10948 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10949
10950 // Find the break point where execution has stopped.
10951 BreakLocationIterator break_location_iterator(debug_info,
10952 ALL_BREAK_LOCATIONS);
10953 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10954 if (break_location_iterator.IsExit()) {
10955 // We are within the return sequence. At the momemt it is not possible to
10956 // get a source position which is consistent with the current scope chain.
10957 // Thus all nested with, catch and block contexts are skipped and we only
10958 // provide the function scope.
10959 if (scope_info->HasContext()) {
10960 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10961 } else {
10962 while (context_->closure() == *function_) {
10963 context_ = Handle<Context>(context_->previous(), isolate_);
10964 }
10965 }
10966 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10967 } else {
10968 // Reparse the code and analyze the scopes.
10969 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
10970 Handle<Script> script(Script::cast(shared_info->script()));
10971 Scope* scope = NULL;
10972
10973 // Check whether we are in global, eval or function code.
10974 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10975 if (scope_info->Type() != FUNCTION_SCOPE) {
10976 // Global or eval code.
10977 CompilationInfo info(script);
10978 if (scope_info->Type() == GLOBAL_SCOPE) {
10979 info.MarkAsGlobal();
10980 } else {
10981 ASSERT(scope_info->Type() == EVAL_SCOPE);
10982 info.MarkAsEval();
10983 info.SetCallingContext(Handle<Context>(function_->context()));
10984 }
10985 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
10986 scope = info.function()->scope();
10987 }
10988 } else {
10989 // Function code
10990 CompilationInfo info(shared_info);
10991 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
10992 scope = info.function()->scope();
10993 }
10994 }
10995
10996 // Retrieve the scope chain for the current position.
10997 if (scope != NULL) {
10998 int source_position = shared_info->code()->SourcePosition(frame_->pc());
10999 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11000 } else {
11001 // A failed reparse indicates that the preparser has diverged from the
11002 // parser or that the preparse data given to the initial parse has been
11003 // faulty. We fail in debug mode but in release mode we only provide the
11004 // information we get from the context chain but nothing about
11005 // completely stack allocated scopes or stack allocated locals.
11006 UNREACHABLE();
11007 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011008 }
11009 }
11010
11011 // More scopes?
11012 bool Done() { return context_.is_null(); }
11013
11014 // Move to the next scope.
11015 void Next() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011016 ScopeType scope_type = Type();
11017 if (scope_type == ScopeTypeGlobal) {
11018 // The global scope is always the last in the chain.
11019 ASSERT(context_->IsGlobalContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011020 context_ = Handle<Context>();
11021 return;
11022 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011023 if (nested_scope_chain_.is_empty()) {
11024 context_ = Handle<Context>(context_->previous(), isolate_);
11025 } else {
11026 if (nested_scope_chain_.last()->HasContext()) {
11027 ASSERT(context_->previous() != NULL);
11028 context_ = Handle<Context>(context_->previous(), isolate_);
11029 }
11030 nested_scope_chain_.RemoveLast();
Steve Blocka7e24c12009-10-30 11:49:00 +000011031 }
11032 }
11033
11034 // Return the type of the current scope.
Ben Murdoch589d6972011-11-30 16:04:58 +000011035 ScopeType Type() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011036 if (!nested_scope_chain_.is_empty()) {
11037 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11038 switch (scope_info->Type()) {
11039 case FUNCTION_SCOPE:
11040 ASSERT(context_->IsFunctionContext() ||
11041 !scope_info->HasContext());
11042 return ScopeTypeLocal;
11043 case MODULE_SCOPE:
11044 ASSERT(context_->IsModuleContext());
11045 return ScopeTypeModule;
11046 case GLOBAL_SCOPE:
11047 ASSERT(context_->IsGlobalContext());
11048 return ScopeTypeGlobal;
11049 case WITH_SCOPE:
11050 ASSERT(context_->IsWithContext());
11051 return ScopeTypeWith;
11052 case CATCH_SCOPE:
11053 ASSERT(context_->IsCatchContext());
11054 return ScopeTypeCatch;
11055 case BLOCK_SCOPE:
11056 ASSERT(!scope_info->HasContext() ||
11057 context_->IsBlockContext());
11058 return ScopeTypeBlock;
11059 case EVAL_SCOPE:
11060 UNREACHABLE();
11061 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011062 }
11063 if (context_->IsGlobalContext()) {
11064 ASSERT(context_->global()->IsGlobalObject());
11065 return ScopeTypeGlobal;
11066 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011067 if (context_->IsFunctionContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011068 return ScopeTypeClosure;
11069 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011070 if (context_->IsCatchContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011071 return ScopeTypeCatch;
11072 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011073 if (context_->IsBlockContext()) {
11074 return ScopeTypeBlock;
11075 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011076 if (context_->IsModuleContext()) {
11077 return ScopeTypeModule;
11078 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011079 ASSERT(context_->IsWithContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011080 return ScopeTypeWith;
11081 }
11082
11083 // Return the JavaScript object with the content of the current scope.
11084 Handle<JSObject> ScopeObject() {
11085 switch (Type()) {
11086 case ScopeIterator::ScopeTypeGlobal:
11087 return Handle<JSObject>(CurrentContext()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +000011088 case ScopeIterator::ScopeTypeLocal:
11089 // Materialize the content of the local scope into a JSObject.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011090 ASSERT(nested_scope_chain_.length() == 1);
11091 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011092 case ScopeIterator::ScopeTypeWith:
Steve Blocka7e24c12009-10-30 11:49:00 +000011093 // Return the with object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011094 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11095 case ScopeIterator::ScopeTypeCatch:
11096 return MaterializeCatchScope(isolate_, CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011097 case ScopeIterator::ScopeTypeClosure:
11098 // Materialize the content of the closure scope into a JSObject.
Steve Block44f0eee2011-05-26 01:26:41 +010011099 return MaterializeClosure(isolate_, CurrentContext());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011100 case ScopeIterator::ScopeTypeBlock:
11101 return MaterializeBlockScope(isolate_, CurrentContext());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011102 case ScopeIterator::ScopeTypeModule:
11103 return MaterializeModuleScope(isolate_, CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011104 }
11105 UNREACHABLE();
11106 return Handle<JSObject>();
11107 }
11108
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011109 Handle<ScopeInfo> CurrentScopeInfo() {
11110 if (!nested_scope_chain_.is_empty()) {
11111 return nested_scope_chain_.last();
11112 } else if (context_->IsBlockContext()) {
11113 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11114 } else if (context_->IsFunctionContext()) {
11115 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11116 }
11117 return Handle<ScopeInfo>::null();
11118 }
11119
Steve Blocka7e24c12009-10-30 11:49:00 +000011120 // Return the context for this scope. For the local context there might not
11121 // be an actual context.
11122 Handle<Context> CurrentContext() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011123 if (Type() == ScopeTypeGlobal ||
11124 nested_scope_chain_.is_empty()) {
11125 return context_;
11126 } else if (nested_scope_chain_.last()->HasContext()) {
11127 return context_;
11128 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +000011129 return Handle<Context>();
11130 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011131 }
11132
11133#ifdef DEBUG
11134 // Debug print of the content of the current scope.
11135 void DebugPrint() {
11136 switch (Type()) {
11137 case ScopeIterator::ScopeTypeGlobal:
11138 PrintF("Global:\n");
11139 CurrentContext()->Print();
11140 break;
11141
11142 case ScopeIterator::ScopeTypeLocal: {
11143 PrintF("Local:\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011144 function_->shared()->scope_info()->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011145 if (!CurrentContext().is_null()) {
11146 CurrentContext()->Print();
11147 if (CurrentContext()->has_extension()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011148 Handle<Object> extension(CurrentContext()->extension());
Steve Blocka7e24c12009-10-30 11:49:00 +000011149 if (extension->IsJSContextExtensionObject()) {
11150 extension->Print();
11151 }
11152 }
11153 }
11154 break;
11155 }
11156
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011157 case ScopeIterator::ScopeTypeWith:
Steve Blocka7e24c12009-10-30 11:49:00 +000011158 PrintF("With:\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011159 CurrentContext()->extension()->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011160 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011161
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011162 case ScopeIterator::ScopeTypeCatch:
Steve Blocka7e24c12009-10-30 11:49:00 +000011163 PrintF("Catch:\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011164 CurrentContext()->extension()->Print();
11165 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011166 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011167
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011168 case ScopeIterator::ScopeTypeClosure:
Steve Blocka7e24c12009-10-30 11:49:00 +000011169 PrintF("Closure:\n");
11170 CurrentContext()->Print();
11171 if (CurrentContext()->has_extension()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011172 Handle<Object> extension(CurrentContext()->extension());
Steve Blocka7e24c12009-10-30 11:49:00 +000011173 if (extension->IsJSContextExtensionObject()) {
11174 extension->Print();
11175 }
11176 }
11177 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011178
11179 default:
11180 UNREACHABLE();
11181 }
11182 PrintF("\n");
11183 }
11184#endif
11185
11186 private:
Steve Block44f0eee2011-05-26 01:26:41 +010011187 Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011188 JavaScriptFrame* frame_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011189 int inlined_jsframe_index_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011190 Handle<JSFunction> function_;
11191 Handle<Context> context_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011192 List<Handle<ScopeInfo> > nested_scope_chain_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011193
11194 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11195};
11196
11197
Ben Murdoch8b112d22011-06-08 16:22:53 +010011198RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010011199 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011200 ASSERT(args.length() == 2);
11201
11202 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011203 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011204 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11205 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011206 if (!maybe_check->ToObject(&check)) return maybe_check;
11207 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011208 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011209
11210 // Get the frame where the debugging is performed.
11211 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011212 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000011213 JavaScriptFrame* frame = it.frame();
11214
11215 // Count the visible scopes.
11216 int n = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011217 for (ScopeIterator it(isolate, frame, 0);
11218 !it.Done();
11219 it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011220 n++;
11221 }
11222
11223 return Smi::FromInt(n);
11224}
11225
11226
11227static const int kScopeDetailsTypeIndex = 0;
11228static const int kScopeDetailsObjectIndex = 1;
11229static const int kScopeDetailsSize = 2;
11230
11231// Return an array with scope details
11232// args[0]: number: break id
11233// args[1]: number: frame index
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011234// args[2]: number: inlined frame index
11235// args[3]: number: scope index
Steve Blocka7e24c12009-10-30 11:49:00 +000011236//
11237// The array returned contains the following information:
11238// 0: Scope type
11239// 1: Scope object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011240RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010011241 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011242 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000011243
11244 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011245 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011246 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11247 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011248 if (!maybe_check->ToObject(&check)) return maybe_check;
11249 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011250 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11251 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011252 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011253
11254 // Get the frame where the debugging is performed.
11255 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011256 JavaScriptFrameIterator frame_it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000011257 JavaScriptFrame* frame = frame_it.frame();
11258
11259 // Find the requested scope.
11260 int n = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011261 ScopeIterator it(isolate, frame, inlined_jsframe_index);
Steve Blocka7e24c12009-10-30 11:49:00 +000011262 for (; !it.Done() && n < index; it.Next()) {
11263 n++;
11264 }
11265 if (it.Done()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011266 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011267 }
11268
11269 // Calculate the size of the result.
11270 int details_size = kScopeDetailsSize;
Steve Block44f0eee2011-05-26 01:26:41 +010011271 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +000011272
11273 // Fill in scope details.
11274 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011275 Handle<JSObject> scope_object = it.ScopeObject();
Steve Block44f0eee2011-05-26 01:26:41 +010011276 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011277 details->set(kScopeDetailsObjectIndex, *scope_object);
Steve Blocka7e24c12009-10-30 11:49:00 +000011278
Steve Block44f0eee2011-05-26 01:26:41 +010011279 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011280}
11281
11282
Ben Murdoch8b112d22011-06-08 16:22:53 +010011283RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
Steve Block44f0eee2011-05-26 01:26:41 +010011284 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011285 ASSERT(args.length() == 0);
11286
11287#ifdef DEBUG
11288 // Print the scopes for the top frame.
11289 StackFrameLocator locator;
11290 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011291 for (ScopeIterator it(isolate, frame, 0);
11292 !it.Done();
11293 it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011294 it.DebugPrint();
11295 }
11296#endif
Steve Block44f0eee2011-05-26 01:26:41 +010011297 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011298}
11299
11300
Ben Murdoch8b112d22011-06-08 16:22:53 +010011301RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010011302 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011303 ASSERT(args.length() == 1);
11304
11305 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011306 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011307 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11308 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011309 if (!maybe_result->ToObject(&result)) return maybe_result;
11310 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011311
11312 // Count all archived V8 threads.
11313 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011314 for (ThreadState* thread =
11315 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000011316 thread != NULL;
11317 thread = thread->Next()) {
11318 n++;
11319 }
11320
11321 // Total number of threads is current thread and archived threads.
11322 return Smi::FromInt(n + 1);
11323}
11324
11325
11326static const int kThreadDetailsCurrentThreadIndex = 0;
11327static const int kThreadDetailsThreadIdIndex = 1;
11328static const int kThreadDetailsSize = 2;
11329
11330// Return an array with thread details
11331// args[0]: number: break id
11332// args[1]: number: thread index
11333//
11334// The array returned contains the following information:
11335// 0: Is current thread?
11336// 1: Thread id
Ben Murdoch8b112d22011-06-08 16:22:53 +010011337RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010011338 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011339 ASSERT(args.length() == 2);
11340
11341 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011342 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011343 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11344 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011345 if (!maybe_check->ToObject(&check)) return maybe_check;
11346 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011347 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11348
11349 // Allocate array for result.
Steve Block44f0eee2011-05-26 01:26:41 +010011350 Handle<FixedArray> details =
11351 isolate->factory()->NewFixedArray(kThreadDetailsSize);
Steve Blocka7e24c12009-10-30 11:49:00 +000011352
11353 // Thread index 0 is current thread.
11354 if (index == 0) {
11355 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010011356 details->set(kThreadDetailsCurrentThreadIndex,
11357 isolate->heap()->true_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011358 details->set(kThreadDetailsThreadIdIndex,
Ben Murdoch8b112d22011-06-08 16:22:53 +010011359 Smi::FromInt(ThreadId::Current().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011360 } else {
11361 // Find the thread with the requested index.
11362 int n = 1;
Steve Block44f0eee2011-05-26 01:26:41 +010011363 ThreadState* thread =
11364 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000011365 while (index != n && thread != NULL) {
11366 thread = thread->Next();
11367 n++;
11368 }
11369 if (thread == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010011370 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011371 }
11372
11373 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010011374 details->set(kThreadDetailsCurrentThreadIndex,
11375 isolate->heap()->false_value());
Ben Murdoch8b112d22011-06-08 16:22:53 +010011376 details->set(kThreadDetailsThreadIdIndex,
11377 Smi::FromInt(thread->id().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011378 }
11379
11380 // Convert to JS array and return.
Steve Block44f0eee2011-05-26 01:26:41 +010011381 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011382}
11383
11384
Ben Murdochbb769b22010-08-11 14:56:33 +010011385// Sets the disable break state
11386// args[0]: disable break state
Ben Murdoch8b112d22011-06-08 16:22:53 +010011387RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
Steve Block44f0eee2011-05-26 01:26:41 +010011388 HandleScope scope(isolate);
Ben Murdochbb769b22010-08-11 14:56:33 +010011389 ASSERT(args.length() == 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011390 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
Steve Block44f0eee2011-05-26 01:26:41 +010011391 isolate->debug()->set_disable_break(disable_break);
11392 return isolate->heap()->undefined_value();
Ben Murdochbb769b22010-08-11 14:56:33 +010011393}
11394
11395
Ben Murdoch8b112d22011-06-08 16:22:53 +010011396RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
Steve Block44f0eee2011-05-26 01:26:41 +010011397 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011398 ASSERT(args.length() == 1);
11399
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011400 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000011401 Handle<SharedFunctionInfo> shared(fun->shared());
11402 // Find the number of break points
11403 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
Steve Block44f0eee2011-05-26 01:26:41 +010011404 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011405 // Return array as JS array
Steve Block44f0eee2011-05-26 01:26:41 +010011406 return *isolate->factory()->NewJSArrayWithElements(
Steve Blocka7e24c12009-10-30 11:49:00 +000011407 Handle<FixedArray>::cast(break_locations));
11408}
11409
11410
11411// Set a break point in a function
11412// args[0]: function
11413// args[1]: number: break source position (within the function source)
11414// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011415RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011416 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011417 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011418 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000011419 Handle<SharedFunctionInfo> shared(fun->shared());
11420 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11421 RUNTIME_ASSERT(source_position >= 0);
11422 Handle<Object> break_point_object_arg = args.at<Object>(2);
11423
11424 // Set break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011425 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11426 &source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011427
Steve Block8defd9f2010-07-08 12:39:36 +010011428 return Smi::FromInt(source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011429}
11430
11431
Steve Block44f0eee2011-05-26 01:26:41 +010011432Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11433 Handle<Script> script,
Steve Blocka7e24c12009-10-30 11:49:00 +000011434 int position) {
11435 // Iterate the heap looking for SharedFunctionInfo generated from the
11436 // script. The inner most SharedFunctionInfo containing the source position
11437 // for the requested break point is found.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011438 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
Steve Blocka7e24c12009-10-30 11:49:00 +000011439 // which is found is not compiled it is compiled and the heap is iterated
11440 // again as the compilation might create inner functions from the newly
11441 // compiled function and the actual requested break point might be in one of
11442 // these functions.
11443 bool done = false;
11444 // The current candidate for the source position:
11445 int target_start_position = RelocInfo::kNoPosition;
11446 Handle<SharedFunctionInfo> target;
Steve Blocka7e24c12009-10-30 11:49:00 +000011447 while (!done) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011448 { // Extra scope for iterator and no-allocation.
11449 isolate->heap()->EnsureHeapIsIterable();
11450 AssertNoAllocation no_alloc_during_heap_iteration;
11451 HeapIterator iterator;
11452 for (HeapObject* obj = iterator.next();
11453 obj != NULL; obj = iterator.next()) {
11454 if (obj->IsSharedFunctionInfo()) {
11455 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11456 if (shared->script() == *script) {
11457 // If the SharedFunctionInfo found has the requested script data and
11458 // contains the source position it is a candidate.
11459 int start_position = shared->function_token_position();
11460 if (start_position == RelocInfo::kNoPosition) {
11461 start_position = shared->start_position();
11462 }
11463 if (start_position <= position &&
11464 position <= shared->end_position()) {
11465 // If there is no candidate or this function is within the current
11466 // candidate this is the new candidate.
11467 if (target.is_null()) {
11468 target_start_position = start_position;
11469 target = shared;
11470 } else {
11471 if (target_start_position == start_position &&
11472 shared->end_position() == target->end_position()) {
11473 // If a top-level function contain only one function
11474 // declartion the source for the top-level and the
11475 // function is the same. In that case prefer the non
11476 // top-level function.
11477 if (!shared->is_toplevel()) {
11478 target_start_position = start_position;
11479 target = shared;
11480 }
11481 } else if (target_start_position <= start_position &&
11482 shared->end_position() <= target->end_position()) {
11483 // This containment check includes equality as a function
11484 // inside a top-level function can share either start or end
11485 // position with the top-level function.
Steve Blocka7e24c12009-10-30 11:49:00 +000011486 target_start_position = start_position;
11487 target = shared;
11488 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011489 }
11490 }
11491 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011492 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011493 } // End for loop.
11494 } // End No allocation scope.
Steve Blocka7e24c12009-10-30 11:49:00 +000011495
Steve Blocka7e24c12009-10-30 11:49:00 +000011496 if (target.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011497 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011498 }
11499
11500 // If the candidate found is compiled we are done. NOTE: when lazy
11501 // compilation of inner functions is introduced some additional checking
11502 // needs to be done here to compile inner functions.
11503 done = target->is_compiled();
11504 if (!done) {
11505 // If the candidate is not compiled compile it to reveal any inner
11506 // functions which might contain the requested source position.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011507 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +000011508 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011509 } // End while loop.
Steve Blocka7e24c12009-10-30 11:49:00 +000011510
11511 return *target;
11512}
11513
11514
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011515// Changes the state of a break point in a script and returns source position
11516// where break point was set. NOTE: Regarding performance see the NOTE for
11517// GetScriptFromScriptData.
Steve Blocka7e24c12009-10-30 11:49:00 +000011518// args[0]: script to set break point in
11519// args[1]: number: break source position (within the script source)
11520// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011521RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011522 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011523 ASSERT(args.length() == 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011524 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000011525 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11526 RUNTIME_ASSERT(source_position >= 0);
11527 Handle<Object> break_point_object_arg = args.at<Object>(2);
11528
11529 // Get the script from the script wrapper.
11530 RUNTIME_ASSERT(wrapper->value()->IsScript());
11531 Handle<Script> script(Script::cast(wrapper->value()));
11532
11533 Object* result = Runtime::FindSharedFunctionInfoInScript(
Steve Block44f0eee2011-05-26 01:26:41 +010011534 isolate, script, source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011535 if (!result->IsUndefined()) {
11536 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11537 // Find position within function. The script position might be before the
11538 // source position of the first function.
11539 int position;
11540 if (shared->start_position() > source_position) {
11541 position = 0;
11542 } else {
11543 position = source_position - shared->start_position();
11544 }
Steve Block44f0eee2011-05-26 01:26:41 +010011545 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011546 position += shared->start_position();
11547 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011548 }
Steve Block44f0eee2011-05-26 01:26:41 +010011549 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011550}
11551
11552
11553// Clear a break point
11554// args[0]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011555RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011556 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011557 ASSERT(args.length() == 1);
11558 Handle<Object> break_point_object_arg = args.at<Object>(0);
11559
11560 // Clear break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011561 isolate->debug()->ClearBreakPoint(break_point_object_arg);
Steve Blocka7e24c12009-10-30 11:49:00 +000011562
Steve Block44f0eee2011-05-26 01:26:41 +010011563 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011564}
11565
11566
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011567// Change the state of break on exceptions.
11568// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11569// args[1]: Boolean indicating on/off.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011570RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010011571 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011572 ASSERT(args.length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011573 RUNTIME_ASSERT(args[0]->IsNumber());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011574 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011575
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011576 // If the number doesn't match an enum value, the ChangeBreakOnException
11577 // function will default to affecting caught exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +000011578 ExceptionBreakType type =
11579 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011580 // Update break point state.
Steve Block44f0eee2011-05-26 01:26:41 +010011581 isolate->debug()->ChangeBreakOnException(type, enable);
11582 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011583}
11584
11585
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011586// Returns the state of break on exceptions
11587// args[0]: boolean indicating uncaught exceptions
Ben Murdoch8b112d22011-06-08 16:22:53 +010011588RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010011589 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011590 ASSERT(args.length() == 1);
11591 RUNTIME_ASSERT(args[0]->IsNumber());
11592
11593 ExceptionBreakType type =
11594 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Steve Block44f0eee2011-05-26 01:26:41 +010011595 bool result = isolate->debug()->IsBreakOnException(type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011596 return Smi::FromInt(result);
11597}
11598
11599
Steve Blocka7e24c12009-10-30 11:49:00 +000011600// Prepare for stepping
11601// args[0]: break id for checking execution state
11602// args[1]: step action from the enumeration StepAction
11603// args[2]: number of times to perform the step, for step out it is the number
11604// of frames to step down.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011605RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
Steve Block44f0eee2011-05-26 01:26:41 +010011606 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011607 ASSERT(args.length() == 3);
11608 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011609 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011610 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11611 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011612 if (!maybe_check->ToObject(&check)) return maybe_check;
11613 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011614 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011615 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011616 }
11617
11618 // Get the step action and check validity.
11619 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11620 if (step_action != StepIn &&
11621 step_action != StepNext &&
11622 step_action != StepOut &&
11623 step_action != StepInMin &&
11624 step_action != StepMin) {
Steve Block44f0eee2011-05-26 01:26:41 +010011625 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011626 }
11627
11628 // Get the number of steps.
11629 int step_count = NumberToInt32(args[2]);
11630 if (step_count < 1) {
Steve Block44f0eee2011-05-26 01:26:41 +010011631 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011632 }
11633
11634 // Clear all current stepping setup.
Steve Block44f0eee2011-05-26 01:26:41 +010011635 isolate->debug()->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +000011636
11637 // Prepare step.
Steve Block44f0eee2011-05-26 01:26:41 +010011638 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11639 step_count);
11640 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011641}
11642
11643
11644// Clear all stepping set by PrepareStep.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011645RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
Steve Block44f0eee2011-05-26 01:26:41 +010011646 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011647 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010011648 isolate->debug()->ClearStepping();
11649 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011650}
11651
11652
11653// Creates a copy of the with context chain. The copy of the context chain is
11654// is linked to the function context supplied.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011655static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11656 Handle<JSFunction> function,
11657 Handle<Context> base,
11658 JavaScriptFrame* frame,
11659 int inlined_jsframe_index) {
11660 HandleScope scope(isolate);
11661 List<Handle<ScopeInfo> > scope_chain;
11662 List<Handle<Context> > context_chain;
11663
11664 ScopeIterator it(isolate, frame, inlined_jsframe_index);
11665 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11666 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11667 ASSERT(!it.Done());
11668 scope_chain.Add(it.CurrentScopeInfo());
11669 context_chain.Add(it.CurrentContext());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011670 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011671
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011672 // At the end of the chain. Return the base context to link to.
11673 Handle<Context> context = base;
11674
11675 // Iteratively copy and or materialize the nested contexts.
11676 while (!scope_chain.is_empty()) {
11677 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11678 Handle<Context> current = context_chain.RemoveLast();
11679 ASSERT(!(scope_info->HasContext() & current.is_null()));
11680
11681 if (scope_info->Type() == CATCH_SCOPE) {
11682 Handle<String> name(String::cast(current->extension()));
11683 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11684 context =
11685 isolate->factory()->NewCatchContext(function,
11686 context,
11687 name,
11688 thrown_object);
11689 } else if (scope_info->Type() == BLOCK_SCOPE) {
11690 // Materialize the contents of the block scope into a JSObject.
11691 Handle<JSObject> block_scope_object =
11692 MaterializeBlockScope(isolate, current);
11693 if (block_scope_object.is_null()) {
11694 return Handle<Context>::null();
11695 }
11696 // Allocate a new function context for the debug evaluation and set the
11697 // extension object.
11698 Handle<Context> new_context =
11699 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11700 function);
11701 new_context->set_extension(*block_scope_object);
11702 new_context->set_previous(*context);
11703 context = new_context;
11704 } else {
11705 ASSERT(scope_info->Type() == WITH_SCOPE);
11706 ASSERT(current->IsWithContext());
11707 Handle<JSObject> extension(JSObject::cast(current->extension()));
11708 context =
11709 isolate->factory()->NewWithContext(function, context, extension);
Ben Murdoch85b71792012-04-11 18:30:58 +010011710 }
Ben Murdoch85b71792012-04-11 18:30:58 +010011711 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011712
11713 return scope.CloseAndEscape(context);
Steve Blocka7e24c12009-10-30 11:49:00 +000011714}
11715
11716
11717// Helper function to find or create the arguments object for
11718// Runtime_DebugEvaluate.
Steve Block44f0eee2011-05-26 01:26:41 +010011719static Handle<Object> GetArgumentsObject(Isolate* isolate,
11720 JavaScriptFrame* frame,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011721 FrameInspector* frame_inspector,
11722 Handle<ScopeInfo> scope_info,
Steve Blocka7e24c12009-10-30 11:49:00 +000011723 Handle<Context> function_context) {
11724 // Try to find the value of 'arguments' to pass as parameter. If it is not
11725 // found (that is the debugged function does not reference 'arguments' and
11726 // does not support eval) then create an 'arguments' object.
11727 int index;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011728 if (scope_info->StackLocalCount() > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +010011729 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011730 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010011731 return Handle<Object>(frame->GetExpression(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011732 }
11733 }
11734
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011735 if (scope_info->HasHeapAllocatedLocals()) {
11736 VariableMode mode;
11737 InitializationFlag init_flag;
11738 index = scope_info->ContextSlotIndex(
11739 isolate->heap()->arguments_symbol(), &mode, &init_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +000011740 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010011741 return Handle<Object>(function_context->get(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011742 }
11743 }
11744
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011745 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11746 int length = frame_inspector->GetParametersCount();
Steve Block44f0eee2011-05-26 01:26:41 +010011747 Handle<JSObject> arguments =
11748 isolate->factory()->NewArgumentsObject(function, length);
11749 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Leon Clarke4515c472010-02-03 11:58:03 +000011750
11751 AssertNoAllocation no_gc;
11752 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000011753 for (int i = 0; i < length; i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011754 array->set(i, frame_inspector->GetParameter(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011755 }
11756 arguments->set_elements(*array);
11757 return arguments;
11758}
11759
11760
Steve Block44f0eee2011-05-26 01:26:41 +010011761static const char kSourceStr[] =
11762 "(function(arguments,__source__){return eval(__source__);})";
11763
11764
Steve Blocka7e24c12009-10-30 11:49:00 +000011765// Evaluate a piece of JavaScript in the context of a stack frame for
11766// debugging. This is accomplished by creating a new context which in its
11767// extension part has all the parameters and locals of the function on the
11768// stack frame. A function which calls eval with the code to evaluate is then
11769// compiled in this context and called in this context. As this context
11770// replaces the context of the function on the stack frame a new (empty)
11771// function is created as well to be used as the closure for the context.
11772// This function and the context acts as replacements for the function on the
11773// stack frame presenting the same view of the values of parameters and
11774// local variables as if the piece of JavaScript was evaluated at the point
11775// where the function on the stack frame is currently stopped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011776RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
Steve Block44f0eee2011-05-26 01:26:41 +010011777 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011778
11779 // Check the execution state and decode arguments frame and source to be
11780 // evaluated.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011781 ASSERT(args.length() == 6);
John Reck59135872010-11-02 12:39:01 -070011782 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011783 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11784 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011785 if (!maybe_check_result->ToObject(&check_result)) {
11786 return maybe_check_result;
11787 }
11788 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011789 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11790 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
11791 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11792 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011793 Handle<Object> additional_context(args[5]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011794
11795 // Handle the processing of break.
11796 DisableBreak disable_break_save(disable_break);
11797
11798 // Get the frame where the debugging is performed.
11799 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011800 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000011801 JavaScriptFrame* frame = it.frame();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011802 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11803 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
11804 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000011805
11806 // Traverse the saved contexts chain to find the active context for the
11807 // selected frame.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011808 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11809
Steve Block44f0eee2011-05-26 01:26:41 +010011810 SaveContext savex(isolate);
11811 isolate->set_context(*(save->context()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011812
11813 // Create the (empty) function replacing the function on the stack frame for
11814 // the purpose of evaluating in the context created below. It is important
11815 // that this function does not describe any parameters and local variables
11816 // in the context. If it does then this will cause problems with the lookup
11817 // in Context::Lookup, where context slots for parameters and local variables
11818 // are looked at before the extension object.
11819 Handle<JSFunction> go_between =
Steve Block44f0eee2011-05-26 01:26:41 +010011820 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11821 isolate->factory()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011822 go_between->set_context(function->context());
11823#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011824 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11825 ASSERT(go_between_scope_info->ParameterCount() == 0);
11826 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000011827#endif
11828
11829 // Materialize the content of the local scope into a JSObject.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011830 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11831 isolate, frame, &frame_inspector);
Steve Block44f0eee2011-05-26 01:26:41 +010011832 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
Steve Blocka7e24c12009-10-30 11:49:00 +000011833
11834 // Allocate a new context for the debug evaluation and set the extension
11835 // object build.
11836 Handle<Context> context =
Steve Block44f0eee2011-05-26 01:26:41 +010011837 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11838 go_between);
Steve Blocka7e24c12009-10-30 11:49:00 +000011839 context->set_extension(*local_scope);
11840 // Copy any with contexts present and chain them in front of this context.
11841 Handle<Context> frame_context(Context::cast(frame->context()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011842 Handle<Context> function_context;
11843 // Get the function's context if it has one.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011844 if (scope_info->HasContext()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011845 function_context = Handle<Context>(frame_context->declaration_context());
11846 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011847 context = CopyNestedScopeContextChain(isolate,
11848 go_between,
11849 context,
11850 frame,
11851 inlined_jsframe_index);
Steve Blocka7e24c12009-10-30 11:49:00 +000011852
Ben Murdochb0fe1622011-05-05 13:52:32 +010011853 if (additional_context->IsJSObject()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011854 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
11855 context =
11856 isolate->factory()->NewWithContext(go_between, context, extension);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011857 }
11858
Steve Blocka7e24c12009-10-30 11:49:00 +000011859 // Wrap the evaluation statement in a new function compiled in the newly
11860 // created context. The function has one parameter which has to be called
11861 // 'arguments'. This it to have access to what would have been 'arguments' in
11862 // the function being debugged.
11863 // function(arguments,__source__) {return eval(__source__);}
Steve Block44f0eee2011-05-26 01:26:41 +010011864
Steve Blocka7e24c12009-10-30 11:49:00 +000011865 Handle<String> function_source =
Steve Block44f0eee2011-05-26 01:26:41 +010011866 isolate->factory()->NewStringFromAscii(
11867 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
Steve Block1e0659c2011-05-24 12:43:12 +010011868
11869 // Currently, the eval code will be executed in non-strict mode,
11870 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010011871 Handle<SharedFunctionInfo> shared =
Steve Blocka7e24c12009-10-30 11:49:00 +000011872 Compiler::CompileEval(function_source,
11873 context,
Steve Block1e0659c2011-05-24 12:43:12 +010011874 context->IsGlobalContext(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011875 CLASSIC_MODE,
11876 RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +010011877 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000011878 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010011879 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
Steve Blocka7e24c12009-10-30 11:49:00 +000011880
11881 // Invoke the result of the compilation to get the evaluation function.
11882 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010011883 Handle<Object> receiver(frame->receiver(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011884 Handle<Object> evaluation_function =
11885 Execution::Call(compiled_function, receiver, 0, NULL,
11886 &has_pending_exception);
11887 if (has_pending_exception) return Failure::Exception();
11888
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011889 Handle<Object> arguments = GetArgumentsObject(isolate,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011890 frame,
11891 &frame_inspector,
11892 scope_info,
11893 function_context);
Steve Blocka7e24c12009-10-30 11:49:00 +000011894
11895 // Invoke the evaluation function and return the result.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011896 Handle<Object> argv[] = { arguments, source };
Steve Blocka7e24c12009-10-30 11:49:00 +000011897 Handle<Object> result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011898 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11899 receiver,
11900 ARRAY_SIZE(argv),
11901 argv,
11902 &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +000011903 if (has_pending_exception) return Failure::Exception();
11904
11905 // Skip the global proxy as it has no properties and always delegates to the
11906 // real global object.
11907 if (result->IsJSGlobalProxy()) {
11908 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11909 }
11910
11911 return *result;
11912}
11913
11914
Ben Murdoch8b112d22011-06-08 16:22:53 +010011915RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
Steve Block44f0eee2011-05-26 01:26:41 +010011916 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011917
11918 // Check the execution state and decode arguments frame and source to be
11919 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011920 ASSERT(args.length() == 4);
John Reck59135872010-11-02 12:39:01 -070011921 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011922 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11923 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011924 if (!maybe_check_result->ToObject(&check_result)) {
11925 return maybe_check_result;
11926 }
11927 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011928 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11929 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011930 Handle<Object> additional_context(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011931
11932 // Handle the processing of break.
11933 DisableBreak disable_break_save(disable_break);
11934
11935 // Enter the top context from before the debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010011936 SaveContext save(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011937 SaveContext* top = &save;
Steve Block44f0eee2011-05-26 01:26:41 +010011938 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011939 top = top->prev();
11940 }
11941 if (top != NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010011942 isolate->set_context(*top->context());
Steve Blocka7e24c12009-10-30 11:49:00 +000011943 }
11944
11945 // Get the global context now set to the top context from before the
11946 // debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010011947 Handle<Context> context = isolate->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000011948
Ben Murdochb0fe1622011-05-05 13:52:32 +010011949 bool is_global = true;
11950
11951 if (additional_context->IsJSObject()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011952 // Create a new with context with the additional context information between
11953 // the context of the debugged function and the eval code to be executed.
11954 context = isolate->factory()->NewWithContext(
11955 Handle<JSFunction>(context->closure()),
11956 context,
11957 Handle<JSObject>::cast(additional_context));
Ben Murdochb0fe1622011-05-05 13:52:32 +010011958 is_global = false;
11959 }
11960
Steve Blocka7e24c12009-10-30 11:49:00 +000011961 // Compile the source to be evaluated.
Steve Block1e0659c2011-05-24 12:43:12 +010011962 // Currently, the eval code will be executed in non-strict mode,
11963 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010011964 Handle<SharedFunctionInfo> shared =
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011965 Compiler::CompileEval(source,
11966 context,
11967 is_global,
11968 CLASSIC_MODE,
11969 RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +010011970 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000011971 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010011972 Handle<JSFunction>(
11973 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11974 context));
Steve Blocka7e24c12009-10-30 11:49:00 +000011975
11976 // Invoke the result of the compilation to get the evaluation function.
11977 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010011978 Handle<Object> receiver = isolate->global();
Steve Blocka7e24c12009-10-30 11:49:00 +000011979 Handle<Object> result =
11980 Execution::Call(compiled_function, receiver, 0, NULL,
11981 &has_pending_exception);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011982 // Clear the oneshot breakpoints so that the debugger does not step further.
11983 isolate->debug()->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +000011984 if (has_pending_exception) return Failure::Exception();
11985 return *result;
11986}
11987
11988
Ben Murdoch8b112d22011-06-08 16:22:53 +010011989RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
Steve Block44f0eee2011-05-26 01:26:41 +010011990 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011991 ASSERT(args.length() == 0);
11992
11993 // Fill the script objects.
Steve Block44f0eee2011-05-26 01:26:41 +010011994 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
Steve Blocka7e24c12009-10-30 11:49:00 +000011995
11996 // Convert the script objects to proper JS objects.
11997 for (int i = 0; i < instances->length(); i++) {
11998 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11999 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12000 // because using
12001 // instances->set(i, *GetScriptWrapper(script))
12002 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012003 // already have dereferenced the instances handle.
Steve Blocka7e24c12009-10-30 11:49:00 +000012004 Handle<JSValue> wrapper = GetScriptWrapper(script);
12005 instances->set(i, *wrapper);
12006 }
12007
12008 // Return result as a JS array.
Steve Block44f0eee2011-05-26 01:26:41 +010012009 Handle<JSObject> result =
12010 isolate->factory()->NewJSObject(isolate->array_function());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012011 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012012 return *result;
12013}
12014
12015
12016// Helper function used by Runtime_DebugReferencedBy below.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012017static int DebugReferencedBy(HeapIterator* iterator,
12018 JSObject* target,
Steve Blocka7e24c12009-10-30 11:49:00 +000012019 Object* instance_filter, int max_references,
12020 FixedArray* instances, int instances_size,
12021 JSFunction* arguments_function) {
12022 NoHandleAllocation ha;
12023 AssertNoAllocation no_alloc;
12024
12025 // Iterate the heap.
12026 int count = 0;
12027 JSObject* last = NULL;
Leon Clarked91b9f72010-01-27 17:25:45 +000012028 HeapObject* heap_obj = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012029 while (((heap_obj = iterator->next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000012030 (max_references == 0 || count < max_references)) {
12031 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012032 if (heap_obj->IsJSObject()) {
12033 // Skip context extension objects and argument arrays as these are
12034 // checked in the context of functions using them.
12035 JSObject* obj = JSObject::cast(heap_obj);
12036 if (obj->IsJSContextExtensionObject() ||
12037 obj->map()->constructor() == arguments_function) {
12038 continue;
12039 }
12040
12041 // Check if the JS object has a reference to the object looked for.
12042 if (obj->ReferencesObject(target)) {
12043 // Check instance filter if supplied. This is normally used to avoid
12044 // references from mirror objects (see Runtime_IsInPrototypeChain).
12045 if (!instance_filter->IsUndefined()) {
12046 Object* V = obj;
12047 while (true) {
12048 Object* prototype = V->GetPrototype();
12049 if (prototype->IsNull()) {
12050 break;
12051 }
12052 if (instance_filter == prototype) {
12053 obj = NULL; // Don't add this object.
12054 break;
12055 }
12056 V = prototype;
12057 }
12058 }
12059
12060 if (obj != NULL) {
12061 // Valid reference found add to instance array if supplied an update
12062 // count.
12063 if (instances != NULL && count < instances_size) {
12064 instances->set(count, obj);
12065 }
12066 last = obj;
12067 count++;
12068 }
12069 }
12070 }
12071 }
12072
12073 // Check for circular reference only. This can happen when the object is only
12074 // referenced from mirrors and has a circular reference in which case the
12075 // object is not really alive and would have been garbage collected if not
12076 // referenced from the mirror.
12077 if (count == 1 && last == target) {
12078 count = 0;
12079 }
12080
12081 // Return the number of referencing objects found.
12082 return count;
12083}
12084
12085
12086// Scan the heap for objects with direct references to an object
12087// args[0]: the object to find references to
12088// args[1]: constructor function for instances to exclude (Mirror)
12089// args[2]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010012090RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012091 ASSERT(args.length() == 3);
12092
12093 // First perform a full GC in order to avoid references from dead objects.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012094 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12095 "%DebugReferencedBy");
12096 // The heap iterator reserves the right to do a GC to make the heap iterable.
12097 // Due to the GC above we know it won't need to do that, but it seems cleaner
12098 // to get the heap iterator constructed before we start having unprotected
12099 // Object* locals that are not protected by handles.
Steve Blocka7e24c12009-10-30 11:49:00 +000012100
12101 // Check parameters.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012102 CONVERT_ARG_CHECKED(JSObject, target, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012103 Object* instance_filter = args[1];
12104 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12105 instance_filter->IsJSObject());
12106 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12107 RUNTIME_ASSERT(max_references >= 0);
12108
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012109
Steve Blocka7e24c12009-10-30 11:49:00 +000012110 // Get the constructor function for context extension and arguments array.
12111 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +010012112 isolate->context()->global_context()->arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +000012113 JSFunction* arguments_function =
12114 JSFunction::cast(arguments_boilerplate->map()->constructor());
12115
12116 // Get the number of referencing objects.
12117 int count;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012118 HeapIterator heap_iterator;
12119 count = DebugReferencedBy(&heap_iterator,
12120 target, instance_filter, max_references,
Steve Blocka7e24c12009-10-30 11:49:00 +000012121 NULL, 0, arguments_function);
12122
12123 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070012124 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010012125 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070012126 if (!maybe_object->ToObject(&object)) return maybe_object;
12127 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012128 FixedArray* instances = FixedArray::cast(object);
12129
12130 // Fill the referencing objects.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012131 // AllocateFixedArray above does not make the heap non-iterable.
12132 ASSERT(HEAP->IsHeapIterable());
12133 HeapIterator heap_iterator2;
12134 count = DebugReferencedBy(&heap_iterator2,
12135 target, instance_filter, max_references,
Steve Blocka7e24c12009-10-30 11:49:00 +000012136 instances, count, arguments_function);
12137
12138 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070012139 Object* result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012140 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
Steve Block44f0eee2011-05-26 01:26:41 +010012141 isolate->context()->global_context()->array_function());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012142 if (!maybe_result->ToObject(&result)) return maybe_result;
12143 return JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012144}
12145
12146
12147// Helper function used by Runtime_DebugConstructedBy below.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012148static int DebugConstructedBy(HeapIterator* iterator,
12149 JSFunction* constructor,
12150 int max_references,
12151 FixedArray* instances,
12152 int instances_size) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012153 AssertNoAllocation no_alloc;
12154
12155 // Iterate the heap.
12156 int count = 0;
Leon Clarked91b9f72010-01-27 17:25:45 +000012157 HeapObject* heap_obj = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012158 while (((heap_obj = iterator->next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000012159 (max_references == 0 || count < max_references)) {
12160 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012161 if (heap_obj->IsJSObject()) {
12162 JSObject* obj = JSObject::cast(heap_obj);
12163 if (obj->map()->constructor() == constructor) {
12164 // Valid reference found add to instance array if supplied an update
12165 // count.
12166 if (instances != NULL && count < instances_size) {
12167 instances->set(count, obj);
12168 }
12169 count++;
12170 }
12171 }
12172 }
12173
12174 // Return the number of referencing objects found.
12175 return count;
12176}
12177
12178
12179// Scan the heap for objects constructed by a specific function.
12180// args[0]: the constructor to find instances of
12181// args[1]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010012182RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012183 ASSERT(args.length() == 2);
12184
12185 // First perform a full GC in order to avoid dead objects.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012186 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12187 "%DebugConstructedBy");
Steve Blocka7e24c12009-10-30 11:49:00 +000012188
12189 // Check parameters.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012190 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012191 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12192 RUNTIME_ASSERT(max_references >= 0);
12193
12194 // Get the number of referencing objects.
12195 int count;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012196 HeapIterator heap_iterator;
12197 count = DebugConstructedBy(&heap_iterator,
12198 constructor,
12199 max_references,
12200 NULL,
12201 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012202
12203 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070012204 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010012205 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070012206 if (!maybe_object->ToObject(&object)) return maybe_object;
12207 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012208 FixedArray* instances = FixedArray::cast(object);
12209
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012210 ASSERT(HEAP->IsHeapIterable());
Steve Blocka7e24c12009-10-30 11:49:00 +000012211 // Fill the referencing objects.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012212 HeapIterator heap_iterator2;
12213 count = DebugConstructedBy(&heap_iterator2,
12214 constructor,
12215 max_references,
12216 instances,
12217 count);
Steve Blocka7e24c12009-10-30 11:49:00 +000012218
12219 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070012220 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010012221 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12222 isolate->context()->global_context()->array_function());
John Reck59135872010-11-02 12:39:01 -070012223 if (!maybe_result->ToObject(&result)) return maybe_result;
12224 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012225 return JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012226}
12227
12228
12229// Find the effective prototype object as returned by __proto__.
12230// args[0]: the object to find the prototype for.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012231RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012232 ASSERT(args.length() == 1);
12233
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012234 CONVERT_ARG_CHECKED(JSObject, obj, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012235
12236 // Use the __proto__ accessor.
12237 return Accessors::ObjectPrototype.getter(obj, NULL);
12238}
12239
12240
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012241// Patches script source (should be called upon BeforeCompile event).
12242RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12243 HandleScope scope(isolate);
12244 ASSERT(args.length() == 2);
12245
12246 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12247 Handle<String> source(String::cast(args[1]));
12248
12249 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12250 Handle<Script> script(Script::cast(script_wrapper->value()));
12251
12252 int compilation_state = Smi::cast(script->compilation_state())->value();
12253 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12254 script->set_source(*source);
12255
12256 return isolate->heap()->undefined_value();
12257}
12258
12259
Ben Murdoch8b112d22011-06-08 16:22:53 +010012260RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012261 ASSERT(args.length() == 0);
12262 CPU::DebugBreak();
Steve Block44f0eee2011-05-26 01:26:41 +010012263 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012264}
12265
12266
Ben Murdoch8b112d22011-06-08 16:22:53 +010012267RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012268#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012269 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012270 ASSERT(args.length() == 1);
12271 // Get the function and make sure it is compiled.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012272 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000012273 Handle<SharedFunctionInfo> shared(func->shared());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012274 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012275 return Failure::Exception();
12276 }
12277 func->code()->PrintLn();
12278#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012279 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012280}
12281
12282
Ben Murdoch8b112d22011-06-08 16:22:53 +010012283RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012284#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012285 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012286 ASSERT(args.length() == 1);
12287 // Get the function and make sure it is compiled.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012288 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000012289 Handle<SharedFunctionInfo> shared(func->shared());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012290 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012291 return Failure::Exception();
12292 }
Leon Clarke4515c472010-02-03 11:58:03 +000012293 shared->construct_stub()->PrintLn();
Steve Blocka7e24c12009-10-30 11:49:00 +000012294#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012295 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012296}
12297
12298
Ben Murdoch8b112d22011-06-08 16:22:53 +010012299RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012300 NoHandleAllocation ha;
12301 ASSERT(args.length() == 1);
12302
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012303 CONVERT_ARG_CHECKED(JSFunction, f, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012304 return f->shared()->inferred_name();
12305}
Steve Blockd0582a62009-12-15 09:54:21 +000012306
Steve Block6ded16b2010-05-10 14:33:55 +010012307
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012308static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12309 Script* script,
Steve Block44f0eee2011-05-26 01:26:41 +010012310 FixedArray* buffer) {
Steve Block6ded16b2010-05-10 14:33:55 +010012311 AssertNoAllocation no_allocations;
Steve Block6ded16b2010-05-10 14:33:55 +010012312 int counter = 0;
12313 int buffer_size = buffer->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012314 for (HeapObject* obj = iterator->next();
12315 obj != NULL;
12316 obj = iterator->next()) {
Steve Block6ded16b2010-05-10 14:33:55 +010012317 ASSERT(obj != NULL);
12318 if (!obj->IsSharedFunctionInfo()) {
12319 continue;
12320 }
12321 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12322 if (shared->script() != script) {
12323 continue;
12324 }
12325 if (counter < buffer_size) {
12326 buffer->set(counter, shared);
12327 }
12328 counter++;
12329 }
12330 return counter;
12331}
12332
12333// For a script finds all SharedFunctionInfo's in the heap that points
12334// to this script. Returns JSArray of SharedFunctionInfo wrapped
12335// in OpaqueReferences.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012336RUNTIME_FUNCTION(MaybeObject*,
12337 Runtime_LiveEditFindSharedFunctionInfosForScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012338 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012339 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012340 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
12341
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012342
Steve Block6ded16b2010-05-10 14:33:55 +010012343 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12344
12345 const int kBufferSize = 32;
12346
12347 Handle<FixedArray> array;
Steve Block44f0eee2011-05-26 01:26:41 +010012348 array = isolate->factory()->NewFixedArray(kBufferSize);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012349 int number;
12350 {
12351 isolate->heap()->EnsureHeapIsIterable();
12352 AssertNoAllocation no_allocations;
12353 HeapIterator heap_iterator;
12354 Script* scr = *script;
12355 FixedArray* arr = *array;
12356 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12357 }
Steve Block6ded16b2010-05-10 14:33:55 +010012358 if (number > kBufferSize) {
Steve Block44f0eee2011-05-26 01:26:41 +010012359 array = isolate->factory()->NewFixedArray(number);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012360 isolate->heap()->EnsureHeapIsIterable();
12361 AssertNoAllocation no_allocations;
12362 HeapIterator heap_iterator;
12363 Script* scr = *script;
12364 FixedArray* arr = *array;
12365 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
Steve Block6ded16b2010-05-10 14:33:55 +010012366 }
12367
Steve Block44f0eee2011-05-26 01:26:41 +010012368 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
Steve Block6ded16b2010-05-10 14:33:55 +010012369 result->set_length(Smi::FromInt(number));
12370
12371 LiveEdit::WrapSharedFunctionInfos(result);
12372
12373 return *result;
12374}
12375
12376// For a script calculates compilation information about all its functions.
12377// The script source is explicitly specified by the second argument.
12378// The source of the actual script is not used, however it is important that
12379// all generated code keeps references to this particular instance of script.
12380// Returns a JSArray of compilation infos. The array is ordered so that
12381// each function with all its descendant is always stored in a continues range
12382// with the function itself going first. The root function is a script function.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012383RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
Steve Block6ded16b2010-05-10 14:33:55 +010012384 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012385 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012386 CONVERT_ARG_CHECKED(JSValue, script, 0);
12387 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012388 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12389
12390 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12391
Steve Block44f0eee2011-05-26 01:26:41 +010012392 if (isolate->has_pending_exception()) {
Steve Block6ded16b2010-05-10 14:33:55 +010012393 return Failure::Exception();
12394 }
12395
12396 return result;
12397}
12398
12399// Changes the source of the script to a new_source.
12400// If old_script_name is provided (i.e. is a String), also creates a copy of
12401// the script with its original source and sends notification to debugger.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012402RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012403 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010012404 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012405 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12406 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012407 Handle<Object> old_script_name(args[2], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012408
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012409 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12410 Handle<Script> original_script(Script::cast(original_script_value->value()));
Steve Block6ded16b2010-05-10 14:33:55 +010012411
12412 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12413 new_source,
12414 old_script_name);
12415
12416 if (old_script->IsScript()) {
12417 Handle<Script> script_handle(Script::cast(old_script));
12418 return *(GetScriptWrapper(script_handle));
12419 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010012420 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012421 }
12422}
12423
Ben Murdochb0fe1622011-05-05 13:52:32 +010012424
Ben Murdoch8b112d22011-06-08 16:22:53 +010012425RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010012426 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012427 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012428 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012429 return LiveEdit::FunctionSourceUpdated(shared_info);
12430}
12431
12432
Steve Block6ded16b2010-05-10 14:33:55 +010012433// Replaces code of SharedFunctionInfo with a new one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012434RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
Steve Block6ded16b2010-05-10 14:33:55 +010012435 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012436 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012437 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12438 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012439
12440 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
12441}
12442
12443// Connects SharedFunctionInfo to another script.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012444RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012445 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012446 HandleScope scope(isolate);
12447 Handle<Object> function_object(args[0], isolate);
12448 Handle<Object> script_object(args[1], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012449
12450 if (function_object->IsJSValue()) {
12451 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12452 if (script_object->IsJSValue()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012453 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12454 Script* script = Script::cast(JSValue::cast(*script_object)->value());
Steve Block44f0eee2011-05-26 01:26:41 +010012455 script_object = Handle<Object>(script, isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012456 }
12457
12458 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12459 } else {
12460 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12461 // and we check it in this function.
12462 }
12463
Steve Block44f0eee2011-05-26 01:26:41 +010012464 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012465}
12466
12467
12468// In a code of a parent function replaces original function as embedded object
12469// with a substitution one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012470RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
Steve Block6ded16b2010-05-10 14:33:55 +010012471 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010012472 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012473
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012474 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12475 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12476 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
Steve Block6ded16b2010-05-10 14:33:55 +010012477
12478 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12479 subst_wrapper);
12480
Steve Block44f0eee2011-05-26 01:26:41 +010012481 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012482}
12483
12484
12485// Updates positions of a shared function info (first parameter) according
12486// to script source change. Text change is described in second parameter as
12487// array of groups of 3 numbers:
12488// (change_begin, change_end, change_end_new_position).
12489// Each group describes a change in text; groups are sorted by change_begin.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012490RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
Steve Block6ded16b2010-05-10 14:33:55 +010012491 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012492 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012493 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12494 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012495
12496 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
12497}
12498
12499
12500// For array of SharedFunctionInfo's (each wrapped in JSValue)
12501// checks that none of them have activations on stacks (of any thread).
12502// Returns array of the same length with corresponding results of
12503// LiveEdit::FunctionPatchabilityStatus type.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012504RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
Steve Block6ded16b2010-05-10 14:33:55 +010012505 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012506 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012507 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12508 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012509
12510 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
12511}
12512
Ben Murdochb8e0da22011-05-16 14:20:40 +010012513// Compares 2 strings line-by-line, then token-wise and returns diff in form
12514// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12515// of diff chunks.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012516RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
Steve Block6ded16b2010-05-10 14:33:55 +010012517 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012518 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012519 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12520 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012521
Ben Murdochb8e0da22011-05-16 14:20:40 +010012522 return *LiveEdit::CompareStrings(s1, s2);
Steve Block6ded16b2010-05-10 14:33:55 +010012523}
12524
12525
Steve Block6ded16b2010-05-10 14:33:55 +010012526// A testing entry. Returns statement position which is the closest to
12527// source_position.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012528RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
Steve Block6ded16b2010-05-10 14:33:55 +010012529 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012530 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012531 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Steve Block6ded16b2010-05-10 14:33:55 +010012532 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12533
Steve Block44f0eee2011-05-26 01:26:41 +010012534 Handle<Code> code(function->code(), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012535
Ben Murdochb0fe1622011-05-05 13:52:32 +010012536 if (code->kind() != Code::FUNCTION &&
12537 code->kind() != Code::OPTIMIZED_FUNCTION) {
Steve Block44f0eee2011-05-26 01:26:41 +010012538 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010012539 }
12540
12541 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
Steve Block6ded16b2010-05-10 14:33:55 +010012542 int closest_pc = 0;
12543 int distance = kMaxInt;
12544 while (!it.done()) {
12545 int statement_position = static_cast<int>(it.rinfo()->data());
12546 // Check if this break point is closer that what was previously found.
12547 if (source_position <= statement_position &&
12548 statement_position - source_position < distance) {
12549 closest_pc =
12550 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
12551 distance = statement_position - source_position;
12552 // Check whether we can't get any closer.
12553 if (distance == 0) break;
12554 }
12555 it.next();
12556 }
12557
12558 return Smi::FromInt(closest_pc);
12559}
12560
12561
12562// Calls specified function with or without entering the debugger.
12563// This is used in unit tests to run code as if debugger is entered or simply
12564// to have a stack with C++ frame in the middle.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012565RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
Steve Block6ded16b2010-05-10 14:33:55 +010012566 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012567 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012568 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12569 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
Steve Block6ded16b2010-05-10 14:33:55 +010012570
12571 Handle<Object> result;
12572 bool pending_exception;
12573 {
12574 if (without_debugger) {
Steve Block44f0eee2011-05-26 01:26:41 +010012575 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010012576 &pending_exception);
12577 } else {
12578 EnterDebugger enter_debugger;
Steve Block44f0eee2011-05-26 01:26:41 +010012579 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010012580 &pending_exception);
12581 }
12582 }
12583 if (!pending_exception) {
12584 return *result;
12585 } else {
12586 return Failure::Exception();
12587 }
12588}
12589
12590
Ben Murdoch086aeea2011-05-13 15:57:08 +010012591// Sets a v8 flag.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012592RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012593 CONVERT_ARG_CHECKED(String, arg, 0);
Ben Murdoch589d6972011-11-30 16:04:58 +000012594 SmartArrayPointer<char> flags =
Ben Murdoch086aeea2011-05-13 15:57:08 +010012595 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12596 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
Steve Block44f0eee2011-05-26 01:26:41 +010012597 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010012598}
12599
12600
12601// Performs a GC.
12602// Presently, it only does a full GC.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012603RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012604 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
Steve Block44f0eee2011-05-26 01:26:41 +010012605 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010012606}
12607
12608
12609// Gets the current heap usage.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
Steve Block44f0eee2011-05-26 01:26:41 +010012611 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
Ben Murdoch086aeea2011-05-13 15:57:08 +010012612 if (!Smi::IsValid(usage)) {
Steve Block44f0eee2011-05-26 01:26:41 +010012613 return *isolate->factory()->NewNumberFromInt(usage);
Ben Murdoch086aeea2011-05-13 15:57:08 +010012614 }
12615 return Smi::FromInt(usage);
12616}
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012617
12618
12619// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012620RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012621#ifdef LIVE_OBJECT_LIST
Steve Block44f0eee2011-05-26 01:26:41 +010012622 return isolate->heap()->true_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012623#else
Steve Block44f0eee2011-05-26 01:26:41 +010012624 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012625#endif
12626}
12627
12628
12629// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012630RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012631#ifdef LIVE_OBJECT_LIST
12632 return LiveObjectList::Capture();
12633#else
Steve Block44f0eee2011-05-26 01:26:41 +010012634 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012635#endif
12636}
12637
12638
12639// Deletes the specified live object list.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012640RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012641#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012642 CONVERT_SMI_ARG_CHECKED(id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012643 bool success = LiveObjectList::Delete(id);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012644 return isolate->heap()->ToBoolean(success);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012645#else
Steve Block44f0eee2011-05-26 01:26:41 +010012646 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012647#endif
12648}
12649
12650
12651// Generates the response to a debugger request for a dump of the objects
12652// contained in the difference between the captured live object lists
12653// specified by id1 and id2.
12654// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12655// dumped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012656RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012657#ifdef LIVE_OBJECT_LIST
12658 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012659 CONVERT_SMI_ARG_CHECKED(id1, 0);
12660 CONVERT_SMI_ARG_CHECKED(id2, 1);
12661 CONVERT_SMI_ARG_CHECKED(start, 2);
12662 CONVERT_SMI_ARG_CHECKED(count, 3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012663 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012664 EnterDebugger enter_debugger;
12665 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12666#else
Steve Block44f0eee2011-05-26 01:26:41 +010012667 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012668#endif
12669}
12670
12671
12672// Gets the specified object as requested by the debugger.
12673// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012674RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012675#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012676 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012677 Object* result = LiveObjectList::GetObj(obj_id);
12678 return result;
12679#else
Steve Block44f0eee2011-05-26 01:26:41 +010012680 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012681#endif
12682}
12683
12684
12685// Gets the obj id for the specified address if valid.
12686// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012687RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012688#ifdef LIVE_OBJECT_LIST
12689 HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012690 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012691 Object* result = LiveObjectList::GetObjId(address);
12692 return result;
12693#else
Steve Block44f0eee2011-05-26 01:26:41 +010012694 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012695#endif
12696}
12697
12698
12699// Gets the retainers that references the specified object alive.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012701#ifdef LIVE_OBJECT_LIST
12702 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012703 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012704 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12705 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12706 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12707 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012708 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012709
12710 Handle<JSObject> instance_filter;
12711 if (args[1]->IsJSObject()) {
12712 instance_filter = args.at<JSObject>(1);
12713 }
12714 bool verbose = false;
12715 if (args[2]->IsBoolean()) {
12716 verbose = args[2]->IsTrue();
12717 }
12718 int start = 0;
12719 if (args[3]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012720 start = args.smi_at(3);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012721 }
12722 int limit = Smi::kMaxValue;
12723 if (args[4]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012724 limit = args.smi_at(4);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012725 }
12726
12727 return LiveObjectList::GetObjRetainers(obj_id,
12728 instance_filter,
12729 verbose,
12730 start,
12731 limit,
12732 filter_obj);
12733#else
Steve Block44f0eee2011-05-26 01:26:41 +010012734 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012735#endif
12736}
12737
12738
12739// Gets the reference path between 2 objects.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012740RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012741#ifdef LIVE_OBJECT_LIST
12742 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012743 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12744 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012745 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12746
12747 Handle<JSObject> instance_filter;
12748 if (args[2]->IsJSObject()) {
12749 instance_filter = args.at<JSObject>(2);
12750 }
12751
12752 Object* result =
12753 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12754 return result;
12755#else
Steve Block44f0eee2011-05-26 01:26:41 +010012756 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012757#endif
12758}
12759
12760
12761// Generates the response to a debugger request for a list of all
12762// previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012763RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012764#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012765 CONVERT_SMI_ARG_CHECKED(start, 0);
12766 CONVERT_SMI_ARG_CHECKED(count, 1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012767 return LiveObjectList::Info(start, count);
12768#else
Steve Block44f0eee2011-05-26 01:26:41 +010012769 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012770#endif
12771}
12772
12773
12774// Gets a dump of the specified object as requested by the debugger.
12775// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012776RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012777#ifdef LIVE_OBJECT_LIST
12778 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012779 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012780 Object* result = LiveObjectList::PrintObj(obj_id);
12781 return result;
12782#else
Steve Block44f0eee2011-05-26 01:26:41 +010012783 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012784#endif
12785}
12786
12787
12788// Resets and releases all previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012789RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012790#ifdef LIVE_OBJECT_LIST
12791 LiveObjectList::Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010012792 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012793#else
Steve Block44f0eee2011-05-26 01:26:41 +010012794 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012795#endif
12796}
12797
12798
12799// Generates the response to a debugger request for a summary of the types
12800// of objects in the difference between the captured live object lists
12801// specified by id1 and id2.
12802// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12803// summarized.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012804RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012805#ifdef LIVE_OBJECT_LIST
12806 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012807 CONVERT_SMI_ARG_CHECKED(id1, 0);
12808 CONVERT_SMI_ARG_CHECKED(id2, 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012809 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012810
12811 EnterDebugger enter_debugger;
12812 return LiveObjectList::Summarize(id1, id2, filter_obj);
12813#else
Steve Block44f0eee2011-05-26 01:26:41 +010012814 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012815#endif
12816}
12817
Steve Blocka7e24c12009-10-30 11:49:00 +000012818#endif // ENABLE_DEBUGGER_SUPPORT
12819
Steve Blockd0582a62009-12-15 09:54:21 +000012820
Ben Murdoch8b112d22011-06-08 16:22:53 +010012821RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
Steve Blockd0582a62009-12-15 09:54:21 +000012822 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012823 v8::V8::ResumeProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +010012824 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000012825}
12826
12827
Ben Murdoch8b112d22011-06-08 16:22:53 +010012828RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
Steve Blockd0582a62009-12-15 09:54:21 +000012829 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012830 v8::V8::PauseProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +010012831 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000012832}
12833
Steve Blocka7e24c12009-10-30 11:49:00 +000012834
12835// Finds the script object from the script data. NOTE: This operation uses
12836// heap traversal to find the function generated for the source position
12837// for the requested break point. For lazily compiled functions several heap
12838// traversals might be required rendering this operation as a rather slow
12839// operation. However for setting break points which is normally done through
12840// some kind of user interaction the performance is not crucial.
12841static Handle<Object> Runtime_GetScriptFromScriptName(
12842 Handle<String> script_name) {
12843 // Scan the heap for Script objects to find the script with the requested
12844 // script data.
12845 Handle<Script> script;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012846 script_name->GetHeap()->EnsureHeapIsIterable();
12847 AssertNoAllocation no_allocation_during_heap_iteration;
Steve Blocka7e24c12009-10-30 11:49:00 +000012848 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000012849 HeapObject* obj = NULL;
12850 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012851 // If a script is found check if it has the script data requested.
12852 if (obj->IsScript()) {
12853 if (Script::cast(obj)->name()->IsString()) {
12854 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12855 script = Handle<Script>(Script::cast(obj));
12856 }
12857 }
12858 }
12859 }
12860
12861 // If no script with the requested script data is found return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +010012862 if (script.is_null()) return FACTORY->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012863
12864 // Return the script found.
12865 return GetScriptWrapper(script);
12866}
12867
12868
12869// Get the script object from script data. NOTE: Regarding performance
12870// see the NOTE for GetScriptFromScriptData.
12871// args[0]: script data for the script to find the source for
Ben Murdoch8b112d22011-06-08 16:22:53 +010012872RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +010012873 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012874
12875 ASSERT(args.length() == 1);
12876
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012877 CONVERT_ARG_CHECKED(String, script_name, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012878
12879 // Find the requested script.
12880 Handle<Object> result =
12881 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12882 return *result;
12883}
12884
12885
12886// Determines whether the given stack frame should be displayed in
12887// a stack trace. The caller is the error constructor that asked
12888// for the stack trace to be collected. The first time a construct
12889// call to this function is encountered it is skipped. The seen_caller
12890// in/out parameter is used to remember if the caller has been seen
12891// yet.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012892static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12893 Object* caller,
12894 bool* seen_caller) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012895 // Only display JS frames.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012896 if (!raw_frame->is_java_script()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012897 return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012898 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012899 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12900 Object* raw_fun = frame->function();
12901 // Not sure when this can happen but skip it just in case.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012902 if (!raw_fun->IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012903 return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012904 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012905 if ((raw_fun == caller) && !(*seen_caller)) {
12906 *seen_caller = true;
12907 return false;
12908 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012909 // Skip all frames until we've seen the caller.
12910 if (!(*seen_caller)) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012911 // Also, skip non-visible built-in functions and any call with the builtins
12912 // object as receiver, so as to not reveal either the builtins object or
12913 // an internal function.
12914 // The --builtins-in-stack-traces command line flag allows including
12915 // internal call sites in the stack trace for debugging purposes.
12916 if (!FLAG_builtins_in_stack_traces) {
12917 JSFunction* fun = JSFunction::cast(raw_fun);
12918 if (frame->receiver()->IsJSBuiltinsObject() ||
12919 (fun->IsBuiltin() && !fun->shared()->native())) {
12920 return false;
12921 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012922 }
12923 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000012924}
12925
12926
Ben Murdochb0fe1622011-05-05 13:52:32 +010012927// Collect the raw data for a stack trace. Returns an array of 4
12928// element segments each containing a receiver, function, code and
12929// native code offset.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012930RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012931 ASSERT_EQ(args.length(), 3);
12932 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
12933 Handle<Object> caller = args.at<Object>(1);
12934 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
Steve Blocka7e24c12009-10-30 11:49:00 +000012935
Steve Block44f0eee2011-05-26 01:26:41 +010012936 HandleScope scope(isolate);
12937 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000012938
Leon Clarkee46be812010-01-19 14:06:41 +000012939 limit = Max(limit, 0); // Ensure that limit is not negative.
12940 int initial_size = Min(limit, 10);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012941 Handle<FixedArray> elements =
Steve Block44f0eee2011-05-26 01:26:41 +010012942 factory->NewFixedArrayWithHoles(initial_size * 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000012943
Ben Murdoch8b112d22011-06-08 16:22:53 +010012944 StackFrameIterator iter(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012945 // If the caller parameter is a function we skip frames until we're
12946 // under it before starting to collect.
12947 bool seen_caller = !caller->IsJSFunction();
12948 int cursor = 0;
12949 int frames_seen = 0;
12950 while (!iter.done() && frames_seen < limit) {
12951 StackFrame* raw_frame = iter.frame();
12952 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
12953 frames_seen++;
12954 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012955 // Set initial size to the maximum inlining level + 1 for the outermost
12956 // function.
12957 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012958 frame->Summarize(&frames);
12959 for (int i = frames.length() - 1; i >= 0; i--) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012960 if (cursor + 4 > elements->length()) {
12961 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12962 Handle<FixedArray> new_elements =
Steve Block44f0eee2011-05-26 01:26:41 +010012963 factory->NewFixedArrayWithHoles(new_capacity);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012964 for (int i = 0; i < cursor; i++) {
12965 new_elements->set(i, elements->get(i));
12966 }
12967 elements = new_elements;
12968 }
12969 ASSERT(cursor + 4 <= elements->length());
12970
Ben Murdochb0fe1622011-05-05 13:52:32 +010012971 Handle<Object> recv = frames[i].receiver();
12972 Handle<JSFunction> fun = frames[i].function();
12973 Handle<Code> code = frames[i].code();
12974 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012975 elements->set(cursor++, *recv);
12976 elements->set(cursor++, *fun);
12977 elements->set(cursor++, *code);
12978 elements->set(cursor++, *offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000012979 }
12980 }
12981 iter.Advance();
12982 }
Steve Block44f0eee2011-05-26 01:26:41 +010012983 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012984 // Capture and attach a more detailed stack trace if necessary.
12985 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
Leon Clarke4515c472010-02-03 11:58:03 +000012986 result->set_length(Smi::FromInt(cursor));
Steve Blocka7e24c12009-10-30 11:49:00 +000012987 return *result;
12988}
12989
12990
Steve Block3ce2e202009-11-05 08:53:23 +000012991// Returns V8 version as a string.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
Steve Block3ce2e202009-11-05 08:53:23 +000012993 ASSERT_EQ(args.length(), 0);
12994
12995 NoHandleAllocation ha;
12996
12997 const char* version_string = v8::V8::GetVersion();
12998
Steve Block44f0eee2011-05-26 01:26:41 +010012999 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13000 NOT_TENURED);
Steve Block3ce2e202009-11-05 08:53:23 +000013001}
13002
13003
Ben Murdoch8b112d22011-06-08 16:22:53 +010013004RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013005 ASSERT(args.length() == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013006 OS::PrintError("abort: %s\n",
13007 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
Steve Block44f0eee2011-05-26 01:26:41 +010013008 isolate->PrintStack();
Steve Blocka7e24c12009-10-30 11:49:00 +000013009 OS::Abort();
13010 UNREACHABLE();
13011 return NULL;
13012}
13013
13014
Ben Murdoch8b112d22011-06-08 16:22:53 +010013015RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
Steve Block6ded16b2010-05-10 14:33:55 +010013016 // This is only called from codegen, so checks might be more lax.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013017 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
Steve Block6ded16b2010-05-10 14:33:55 +010013018 Object* key = args[1];
13019
Ben Murdochb8e0da22011-05-16 14:20:40 +010013020 int finger_index = cache->finger_index();
Steve Block6ded16b2010-05-10 14:33:55 +010013021 Object* o = cache->get(finger_index);
13022 if (o == key) {
13023 // The fastest case: hit the same place again.
13024 return cache->get(finger_index + 1);
13025 }
13026
13027 for (int i = finger_index - 2;
13028 i >= JSFunctionResultCache::kEntriesIndex;
13029 i -= 2) {
13030 o = cache->get(i);
13031 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010013032 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010013033 return cache->get(i + 1);
13034 }
13035 }
13036
Ben Murdochb8e0da22011-05-16 14:20:40 +010013037 int size = cache->size();
Steve Block6ded16b2010-05-10 14:33:55 +010013038 ASSERT(size <= cache->length());
13039
13040 for (int i = size - 2; i > finger_index; i -= 2) {
13041 o = cache->get(i);
13042 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010013043 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010013044 return cache->get(i + 1);
13045 }
13046 }
13047
Ben Murdochb8e0da22011-05-16 14:20:40 +010013048 // There is no value in the cache. Invoke the function and cache result.
Steve Block44f0eee2011-05-26 01:26:41 +010013049 HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +010013050
13051 Handle<JSFunctionResultCache> cache_handle(cache);
13052 Handle<Object> key_handle(key);
13053 Handle<Object> value;
13054 {
13055 Handle<JSFunction> factory(JSFunction::cast(
13056 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13057 // TODO(antonm): consider passing a receiver when constructing a cache.
Steve Block44f0eee2011-05-26 01:26:41 +010013058 Handle<Object> receiver(isolate->global_context()->global());
Ben Murdochb8e0da22011-05-16 14:20:40 +010013059 // This handle is nor shared, nor used later, so it's safe.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013060 Handle<Object> argv[] = { key_handle };
13061 bool pending_exception;
Ben Murdochb8e0da22011-05-16 14:20:40 +010013062 value = Execution::Call(factory,
13063 receiver,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013064 ARRAY_SIZE(argv),
Ben Murdochb8e0da22011-05-16 14:20:40 +010013065 argv,
13066 &pending_exception);
13067 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +010013068 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013069
13070#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013071 if (FLAG_verify_heap) {
13072 cache_handle->JSFunctionResultCacheVerify();
13073 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013074#endif
13075
13076 // Function invocation may have cleared the cache. Reread all the data.
13077 finger_index = cache_handle->finger_index();
13078 size = cache_handle->size();
13079
13080 // If we have spare room, put new data into it, otherwise evict post finger
13081 // entry which is likely to be the least recently used.
13082 int index = -1;
13083 if (size < cache_handle->length()) {
13084 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13085 index = size;
13086 } else {
13087 index = finger_index + JSFunctionResultCache::kEntrySize;
13088 if (index == cache_handle->length()) {
13089 index = JSFunctionResultCache::kEntriesIndex;
13090 }
13091 }
13092
13093 ASSERT(index % 2 == 0);
13094 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13095 ASSERT(index < cache_handle->length());
13096
13097 cache_handle->set(index, *key_handle);
13098 cache_handle->set(index + 1, *value);
13099 cache_handle->set_finger_index(index);
13100
13101#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013102 if (FLAG_verify_heap) {
13103 cache_handle->JSFunctionResultCacheVerify();
13104 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013105#endif
13106
13107 return *value;
Steve Block6ded16b2010-05-10 14:33:55 +010013108}
13109
Steve Block1e0659c2011-05-24 12:43:12 +010013110
Ben Murdoch8b112d22011-06-08 16:22:53 +010013111RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
Steve Block44f0eee2011-05-26 01:26:41 +010013112 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013113 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13114 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010013115 return *isolate->factory()->NewJSMessageObject(
13116 type,
13117 arguments,
13118 0,
13119 0,
13120 isolate->factory()->undefined_value(),
13121 isolate->factory()->undefined_value(),
13122 isolate->factory()->undefined_value());
Steve Block1e0659c2011-05-24 12:43:12 +010013123}
13124
13125
Ben Murdoch8b112d22011-06-08 16:22:53 +010013126RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013127 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
Steve Block1e0659c2011-05-24 12:43:12 +010013128 return message->type();
13129}
13130
13131
Ben Murdoch8b112d22011-06-08 16:22:53 +010013132RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013133 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
Steve Block1e0659c2011-05-24 12:43:12 +010013134 return message->arguments();
13135}
13136
13137
Ben Murdoch8b112d22011-06-08 16:22:53 +010013138RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013139 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
Steve Block1e0659c2011-05-24 12:43:12 +010013140 return Smi::FromInt(message->start_position());
13141}
13142
13143
Ben Murdoch8b112d22011-06-08 16:22:53 +010013144RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013145 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
Steve Block1e0659c2011-05-24 12:43:12 +010013146 return message->script();
13147}
13148
13149
Steve Blocka7e24c12009-10-30 11:49:00 +000013150#ifdef DEBUG
13151// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13152// Exclude the code in release mode.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013153RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013154 ASSERT(args.length() == 0);
13155 HandleScope scope;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013156#define COUNT_ENTRY(Name, argc, ressize) + 1
13157 int entry_count = 0
13158 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13159 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13160 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13161#undef COUNT_ENTRY
Steve Block44f0eee2011-05-26 01:26:41 +010013162 Factory* factory = isolate->factory();
13163 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
Steve Blocka7e24c12009-10-30 11:49:00 +000013164 int index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010013165 bool inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013166#define ADD_ENTRY(Name, argc, ressize) \
13167 { \
13168 HandleScope inner; \
Steve Block6ded16b2010-05-10 14:33:55 +010013169 Handle<String> name; \
13170 /* Inline runtime functions have an underscore in front of the name. */ \
13171 if (inline_runtime_functions) { \
Steve Block44f0eee2011-05-26 01:26:41 +010013172 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010013173 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13174 } else { \
Steve Block44f0eee2011-05-26 01:26:41 +010013175 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010013176 Vector<const char>(#Name, StrLength(#Name))); \
13177 } \
Steve Block44f0eee2011-05-26 01:26:41 +010013178 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013179 pair_elements->set(0, *name); \
13180 pair_elements->set(1, Smi::FromInt(argc)); \
Steve Block44f0eee2011-05-26 01:26:41 +010013181 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013182 elements->set(index++, *pair); \
Steve Blocka7e24c12009-10-30 11:49:00 +000013183 }
Steve Block6ded16b2010-05-10 14:33:55 +010013184 inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013185 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010013186 inline_runtime_functions = true;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013187 INLINE_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010013188 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Blocka7e24c12009-10-30 11:49:00 +000013189#undef ADD_ENTRY
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013190 ASSERT_EQ(index, entry_count);
Steve Block44f0eee2011-05-26 01:26:41 +010013191 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +000013192 return *result;
13193}
13194#endif
13195
13196
Ben Murdoch8b112d22011-06-08 16:22:53 +010013197RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013198 ASSERT(args.length() == 2);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013199 CONVERT_ARG_CHECKED(String, format, 0);
13200 CONVERT_ARG_CHECKED(JSArray, elms, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013201 String::FlatContent format_content = format->GetFlatContent();
13202 RUNTIME_ASSERT(format_content.IsAscii());
13203 Vector<const char> chars = format_content.ToAsciiVector();
Steve Block44f0eee2011-05-26 01:26:41 +010013204 LOGGER->LogRuntime(chars, elms);
13205 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000013206}
13207
13208
Ben Murdoch8b112d22011-06-08 16:22:53 +010013209RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013210 UNREACHABLE(); // implemented as macro in the parser
13211 return NULL;
13212}
13213
13214
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013215#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13216 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013217 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013218 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13219 }
13220
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013221ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013222ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13223ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13224ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13225ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13226ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13227ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13228ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13229ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13230ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13231ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13232ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13233ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13234ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13235
13236#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13237
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013238
13239RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13240 ASSERT(args.length() == 2);
13241 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13242 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
13243 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13244}
13245
Steve Blocka7e24c12009-10-30 11:49:00 +000013246// ----------------------------------------------------------------------------
13247// Implementation of Runtime
13248
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013249#define F(name, number_of_args, result_size) \
13250 { Runtime::k##name, Runtime::RUNTIME, #name, \
13251 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
Steve Blocka7e24c12009-10-30 11:49:00 +000013252
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013253
13254#define I(name, number_of_args, result_size) \
13255 { Runtime::kInline##name, Runtime::INLINE, \
13256 "_" #name, NULL, number_of_args, result_size },
13257
Steve Block44f0eee2011-05-26 01:26:41 +010013258static const Runtime::Function kIntrinsicFunctions[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000013259 RUNTIME_FUNCTION_LIST(F)
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013260 INLINE_FUNCTION_LIST(I)
13261 INLINE_RUNTIME_FUNCTION_LIST(I)
Steve Blocka7e24c12009-10-30 11:49:00 +000013262};
13263
Steve Blocka7e24c12009-10-30 11:49:00 +000013264
Steve Block44f0eee2011-05-26 01:26:41 +010013265MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13266 Object* dictionary) {
13267 ASSERT(Isolate::Current()->heap() == heap);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013268 ASSERT(dictionary != NULL);
13269 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13270 for (int i = 0; i < kNumFunctions; ++i) {
John Reck59135872010-11-02 12:39:01 -070013271 Object* name_symbol;
13272 { MaybeObject* maybe_name_symbol =
Steve Block44f0eee2011-05-26 01:26:41 +010013273 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
John Reck59135872010-11-02 12:39:01 -070013274 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13275 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013276 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
John Reck59135872010-11-02 12:39:01 -070013277 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13278 String::cast(name_symbol),
13279 Smi::FromInt(i),
13280 PropertyDetails(NONE, NORMAL));
13281 if (!maybe_dictionary->ToObject(&dictionary)) {
13282 // Non-recoverable failure. Calling code must restart heap
13283 // initialization.
13284 return maybe_dictionary;
13285 }
13286 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013287 }
13288 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000013289}
13290
13291
Steve Block44f0eee2011-05-26 01:26:41 +010013292const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13293 Heap* heap = name->GetHeap();
13294 int entry = heap->intrinsic_function_names()->FindEntry(*name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013295 if (entry != kNotFound) {
Steve Block44f0eee2011-05-26 01:26:41 +010013296 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013297 int function_index = Smi::cast(smi_index)->value();
13298 return &(kIntrinsicFunctions[function_index]);
Steve Blocka7e24c12009-10-30 11:49:00 +000013299 }
13300 return NULL;
13301}
13302
13303
Steve Block44f0eee2011-05-26 01:26:41 +010013304const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013305 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13306}
13307
13308
Steve Blocka7e24c12009-10-30 11:49:00 +000013309void Runtime::PerformGC(Object* result) {
Steve Block44f0eee2011-05-26 01:26:41 +010013310 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000013311 Failure* failure = Failure::cast(result);
13312 if (failure->IsRetryAfterGC()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013313 if (isolate->heap()->new_space()->AddFreshPage()) {
13314 return;
13315 }
13316
Steve Blocka7e24c12009-10-30 11:49:00 +000013317 // Try to do a garbage collection; ignore it if it fails. The C
13318 // entry stub will throw an out-of-memory exception in that case.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013319 isolate->heap()->CollectGarbage(failure->allocation_space(),
13320 "Runtime::PerformGC");
Steve Blocka7e24c12009-10-30 11:49:00 +000013321 } else {
13322 // Handle last resort GC and make sure to allow future allocations
13323 // to grow the heap without causing GCs (if possible).
Steve Block44f0eee2011-05-26 01:26:41 +010013324 isolate->counters()->gc_last_resort_from_js()->Increment();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013325 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13326 "Runtime::PerformGC");
Steve Blocka7e24c12009-10-30 11:49:00 +000013327 }
13328}
13329
13330
13331} } // namespace v8::internal