blob: f95ecdfc6f2f00e0bf13c6ef0f41dabf939c9ae3 [file] [log] [blame]
Ben Murdochc7cc0282012-03-05 14:35:55 +00001// 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"
Steve Blocka7e24c12009-10-30 11:49:00 +000043#include "execution.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010044#include "global-handles.h"
Ben Murdoch592a9fc2012-03-05 11:04:45 +000045#include "isolate-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000046#include "jsregexp.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000047#include "json-parser.h"
Steve Block6ded16b2010-05-10 14:33:55 +010048#include "liveedit.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010049#include "liveobjectlist-inl.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000050#include "misc-intrinsics.h"
Steve Block3ce2e202009-11-05 08:53:23 +000051#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000052#include "platform.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010053#include "runtime-profiler.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000054#include "runtime.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000055#include "scopeinfo.h"
Ben Murdoch589d6972011-11-30 16:04:58 +000056#include "smart-array-pointer.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000057#include "string-search.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000058#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000059#include "v8threads.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000060#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000061
62namespace v8 {
63namespace internal {
64
65
66#define RUNTIME_ASSERT(value) \
Steve Block44f0eee2011-05-26 01:26:41 +010067 if (!(value)) return isolate->ThrowIllegalOperation();
Steve Blocka7e24c12009-10-30 11:49:00 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
80// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
Steve Blocka7e24c12009-10-30 11:49:00 +000089// and return.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
Steve Blocka7e24c12009-10-30 11:49:00 +000093
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
Steve Blocka7e24c12009-10-30 11:49:00 +000096// the number not-a-number) call IllegalOperation and return.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
Steve Blocka7e24c12009-10-30 11:49:00 +0000108
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
Steve Block44f0eee2011-05-26 01:26:41 +0100130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +0000134
Steve Block44f0eee2011-05-26 01:26:41 +0100135 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -0700136 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
John Reck59135872010-11-02 12:39:01 -0700138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000148 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
Leon Clarke4515c472010-02-03 11:58:03 +0000152 properties->set(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 }
154 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000159 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
Leon Clarke4515c472010-02-03 11:58:03 +0000163 copy->InObjectPropertyAtPut(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 }
165 }
166 } else {
John Reck59135872010-11-02 12:39:01 -0700167 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
John Reck59135872010-11-02 12:39:01 -0700169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
Leon Clarke4515c472010-02-03 11:58:03 +0000175 String* key_string = String::cast(names->get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 PropertyAttributes attributes =
Leon Clarke4515c472010-02-03 11:58:03 +0000177 copy->GetLocalPropertyAttribute(key_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
John Reck59135872010-11-02 12:39:01 -0700182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000184 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000185 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -0700192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
199 // Pixel elements cannot be created using an object literal.
Steve Block44f0eee2011-05-26 01:26:41 +0100200 ASSERT(!copy->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 switch (copy->GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000202 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +0000203 case FAST_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
Steve Block44f0eee2011-05-26 01:26:41 +0100205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
Iain Merrick75681382010-08-19 15:07:18 +0100218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
John Reck59135872010-11-02 12:39:01 -0700222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
Iain Merrick75681382010-08-19 15:07:18 +0100224 elements->set(i, result);
225 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000226 }
227 }
228 break;
229 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000230 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000231 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000238 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
John Reck59135872010-11-02 12:39:01 -0700241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000250 UNIMPLEMENTED();
251 break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000262 // No contained objects, nothing to do.
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 break;
264 }
265 return copy;
266}
267
268
Steve Blocka7e24c12009-10-30 11:49:00 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
272 bool* is_result_from_cache) {
Steve Block44f0eee2011-05-26 01:26:41 +0100273 Isolate* isolate = context->GetIsolate();
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 if (FLAG_canonicalize_object_literal_maps) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100277 // Check that there are only symbols and array indices among keys.
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 int number_of_symbol_keys = 0;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 const int kMaxKeys = 10;
297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
299 // Create the fixed array with the key.
Steve Block44f0eee2011-05-26 01:26:41 +0100300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 }
312 *is_result_from_cache = true;
Steve Block44f0eee2011-05-26 01:26:41 +0100313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 }
315 }
316 *is_result_from_cache = false;
Steve Block44f0eee2011-05-26 01:26:41 +0100317 return isolate->factory()->CopyMap(
Steve Blocka7e24c12009-10-30 11:49:00 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
320}
321
322
323static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100324 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
327
328
329static Handle<Object> CreateObjectLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100330 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 Handle<FixedArray> literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100332 Handle<FixedArray> constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100333 bool should_have_fast_elements,
334 bool has_function_literal) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
Steve Block44f0eee2011-05-26 01:26:41 +0100344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
Steve Blocka7e24c12009-10-30 11:49:00 +0000354
Steve Block44f0eee2011-05-26 01:26:41 +0100355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
Steve Block6ded16b2010-05-10 14:33:55 +0100356
357 // Normalize the elements of the boilerplate to save space if needed.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000358 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
Steve Block6ded16b2010-05-10 14:33:55 +0100359
Steve Block44f0eee2011-05-26 01:26:41 +0100360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000368 JSObject::NormalizeProperties(
369 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
Ben Murdochc7cc0282012-03-05 14:35:55 +0000387 result = JSObject::SetOwnElement(
388 boilerplate, element_index, value, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100390 Handle<String> name(String::cast(*key));
391 ASSERT(!name->AsArrayIndex(&element_index));
Ben Murdochc7cc0282012-03-05 14:35:55 +0000392 result = JSObject::SetLocalPropertyIgnoreAttributes(
393 boilerplate, name, value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 }
Steve Block44f0eee2011-05-26 01:26:41 +0100395 } else if (key->ToArrayIndex(&element_index)) {
396 // Array index (uint32).
Ben Murdochc7cc0282012-03-05 14:35:55 +0000397 result = JSObject::SetOwnElement(
398 boilerplate, element_index, value, kNonStrictMode);
Steve Block44f0eee2011-05-26 01:26:41 +0100399 } else {
400 // Non-uint32 number.
401 ASSERT(key->IsNumber());
402 double num = key->Number();
403 char arr[100];
404 Vector<char> buffer(arr, ARRAY_SIZE(arr));
405 const char* str = DoubleToCString(num, buffer);
406 Handle<String> name =
407 isolate->factory()->NewStringFromAscii(CStrVector(str));
Ben Murdochc7cc0282012-03-05 14:35:55 +0000408 result = JSObject::SetLocalPropertyIgnoreAttributes(
409 boilerplate, name, value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 }
Steve Block44f0eee2011-05-26 01:26:41 +0100411 // If setting the property on the boilerplate throws an
412 // exception, the exception is converted to an empty handle in
413 // the handle based operations. In that case, we need to
414 // convert back to an exception.
415 if (result.is_null()) return result;
416 }
417
418 // Transform to fast properties if necessary. For object literals with
419 // containing function literals we defer this operation until after all
420 // computed properties have been assigned so that we can generate
421 // constant function properties.
422 if (should_transform && !has_function_literal) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000423 JSObject::TransformToFastProperties(
424 boilerplate, boilerplate->map()->unused_property_fields());
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 }
426
427 return boilerplate;
428}
429
430
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000431static const int kSmiOnlyLiteralMinimumLength = 1024;
432
433
Ben Murdochc7cc0282012-03-05 14:35:55 +0000434Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100435 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000436 Handle<FixedArray> literals,
437 Handle<FixedArray> elements) {
438 // Create the JSArray.
439 Handle<JSFunction> constructor(
440 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000441 Handle<JSArray> object =
442 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
Steve Blocka7e24c12009-10-30 11:49:00 +0000443
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000444 ElementsKind constant_elements_kind =
445 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
446 Handle<FixedArrayBase> constant_elements_values(
447 FixedArrayBase::cast(elements->get(1)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000449 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
450 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
451 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
452 constant_elements_kind > object->GetElementsKind();
453
454 if (!FLAG_smi_only_arrays &&
455 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
456 constant_elements_kind != object->GetElementsKind()) {
457 allow_literal_kind_transition = true;
458 }
459
460 // If the ElementsKind of the constant values of the array literal are less
461 // specific than the ElementsKind of the boilerplate array object, change the
462 // boilerplate array object's map to reflect that kind.
463 if (allow_literal_kind_transition) {
464 Handle<Map> transitioned_array_map =
465 isolate->factory()->GetElementsTransitionMap(object,
466 constant_elements_kind);
467 object->set_map(*transitioned_array_map);
468 }
469
470 Handle<FixedArrayBase> copied_elements_values;
471 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
472 ASSERT(FLAG_smi_only_arrays);
473 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
474 Handle<FixedDoubleArray>::cast(constant_elements_values));
Iain Merrick75681382010-08-19 15:07:18 +0100475 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000476 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
477 constant_elements_kind == FAST_ELEMENTS);
478 const bool is_cow =
479 (constant_elements_values->map() ==
480 isolate->heap()->fixed_cow_array_map());
481 if (is_cow) {
482 copied_elements_values = constant_elements_values;
483#if DEBUG
484 Handle<FixedArray> fixed_array_values =
485 Handle<FixedArray>::cast(copied_elements_values);
486 for (int i = 0; i < fixed_array_values->length(); i++) {
487 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
488 }
489#endif
490 } else {
491 Handle<FixedArray> fixed_array_values =
492 Handle<FixedArray>::cast(constant_elements_values);
493 Handle<FixedArray> fixed_array_values_copy =
494 isolate->factory()->CopyFixedArray(fixed_array_values);
495 copied_elements_values = fixed_array_values_copy;
496 for (int i = 0; i < fixed_array_values->length(); i++) {
497 Object* current = fixed_array_values->get(i);
498 if (current->IsFixedArray()) {
499 // The value contains the constant_properties of a
500 // simple object or array literal.
501 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
502 Handle<Object> result =
503 CreateLiteralBoilerplate(isolate, literals, fa);
504 if (result.is_null()) return result;
505 fixed_array_values_copy->set(i, *result);
506 }
Iain Merrick75681382010-08-19 15:07:18 +0100507 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000508 }
509 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000510 object->set_elements(*copied_elements_values);
511 object->set_length(Smi::FromInt(copied_elements_values->length()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 return object;
513}
514
515
516static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100517 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000518 Handle<FixedArray> literals,
519 Handle<FixedArray> array) {
520 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
Steve Block44f0eee2011-05-26 01:26:41 +0100521 const bool kHasNoFunctionLiteral = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000522 switch (CompileTimeValue::GetType(array)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100523 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 true,
528 kHasNoFunctionLiteral);
Steve Block6ded16b2010-05-10 14:33:55 +0100529 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100530 return CreateObjectLiteralBoilerplate(isolate,
531 literals,
532 elements,
533 false,
534 kHasNoFunctionLiteral);
Steve Blocka7e24c12009-10-30 11:49:00 +0000535 case CompileTimeValue::ARRAY_LITERAL:
Ben Murdochc7cc0282012-03-05 14:35:55 +0000536 return Runtime::CreateArrayLiteralBoilerplate(
537 isolate, literals, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000538 default:
539 UNREACHABLE();
540 return Handle<Object>::null();
541 }
542}
543
544
Ben Murdoch8b112d22011-06-08 16:22:53 +0100545RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100546 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100547 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000549 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000550 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000551 CONVERT_SMI_ARG_CHECKED(flags, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100552 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
553 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000554
555 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateObjectLiteralBoilerplate(isolate,
559 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100560 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100561 should_have_fast_elements,
562 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000563 if (boilerplate.is_null()) return Failure::Exception();
564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *boilerplate);
566 }
Steve Block44f0eee2011-05-26 01:26:41 +0100567 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000568}
569
570
Ben Murdoch8b112d22011-06-08 16:22:53 +0100571RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100572 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100573 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000574 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000575 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000576 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000577 CONVERT_SMI_ARG_CHECKED(flags, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100578 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
579 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000580
581 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100582 Handle<Object> boilerplate(literals->get(literals_index), isolate);
583 if (*boilerplate == isolate->heap()->undefined_value()) {
584 boilerplate = CreateObjectLiteralBoilerplate(isolate,
585 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100586 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100587 should_have_fast_elements,
588 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000589 if (boilerplate.is_null()) return Failure::Exception();
590 // Update the functions literal and return the boilerplate.
591 literals->set(literals_index, *boilerplate);
592 }
Steve Block44f0eee2011-05-26 01:26:41 +0100593 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000594}
595
596
Ben Murdoch8b112d22011-06-08 16:22:53 +0100597RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100598 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000599 ASSERT(args.length() == 3);
600 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000601 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000602 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
603
604 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100605 Handle<Object> boilerplate(literals->get(literals_index), isolate);
606 if (*boilerplate == isolate->heap()->undefined_value()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000607 boilerplate =
608 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000609 if (boilerplate.is_null()) return Failure::Exception();
610 // Update the functions literal and return the boilerplate.
611 literals->set(literals_index, *boilerplate);
612 }
Steve Block44f0eee2011-05-26 01:26:41 +0100613 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000614}
615
616
Ben Murdoch8b112d22011-06-08 16:22:53 +0100617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100618 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000619 ASSERT(args.length() == 3);
620 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000621 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000622 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
623
624 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100625 Handle<Object> boilerplate(literals->get(literals_index), isolate);
626 if (*boilerplate == isolate->heap()->undefined_value()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000627 ASSERT(*elements != isolate->heap()->empty_fixed_array());
628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
Iain Merrick75681382010-08-19 15:07:18 +0100634 if (JSObject::cast(*boilerplate)->elements()->map() ==
Steve Block44f0eee2011-05-26 01:26:41 +0100635 isolate->heap()->fixed_cow_array_map()) {
636 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100637 }
Steve Block44f0eee2011-05-26 01:26:41 +0100638 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000639}
640
641
Ben Murdoch257744e2011-11-30 15:57:28 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
643 ASSERT(args.length() == 2);
644 Object* handler = args[0];
645 Object* prototype = args[1];
646 Object* used_prototype =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000647 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
Ben Murdoch257744e2011-11-30 15:57:28 +0000648 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
649}
650
651
Ben Murdoch589d6972011-11-30 16:04:58 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
653 ASSERT(args.length() == 4);
654 Object* handler = args[0];
655 Object* call_trap = args[1];
656 Object* construct_trap = args[2];
657 Object* prototype = args[3];
658 Object* used_prototype =
659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
660 return isolate->heap()->AllocateJSFunctionProxy(
661 handler, call_trap, construct_trap, used_prototype);
662}
663
664
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
666 ASSERT(args.length() == 1);
667 Object* obj = args[0];
668 return isolate->heap()->ToBoolean(obj->IsJSProxy());
669}
670
671
Ben Murdoch589d6972011-11-30 16:04:58 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
673 ASSERT(args.length() == 1);
674 Object* obj = args[0];
675 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
676}
677
678
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(JSProxy, proxy, args[0]);
682 return proxy->handler();
683}
684
685
Ben Murdoch589d6972011-11-30 16:04:58 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
687 ASSERT(args.length() == 1);
688 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
689 return proxy->call_trap();
690}
691
692
693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
694 ASSERT(args.length() == 1);
695 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
696 return proxy->construct_trap();
697}
698
699
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
701 ASSERT(args.length() == 1);
702 CONVERT_CHECKED(JSProxy, proxy, args[0]);
703 proxy->Fix();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000704 return isolate->heap()->undefined_value();
705}
706
707
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
709 HandleScope scope(isolate);
710 ASSERT(args.length() == 1);
711 CONVERT_ARG_CHECKED(JSSet, holder, 0);
712 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
713 holder->set_table(*table);
714 return *holder;
715}
716
717
718RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
719 HandleScope scope(isolate);
720 ASSERT(args.length() == 2);
721 CONVERT_ARG_CHECKED(JSSet, holder, 0);
722 Handle<Object> key(args[1]);
723 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
724 table = ObjectHashSetAdd(table, key);
725 holder->set_table(*table);
726 return isolate->heap()->undefined_symbol();
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 return isolate->heap()->ToBoolean(table->Contains(*key));
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetRemove(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 1);
755 CONVERT_ARG_CHECKED(JSMap, holder, 0);
756 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
757 holder->set_table(*table);
758 return *holder;
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSMap, holder, 0);
766 Handle<Object> key(args[1]);
767 return ObjectHashTable::cast(holder->table())->Lookup(*key);
768}
769
770
771RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
772 HandleScope scope(isolate);
773 ASSERT(args.length() == 3);
774 CONVERT_ARG_CHECKED(JSMap, holder, 0);
775 Handle<Object> key(args[1]);
776 Handle<Object> value(args[2]);
777 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
778 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
779 holder->set_table(*new_table);
780 return *value;
781}
782
783
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000784RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 1);
787 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
788 ASSERT(weakmap->map()->inobject_properties() == 0);
789 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
790 weakmap->set_table(*table);
791 weakmap->set_next(Smi::FromInt(0));
792 return *weakmap;
793}
794
795
796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000800 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
801 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000802}
803
804
805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 3);
808 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000809 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000810 Handle<Object> value(args[2]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000811 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000812 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
813 weakmap->set_table(*new_table);
814 return *value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000815}
816
817
Ben Murdoch8b112d22011-06-08 16:22:53 +0100818RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 NoHandleAllocation ha;
820 ASSERT(args.length() == 1);
821 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +0100822 if (!obj->IsJSObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 return JSObject::cast(obj)->class_name();
824}
825
826
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
828 NoHandleAllocation ha;
829 ASSERT(args.length() == 1);
830 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
831 Object* obj = input_obj;
832 // We don't expect access checks to be needed on JSProxy objects.
833 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
834 do {
835 if (obj->IsAccessCheckNeeded() &&
836 !isolate->MayNamedAccess(JSObject::cast(obj),
837 isolate->heap()->Proto_symbol(),
838 v8::ACCESS_GET)) {
839 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
840 return isolate->heap()->undefined_value();
841 }
842 obj = obj->GetPrototype();
843 } while (obj->IsJSObject() &&
844 JSObject::cast(obj)->map()->is_hidden_prototype());
845 return obj;
846}
847
848
Ben Murdoch8b112d22011-06-08 16:22:53 +0100849RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
853 Object* O = args[0];
854 Object* V = args[1];
855 while (true) {
856 Object* prototype = V->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100857 if (prototype->IsNull()) return isolate->heap()->false_value();
858 if (O == prototype) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000859 V = prototype;
860 }
861}
862
863
Ben Murdoch8b112d22011-06-08 16:22:53 +0100864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000865 NoHandleAllocation ha;
866 ASSERT(args.length() == 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100867 JavaScriptFrameIterator it(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100868 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000869}
870
871
Leon Clarkee46be812010-01-19 14:06:41 +0000872// Recursively traverses hidden prototypes if property is not found
873static void GetOwnPropertyImplementation(JSObject* obj,
874 String* name,
875 LookupResult* result) {
876 obj->LocalLookupRealNamedProperty(name, result);
877
878 if (!result->IsProperty()) {
879 Object* proto = obj->GetPrototype();
880 if (proto->IsJSObject() &&
881 JSObject::cast(proto)->map()->is_hidden_prototype())
882 GetOwnPropertyImplementation(JSObject::cast(proto),
883 name, result);
884 }
885}
886
887
Steve Block1e0659c2011-05-24 12:43:12 +0100888static bool CheckAccessException(LookupResult* result,
889 v8::AccessType access_type) {
890 if (result->type() == CALLBACKS) {
891 Object* callback = result->GetCallbackObject();
892 if (callback->IsAccessorInfo()) {
893 AccessorInfo* info = AccessorInfo::cast(callback);
894 bool can_access =
895 (access_type == v8::ACCESS_HAS &&
896 (info->all_can_read() || info->all_can_write())) ||
897 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
898 (access_type == v8::ACCESS_SET && info->all_can_write());
899 return can_access;
900 }
901 }
902
903 return false;
904}
905
906
907static bool CheckAccess(JSObject* obj,
908 String* name,
909 LookupResult* result,
910 v8::AccessType access_type) {
911 ASSERT(result->IsProperty());
912
913 JSObject* holder = result->holder();
914 JSObject* current = obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100915 Isolate* isolate = obj->GetIsolate();
Steve Block1e0659c2011-05-24 12:43:12 +0100916 while (true) {
917 if (current->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100918 !isolate->MayNamedAccess(current, name, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100919 // Access check callback denied the access, but some properties
920 // can have a special permissions which override callbacks descision
921 // (currently see v8::AccessControl).
922 break;
923 }
924
925 if (current == holder) {
926 return true;
927 }
928
929 current = JSObject::cast(current->GetPrototype());
930 }
931
932 // API callbacks can have per callback access exceptions.
933 switch (result->type()) {
934 case CALLBACKS: {
935 if (CheckAccessException(result, access_type)) {
936 return true;
937 }
938 break;
939 }
940 case INTERCEPTOR: {
941 // If the object has an interceptor, try real named properties.
942 // Overwrite the result to fetch the correct property later.
943 holder->LookupRealNamedProperty(name, result);
944 if (result->IsProperty()) {
945 if (CheckAccessException(result, access_type)) {
946 return true;
947 }
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
Steve Block44f0eee2011-05-26 01:26:41 +0100955 isolate->ReportFailedAccessCheck(current, access_type);
Steve Block1e0659c2011-05-24 12:43:12 +0100956 return false;
957}
958
959
960// TODO(1095): we should traverse hidden prototype hierachy as well.
961static bool CheckElementAccess(JSObject* obj,
962 uint32_t index,
963 v8::AccessType access_type) {
964 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100965 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100966 return false;
967 }
968
969 return true;
970}
971
972
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100973// Enumerator used as indices into the array returned from GetOwnProperty
974enum PropertyDescriptorIndices {
975 IS_ACCESSOR_INDEX,
976 VALUE_INDEX,
977 GETTER_INDEX,
978 SETTER_INDEX,
979 WRITABLE_INDEX,
980 ENUMERABLE_INDEX,
981 CONFIGURABLE_INDEX,
982 DESCRIPTOR_SIZE
983};
984
Leon Clarkee46be812010-01-19 14:06:41 +0000985// Returns an array with the property description:
986// if args[1] is not a property on args[0]
987// returns undefined
988// if args[1] is a data property on args[0]
989// [false, value, Writeable, Enumerable, Configurable]
990// if args[1] is an accessor on args[0]
991// [true, GetFunction, SetFunction, Enumerable, Configurable]
Ben Murdoch8b112d22011-06-08 16:22:53 +0100992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
Leon Clarkee46be812010-01-19 14:06:41 +0000993 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100994 Heap* heap = isolate->heap();
995 HandleScope scope(isolate);
996 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
997 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000998 LookupResult result(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1000 CONVERT_ARG_CHECKED(String, name, 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001001
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001002 // This could be an element.
1003 uint32_t index;
1004 if (name->AsArrayIndex(&index)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001005 switch (obj->HasLocalElement(index)) {
1006 case JSObject::UNDEFINED_ELEMENT:
Steve Block44f0eee2011-05-26 01:26:41 +01001007 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001008
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001009 case JSObject::STRING_CHARACTER_ELEMENT: {
1010 // Special handling of string objects according to ECMAScript 5
1011 // 15.5.5.2. Note that this might be a string object with elements
1012 // other than the actual string value. This is covered by the
1013 // subsequent cases.
1014 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1015 Handle<String> str(String::cast(js_value->value()));
Steve Block1e0659c2011-05-24 12:43:12 +01001016 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001017
Steve Block44f0eee2011-05-26 01:26:41 +01001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001019 elms->set(VALUE_INDEX, *substr);
Steve Block44f0eee2011-05-26 01:26:41 +01001020 elms->set(WRITABLE_INDEX, heap->false_value());
1021 elms->set(ENUMERABLE_INDEX, heap->false_value());
1022 elms->set(CONFIGURABLE_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001023 return *desc;
1024 }
1025
1026 case JSObject::INTERCEPTED_ELEMENT:
1027 case JSObject::FAST_ELEMENT: {
Steve Block44f0eee2011-05-26 01:26:41 +01001028 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001029 Handle<Object> value = Object::GetElement(obj, index);
Steve Block44f0eee2011-05-26 01:26:41 +01001030 RETURN_IF_EMPTY_HANDLE(isolate, value);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001031 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +01001032 elms->set(WRITABLE_INDEX, heap->true_value());
1033 elms->set(ENUMERABLE_INDEX, heap->true_value());
1034 elms->set(CONFIGURABLE_INDEX, heap->true_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001035 return *desc;
1036 }
1037
1038 case JSObject::DICTIONARY_ELEMENT: {
Steve Block1e0659c2011-05-24 12:43:12 +01001039 Handle<JSObject> holder = obj;
1040 if (obj->IsJSGlobalProxy()) {
1041 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001042 if (proto->IsNull()) return heap->undefined_value();
Steve Block1e0659c2011-05-24 12:43:12 +01001043 ASSERT(proto->IsJSGlobalObject());
1044 holder = Handle<JSObject>(JSObject::cast(proto));
1045 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001046 FixedArray* elements = FixedArray::cast(holder->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00001047 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001048 if (elements->map() == heap->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001049 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001050 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001051 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001052 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001053 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001054 ASSERT(entry != SeededNumberDictionary::kNotFound);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001055 PropertyDetails details = dictionary->DetailsAt(entry);
1056 switch (details.type()) {
1057 case CALLBACKS: {
1058 // This is an accessor property with getter and/or setter.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001059 AccessorPair* accessors =
1060 AccessorPair::cast(dictionary->ValueAt(entry));
Steve Block44f0eee2011-05-26 01:26:41 +01001061 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +01001062 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001063 elms->set(GETTER_INDEX, accessors->getter());
Steve Block1e0659c2011-05-24 12:43:12 +01001064 }
1065 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001066 elms->set(SETTER_INDEX, accessors->setter());
Steve Block1e0659c2011-05-24 12:43:12 +01001067 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001068 break;
1069 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001070 case NORMAL: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001071 // This is a data property.
Steve Block44f0eee2011-05-26 01:26:41 +01001072 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001073 Handle<Object> value = Object::GetElement(obj, index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001074 ASSERT(!value.is_null());
1075 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +01001076 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001077 break;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001078 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001079 default:
1080 UNREACHABLE();
1081 break;
1082 }
Steve Block44f0eee2011-05-26 01:26:41 +01001083 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1084 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001085 return *desc;
1086 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001087 }
1088 }
1089
Leon Clarkee46be812010-01-19 14:06:41 +00001090 // Use recursive implementation to also traverse hidden prototypes
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001091 GetOwnPropertyImplementation(*obj, *name, &result);
Leon Clarkee46be812010-01-19 14:06:41 +00001092
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001093 if (!result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001094 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001095 }
Steve Block1e0659c2011-05-24 12:43:12 +01001096
1097 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001098 return heap->false_value();
Leon Clarkee46be812010-01-19 14:06:41 +00001099 }
1100
Steve Block44f0eee2011-05-26 01:26:41 +01001101 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1102 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
Steve Block1e0659c2011-05-24 12:43:12 +01001103
1104 bool is_js_accessor = (result.type() == CALLBACKS) &&
Ben Murdochc7cc0282012-03-05 14:35:55 +00001105 (result.GetCallbackObject()->IsAccessorPair());
Steve Block1e0659c2011-05-24 12:43:12 +01001106
1107 if (is_js_accessor) {
1108 // __defineGetter__/__defineSetter__ callback.
Steve Block44f0eee2011-05-26 01:26:41 +01001109 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +01001110
Ben Murdochc7cc0282012-03-05 14:35:55 +00001111 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
Steve Block1e0659c2011-05-24 12:43:12 +01001112 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001113 elms->set(GETTER_INDEX, accessors->getter());
Steve Block1e0659c2011-05-24 12:43:12 +01001114 }
1115 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001116 elms->set(SETTER_INDEX, accessors->setter());
Steve Block1e0659c2011-05-24 12:43:12 +01001117 }
1118 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001119 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
Steve Block1e0659c2011-05-24 12:43:12 +01001121
1122 PropertyAttributes attrs;
1123 Object* value;
1124 // GetProperty will check access and report any violations.
1125 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1126 if (!maybe_value->ToObject(&value)) return maybe_value;
1127 }
1128 elms->set(VALUE_INDEX, value);
1129 }
1130
Leon Clarkee46be812010-01-19 14:06:41 +00001131 return *desc;
1132}
1133
1134
Ben Murdoch8b112d22011-06-08 16:22:53 +01001135RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
Steve Block8defd9f2010-07-08 12:39:36 +01001136 ASSERT(args.length() == 1);
1137 CONVERT_CHECKED(JSObject, obj, args[0]);
1138 return obj->PreventExtensions();
1139}
1140
Steve Block1e0659c2011-05-24 12:43:12 +01001141
Ben Murdoch8b112d22011-06-08 16:22:53 +01001142RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
Leon Clarkee46be812010-01-19 14:06:41 +00001143 ASSERT(args.length() == 1);
1144 CONVERT_CHECKED(JSObject, obj, args[0]);
Steve Block1e0659c2011-05-24 12:43:12 +01001145 if (obj->IsJSGlobalProxy()) {
1146 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001147 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +01001148 ASSERT(proto->IsJSGlobalObject());
1149 obj = JSObject::cast(proto);
1150 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001151 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
Leon Clarkee46be812010-01-19 14:06:41 +00001152}
1153
1154
Ben Murdoch8b112d22011-06-08 16:22:53 +01001155RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01001156 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 ASSERT(args.length() == 3);
1158 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1159 CONVERT_ARG_CHECKED(String, pattern, 1);
1160 CONVERT_ARG_CHECKED(String, flags, 2);
1161 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1162 if (result.is_null()) return Failure::Exception();
1163 return *result;
1164}
1165
1166
Ben Murdoch8b112d22011-06-08 16:22:53 +01001167RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001168 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 ASSERT(args.length() == 1);
1170 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001171 return *isolate->factory()->CreateApiFunction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001172}
1173
1174
Ben Murdoch8b112d22011-06-08 16:22:53 +01001175RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 ASSERT(args.length() == 1);
1177 Object* arg = args[0];
1178 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
Steve Block44f0eee2011-05-26 01:26:41 +01001179 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001180}
1181
1182
Ben Murdoch8b112d22011-06-08 16:22:53 +01001183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001184 ASSERT(args.length() == 2);
1185 CONVERT_CHECKED(HeapObject, templ, args[0]);
1186 CONVERT_CHECKED(Smi, field, args[1]);
1187 int index = field->value();
1188 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1189 InstanceType type = templ->map()->instance_type();
1190 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1191 type == OBJECT_TEMPLATE_INFO_TYPE);
1192 RUNTIME_ASSERT(offset > 0);
Steve Block3ce2e202009-11-05 08:53:23 +00001193 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001194 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1195 } else {
1196 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1197 }
1198 return *HeapObject::RawField(templ, offset);
1199}
1200
1201
Ben Murdoch8b112d22011-06-08 16:22:53 +01001202RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001203 ASSERT(args.length() == 1);
1204 CONVERT_CHECKED(HeapObject, object, args[0]);
1205 Map* old_map = object->map();
1206 bool needs_access_checks = old_map->is_access_check_needed();
1207 if (needs_access_checks) {
1208 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -07001209 Object* new_map;
1210 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1211 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1212 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001213
1214 Map::cast(new_map)->set_is_access_check_needed(false);
1215 object->set_map(Map::cast(new_map));
1216 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001217 return isolate->heap()->ToBoolean(needs_access_checks);
Steve Blocka7e24c12009-10-30 11:49:00 +00001218}
1219
1220
Ben Murdoch8b112d22011-06-08 16:22:53 +01001221RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 ASSERT(args.length() == 1);
1223 CONVERT_CHECKED(HeapObject, object, args[0]);
1224 Map* old_map = object->map();
1225 if (!old_map->is_access_check_needed()) {
1226 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -07001227 Object* new_map;
1228 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1229 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1230 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001231
1232 Map::cast(new_map)->set_is_access_check_needed(true);
1233 object->set_map(Map::cast(new_map));
1234 }
Steve Block44f0eee2011-05-26 01:26:41 +01001235 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001236}
1237
1238
Steve Block44f0eee2011-05-26 01:26:41 +01001239static Failure* ThrowRedeclarationError(Isolate* isolate,
1240 const char* type,
1241 Handle<String> name) {
1242 HandleScope scope(isolate);
1243 Handle<Object> type_handle =
1244 isolate->factory()->NewStringFromAscii(CStrVector(type));
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 Handle<Object> args[2] = { type_handle, name };
1246 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001247 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1248 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001249}
1250
1251
Ben Murdoch8b112d22011-06-08 16:22:53 +01001252RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001253 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +01001254 HandleScope scope(isolate);
1255 Handle<GlobalObject> global = Handle<GlobalObject>(
1256 isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001257
Steve Block3ce2e202009-11-05 08:53:23 +00001258 Handle<Context> context = args.at<Context>(0);
1259 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
Ben Murdoch589d6972011-11-30 16:04:58 +00001260 CONVERT_SMI_ARG_CHECKED(flags, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001261
1262 // Traverse the name/value pairs and set the properties.
1263 int length = pairs->length();
1264 for (int i = 0; i < length; i += 2) {
Steve Block44f0eee2011-05-26 01:26:41 +01001265 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 Handle<String> name(String::cast(pairs->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +01001267 Handle<Object> value(pairs->get(i + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001268
1269 // We have to declare a global const property. To capture we only
1270 // assign to it when evaluating the assignment for "const x =
1271 // <expr>" the initial value is the hole.
1272 bool is_const_property = value->IsTheHole();
Ben Murdoch589d6972011-11-30 16:04:58 +00001273 bool is_function_declaration = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 if (value->IsUndefined() || is_const_property) {
1275 // Lookup the property in the global object, and don't set the
1276 // value of the variable if the property is already there.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001277 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001278 global->Lookup(*name, &lookup);
1279 if (lookup.IsProperty()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001280 // We found an existing property. Unless it was an interceptor
1281 // that claims the property is absent, skip this declaration.
1282 if (lookup.type() != INTERCEPTOR) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 continue;
1284 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001285 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1286 if (attributes != ABSENT) {
1287 continue;
1288 }
1289 // Fall-through and introduce the absent property by using
1290 // SetProperty.
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 }
1292 } else {
Ben Murdoch589d6972011-11-30 16:04:58 +00001293 is_function_declaration = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 // Copy the function and update its context. Use it as value.
Steve Block6ded16b2010-05-10 14:33:55 +01001295 Handle<SharedFunctionInfo> shared =
1296 Handle<SharedFunctionInfo>::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 Handle<JSFunction> function =
Steve Block44f0eee2011-05-26 01:26:41 +01001298 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1299 context,
1300 TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00001301 value = function;
1302 }
1303
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001304 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001305 global->LocalLookup(*name, &lookup);
1306
Ben Murdoch589d6972011-11-30 16:04:58 +00001307 // Compute the property attributes. According to ECMA-262, section
1308 // 13, page 71, the property must be read-only and
1309 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1310 // property as read-only, so we don't either.
1311 int attr = NONE;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001312 if (!DeclareGlobalsEvalFlag::decode(flags)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001313 attr |= DONT_DELETE;
1314 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001315 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
Ben Murdoch589d6972011-11-30 16:04:58 +00001316 if (is_const_property || (is_native && is_function_declaration)) {
1317 attr |= READ_ONLY;
1318 }
1319
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001320 // Safari does not allow the invocation of callback setters for
1321 // function declarations. To mimic this behavior, we do not allow
1322 // the invocation of setters for function values. This makes a
1323 // difference for global functions with the same names as event
1324 // handlers such as "function onload() {}". Firefox does call the
1325 // onload setter in those case and Safari does not. We follow
1326 // Safari for compatibility.
1327 if (value->IsJSFunction()) {
1328 // Do not change DONT_DELETE to false from true.
1329 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001330 attr |= lookup.GetAttributes() & DONT_DELETE;
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001332 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1333
Ben Murdochc7cc0282012-03-05 14:35:55 +00001334 RETURN_IF_EMPTY_HANDLE(
1335 isolate,
1336 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1337 attributes));
Steve Blocka7e24c12009-10-30 11:49:00 +00001338 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
Ben Murdochc7cc0282012-03-05 14:35:55 +00001342 RETURN_IF_EMPTY_HANDLE(
1343 isolate,
1344 JSReceiver::SetProperty(global, name, value,
1345 static_cast<PropertyAttributes>(attr),
1346 strict_mode_flag));
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 }
1348 }
1349
Steve Block44f0eee2011-05-26 01:26:41 +01001350 ASSERT(!isolate->has_pending_exception());
1351 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001352}
1353
1354
Ben Murdoch8b112d22011-06-08 16:22:53 +01001355RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001356 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001357 ASSERT(args.length() == 4);
1358
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001359 // Declarations are always made in a function or global context. In the
1360 // case of eval code, the context passed is the context of the caller,
1361 // which may be some nested context and not the declaration context.
1362 RUNTIME_ASSERT(args[0]->IsContext());
1363 Handle<Context> context(Context::cast(args[0])->declaration_context());
1364
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 Handle<String> name(String::cast(args[1]));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001366 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001367 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Steve Block44f0eee2011-05-26 01:26:41 +01001368 Handle<Object> initial_value(args[3], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369
Steve Blocka7e24c12009-10-30 11:49:00 +00001370 int index;
1371 PropertyAttributes attributes;
1372 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001373 BindingFlags binding_flags;
Steve Blocka7e24c12009-10-30 11:49:00 +00001374 Handle<Object> holder =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001375 context->Lookup(name, flags, &index, &attributes, &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001376
1377 if (attributes != ABSENT) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001378 // The name was declared before; check for conflicting re-declarations.
Steve Blocka7e24c12009-10-30 11:49:00 +00001379 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1380 // Functions are not read-only.
1381 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1382 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001383 return ThrowRedeclarationError(isolate, type, name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001384 }
1385
1386 // Initialize it if necessary.
1387 if (*initial_value != NULL) {
1388 if (index >= 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001389 ASSERT(holder.is_identical_to(context));
1390 if (((attributes & READ_ONLY) == 0) ||
1391 context->get(index)->IsTheHole()) {
1392 context->set(index, *initial_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 }
1394 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001395 // Slow case: The property is in the context extension object of a
1396 // function context or the global object of a global context.
1397 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Steve Block1e0659c2011-05-24 12:43:12 +01001398 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001399 isolate,
Ben Murdochc7cc0282012-03-05 14:35:55 +00001400 JSReceiver::SetProperty(object, name, initial_value, mode,
1401 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001402 }
1403 }
1404
1405 } else {
1406 // The property is not in the function context. It needs to be
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
Steve Blocka7e24c12009-10-30 11:49:00 +00001410 if (context->has_extension()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
Steve Block44f0eee2011-05-26 01:26:41 +01001416 isolate->context_extension_function());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001417 context->set_extension(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001418 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001419 ASSERT(*object != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001420
1421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001424 ASSERT(!object->HasLocalProperty(*name));
Steve Block44f0eee2011-05-26 01:26:41 +01001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001426 if (*initial_value != NULL) value = initial_value;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001434 !object->IsJSContextExtensionObject()) {
1435 LookupResult lookup(isolate);
1436 object->Lookup(*name, &lookup);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001437 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001438 return ThrowRedeclarationError(isolate, "const", name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001439 }
1440 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001441 RETURN_IF_EMPTY_HANDLE(
1442 isolate,
1443 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001444 }
1445
Steve Block44f0eee2011-05-26 01:26:41 +01001446 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001447}
1448
1449
Ben Murdoch8b112d22011-06-08 16:22:53 +01001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001451 NoHandleAllocation nha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001452 // args[0] == name
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001453 // args[1] == language_mode
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001454 // args[2] == value (optional)
Steve Blocka7e24c12009-10-30 11:49:00 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
Steve Blocka7e24c12009-10-30 11:49:00 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001462 GlobalObject* global = isolate->context()->global();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001463 RUNTIME_ASSERT(args[1]->IsSmi());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
Steve Blocka7e24c12009-10-30 11:49:00 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
1473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001476 // to assign to the property.
Steve Blockd0582a62009-12-15 09:54:21 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001479 Object* object = global;
1480 LookupResult lookup(isolate);
1481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001485 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
1495 &lookup, *name, args[2], attributes, strict_mode_flag);
1496 } else {
1497 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00001498 }
1499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001501 object = raw_holder->GetPrototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00001502 }
1503
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001504 // Reload global in case the loop above performed a GC.
Steve Block44f0eee2011-05-26 01:26:41 +01001505 global = isolate->context()->global();
Steve Blockd0582a62009-12-15 09:54:21 +00001506 if (assign) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 }
Steve Block44f0eee2011-05-26 01:26:41 +01001509 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001510}
1511
1512
Ben Murdoch8b112d22011-06-08 16:22:53 +01001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
Steve Block44f0eee2011-05-26 01:26:41 +01001522 GlobalObject* global = isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
Ben Murdoch086aeea2011-05-13 15:57:08 +01001533 // We use SetLocalPropertyIgnoreAttributes instead
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001534 LookupResult lookup(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001540 }
1541
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 if (!lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 // Restore global object from context (in case of GC) and continue
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001544 // with setting the value.
Steve Block44f0eee2011-05-26 01:26:41 +01001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001547
Steve Block1e0659c2011-05-24 12:43:12 +01001548 // BUG 1213575: Handle the case where we have to set a read-only
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001551 // Passing non-strict mode because the property is writable.
Ben Murdochc7cc0282012-03-05 14:35:55 +00001552 RETURN_IF_EMPTY_HANDLE(
1553 isolate,
1554 JSReceiver::SetProperty(global, name, value, attributes,
1555 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001556 return *value;
1557 }
1558
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001559 // Set the value, but only if we're assigning the initial value to a
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 // constant. For now, we determine this by checking if the
1561 // current value is the hole.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001562 // Strict mode handling not needed (const is disallowed in strict mode).
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 PropertyType type = lookup.type();
1564 if (type == FIELD) {
1565 FixedArray* properties = global->properties();
1566 int index = lookup.GetFieldIndex();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001567 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 properties->set(index, *value);
1569 }
1570 } else if (type == NORMAL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001571 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1572 !lookup.IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 global->SetNormalizedProperty(&lookup, *value);
1574 }
1575 } else {
1576 // Ignore re-initialization of constants that have already been
1577 // assigned a function value.
1578 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1579 }
1580
1581 // Use the set value as the result of the operation.
1582 return *value;
1583}
1584
1585
Ben Murdoch8b112d22011-06-08 16:22:53 +01001586RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001587 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001588 ASSERT(args.length() == 3);
1589
Steve Block44f0eee2011-05-26 01:26:41 +01001590 Handle<Object> value(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 ASSERT(!value->IsTheHole());
Steve Blocka7e24c12009-10-30 11:49:00 +00001592
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001593 // Initializations are always done in a function or global context.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001594 RUNTIME_ASSERT(args[1]->IsContext());
1595 Handle<Context> context(Context::cast(args[1])->declaration_context());
1596
1597 Handle<String> name(String::cast(args[2]));
Steve Blocka7e24c12009-10-30 11:49:00 +00001598
1599 int index;
1600 PropertyAttributes attributes;
1601 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001602 BindingFlags binding_flags;
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 Handle<Object> holder =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001604 context->Lookup(name, flags, &index, &attributes, &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00001605
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 if (index >= 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001607 ASSERT(holder->IsContext());
1608 // Property was found in a context. Perform the assignment if we
1609 // found some non-constant or an uninitialized constant.
1610 Handle<Context> context = Handle<Context>::cast(holder);
1611 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1612 context->set(index, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 }
1614 return *value;
1615 }
1616
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001617 // The property could not be found, we introduce it as a property of the
1618 // global object.
Steve Blocka7e24c12009-10-30 11:49:00 +00001619 if (attributes == ABSENT) {
Steve Block44f0eee2011-05-26 01:26:41 +01001620 Handle<JSObject> global = Handle<JSObject>(
1621 isolate->context()->global());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001622 // Strict mode not needed (const disallowed in strict mode).
1623 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001624 isolate,
Ben Murdochc7cc0282012-03-05 14:35:55 +00001625 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 return *value;
1627 }
1628
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001629 // The property was present in some function's context extension object,
1630 // as a property on the subject of a with, or as a property of the global
1631 // object.
1632 //
1633 // In most situations, eval-introduced consts should still be present in
1634 // the context extension object. However, because declaration and
1635 // initialization are separate, the property might have been deleted
1636 // before we reach the initialization point.
1637 //
1638 // Example:
1639 //
1640 // function f() { eval("delete x; const x;"); }
1641 //
1642 // In that case, the initialization behaves like a normal assignment.
1643 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001645 if (*object == context->extension()) {
1646 // This is the property that was introduced by the const declaration.
1647 // Set it if it hasn't been set before. NOTE: We cannot use
1648 // GetProperty() to get the current value as it 'unholes' the value.
1649 LookupResult lookup(isolate);
1650 object->LocalLookupRealNamedProperty(*name, &lookup);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001651 ASSERT(lookup.IsFound()); // the property was declared
Steve Blocka7e24c12009-10-30 11:49:00 +00001652 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1653
1654 PropertyType type = lookup.type();
1655 if (type == FIELD) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001656 FixedArray* properties = object->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 int index = lookup.GetFieldIndex();
1658 if (properties->get(index)->IsTheHole()) {
1659 properties->set(index, *value);
1660 }
1661 } else if (type == NORMAL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001662 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1663 object->SetNormalizedProperty(&lookup, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 }
1665 } else {
1666 // We should not reach here. Any real, named property should be
1667 // either a field or a dictionary slot.
1668 UNREACHABLE();
1669 }
1670 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001671 // The property was found on some other object. Set it if it is not a
1672 // read-only property.
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 if ((attributes & READ_ONLY) == 0) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001674 // Strict mode not needed (const disallowed in strict mode).
Steve Block1e0659c2011-05-24 12:43:12 +01001675 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001676 isolate,
Ben Murdochc7cc0282012-03-05 14:35:55 +00001677 JSReceiver::SetProperty(object, name, value, attributes,
1678 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 }
1680 }
1681
1682 return *value;
1683}
1684
1685
Ben Murdoch8b112d22011-06-08 16:22:53 +01001686RUNTIME_FUNCTION(MaybeObject*,
1687 Runtime_OptimizeObjectForAddingMultipleProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01001688 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_CHECKED(JSObject, object, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001691 CONVERT_SMI_ARG_CHECKED(properties, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001692 if (object->HasFastProperties()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001693 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
Steve Blocka7e24c12009-10-30 11:49:00 +00001694 }
1695 return *object;
1696}
1697
1698
Ben Murdoch8b112d22011-06-08 16:22:53 +01001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
Steve Block44f0eee2011-05-26 01:26:41 +01001700 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 ASSERT(args.length() == 4);
1702 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1703 CONVERT_ARG_CHECKED(String, subject, 1);
1704 // Due to the way the JS calls are constructed this must be less than the
1705 // length of a string, i.e. it is always a Smi. We check anyway for security.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001706 CONVERT_SMI_ARG_CHECKED(index, 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00001707 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
1708 RUNTIME_ASSERT(last_match_info->HasFastElements());
1709 RUNTIME_ASSERT(index >= 0);
1710 RUNTIME_ASSERT(index <= subject->length());
Steve Block44f0eee2011-05-26 01:26:41 +01001711 isolate->counters()->regexp_entry_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 Handle<Object> result = RegExpImpl::Exec(regexp,
1713 subject,
1714 index,
1715 last_match_info);
1716 if (result.is_null()) return Failure::Exception();
1717 return *result;
1718}
1719
1720
Ben Murdoch8b112d22011-06-08 16:22:53 +01001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
Steve Block6ded16b2010-05-10 14:33:55 +01001722 ASSERT(args.length() == 3);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001723 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001724 if (elements_count < 0 ||
1725 elements_count > FixedArray::kMaxLength ||
1726 !Smi::IsValid(elements_count)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001727 return isolate->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01001728 }
John Reck59135872010-11-02 12:39:01 -07001729 Object* new_object;
1730 { MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +01001731 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
John Reck59135872010-11-02 12:39:01 -07001732 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1733 }
Steve Block6ded16b2010-05-10 14:33:55 +01001734 FixedArray* elements = FixedArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001735 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1736 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
John Reck59135872010-11-02 12:39:01 -07001737 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1738 }
Steve Block6ded16b2010-05-10 14:33:55 +01001739 {
1740 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +01001741 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001742 reinterpret_cast<HeapObject*>(new_object)->
Steve Block44f0eee2011-05-26 01:26:41 +01001743 set_map(isolate->global_context()->regexp_result_map());
Steve Block6ded16b2010-05-10 14:33:55 +01001744 }
1745 JSArray* array = JSArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001746 array->set_properties(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001747 array->set_elements(elements);
1748 array->set_length(Smi::FromInt(elements_count));
1749 // Write in-object properties after the length of the array.
1750 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1751 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1752 return array;
1753}
1754
1755
Ben Murdoch8b112d22011-06-08 16:22:53 +01001756RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
Steve Block6ded16b2010-05-10 14:33:55 +01001757 AssertNoAllocation no_alloc;
1758 ASSERT(args.length() == 5);
1759 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1760 CONVERT_CHECKED(String, source, args[1]);
1761
1762 Object* global = args[2];
Steve Block44f0eee2011-05-26 01:26:41 +01001763 if (!global->IsTrue()) global = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001764
1765 Object* ignoreCase = args[3];
Steve Block44f0eee2011-05-26 01:26:41 +01001766 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001767
1768 Object* multiline = args[4];
Steve Block44f0eee2011-05-26 01:26:41 +01001769 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001770
1771 Map* map = regexp->map();
1772 Object* constructor = map->constructor();
1773 if (constructor->IsJSFunction() &&
1774 JSFunction::cast(constructor)->initial_map() == map) {
1775 // If we still have the original map, set in-object properties directly.
1776 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001777 // Both true and false are immovable immortal objects so no need for write
1778 // barrier.
1779 regexp->InObjectPropertyAtPut(
1780 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1781 regexp->InObjectPropertyAtPut(
1782 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1783 regexp->InObjectPropertyAtPut(
1784 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
Steve Block6ded16b2010-05-10 14:33:55 +01001785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001787 SKIP_WRITE_BARRIER); // It's a Smi.
Steve Block6ded16b2010-05-10 14:33:55 +01001788 return regexp;
1789 }
1790
Steve Block44f0eee2011-05-26 01:26:41 +01001791 // Map has changed, so use generic, but slower, method.
Steve Block6ded16b2010-05-10 14:33:55 +01001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
Steve Block44f0eee2011-05-26 01:26:41 +01001796 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -07001797 MaybeObject* result;
Steve Block44f0eee2011-05-26 01:26:41 +01001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001799 source,
1800 final);
John Reck59135872010-11-02 12:39:01 -07001801 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001803 global,
1804 final);
John Reck59135872010-11-02 12:39:01 -07001805 ASSERT(!result->IsFailure());
1806 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001808 ignoreCase,
1809 final);
John Reck59135872010-11-02 12:39:01 -07001810 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001812 multiline,
1813 final);
John Reck59135872010-11-02 12:39:01 -07001814 ASSERT(!result->IsFailure());
1815 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001817 Smi::FromInt(0),
1818 writable);
John Reck59135872010-11-02 12:39:01 -07001819 ASSERT(!result->IsFailure());
1820 USE(result);
Steve Block6ded16b2010-05-10 14:33:55 +01001821 return regexp;
1822}
1823
1824
Ben Murdoch8b112d22011-06-08 16:22:53 +01001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
Steve Block44f0eee2011-05-26 01:26:41 +01001826 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
Steve Block44f0eee2011-05-26 01:26:41 +01001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001832 return Smi::FromInt(0);
1833}
1834
1835
Steve Block44f0eee2011-05-26 01:26:41 +01001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
Steve Block6ded16b2010-05-10 14:33:55 +01001838 const char* name,
Kristian Monsen25f61362010-05-21 11:50:48 +01001839 Builtins::Name builtin_name) {
Steve Block44f0eee2011-05-26 01:26:41 +01001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
Steve Block6ded16b2010-05-10 14:33:55 +01001848 optimized->shared()->DontAdaptArguments();
Ben Murdochc7cc0282012-03-05 14:35:55 +00001849 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +01001850 return optimized;
1851}
1852
1853
Ben Murdoch8b112d22011-06-08 16:22:53 +01001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
Steve Block44f0eee2011-05-26 01:26:41 +01001855 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
Steve Block44f0eee2011-05-26 01:26:41 +01001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
Steve Block6ded16b2010-05-10 14:33:55 +01001866
1867 return *holder;
1868}
1869
1870
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001872 ASSERT(args.length() == 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001873 CONVERT_CHECKED(JSReceiver, callable, args[0]);
1874
1875 if (!callable->IsJSFunction()) {
1876 HandleScope scope(isolate);
1877 bool threw = false;
1878 Handle<Object> delegate =
1879 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1880 if (threw) return Failure::Exception();
1881 callable = JSFunction::cast(*delegate);
1882 }
1883 JSFunction* function = JSFunction::cast(callable);
1884
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001885 SharedFunctionInfo* shared = function->shared();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001886 if (shared->native() || !shared->is_classic_mode()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001887 return isolate->heap()->undefined_value();
1888 }
1889 // Returns undefined for strict or native functions, or
1890 // the associated global receiver for "normal" functions.
1891
Steve Block44f0eee2011-05-26 01:26:41 +01001892 Context* global_context =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001893 function->context()->global()->global_context();
Steve Block6ded16b2010-05-10 14:33:55 +01001894 return global_context->global()->global_receiver();
1895}
1896
1897
Ben Murdoch8b112d22011-06-08 16:22:53 +01001898RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +01001899 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001900 ASSERT(args.length() == 4);
1901 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001902 int index = args.smi_at(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 Handle<String> pattern = args.at<String>(2);
1904 Handle<String> flags = args.at<String>(3);
1905
1906 // Get the RegExp function from the context in the literals array.
1907 // This is the RegExp function from the context in which the
1908 // function was created. We do not use the RegExp function from the
1909 // current global context because this might be the RegExp function
1910 // from another context which we should not have access to.
1911 Handle<JSFunction> constructor =
1912 Handle<JSFunction>(
1913 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
1914 // Compute the regular expression literal.
1915 bool has_pending_exception;
1916 Handle<Object> regexp =
1917 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1918 &has_pending_exception);
1919 if (has_pending_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01001920 ASSERT(isolate->has_pending_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00001921 return Failure::Exception();
1922 }
1923 literals->set(index, *regexp);
1924 return *regexp;
1925}
1926
1927
Ben Murdoch8b112d22011-06-08 16:22:53 +01001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 1);
1931
1932 CONVERT_CHECKED(JSFunction, f, args[0]);
1933 return f->shared()->name();
1934}
1935
1936
Ben Murdoch8b112d22011-06-08 16:22:53 +01001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 2);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 CONVERT_CHECKED(String, name, args[1]);
1943 f->shared()->set_name(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001944 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001945}
1946
1947
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
1952 return isolate->heap()->ToBoolean(
1953 f->shared()->name_should_print_as_anonymous());
1954}
1955
1956
1957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960 CONVERT_CHECKED(JSFunction, f, args[0]);
1961 f->shared()->set_name_should_print_as_anonymous(true);
1962 return isolate->heap()->undefined_value();
1963}
1964
1965
Ben Murdoch8b112d22011-06-08 16:22:53 +01001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
Steve Block6ded16b2010-05-10 14:33:55 +01001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001971 Object* obj = f->RemovePrototype();
1972 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001973
Steve Block44f0eee2011-05-26 01:26:41 +01001974 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001975}
1976
1977
Ben Murdoch8b112d22011-06-08 16:22:53 +01001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +01001979 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, fun, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001983 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1984 if (!script->IsScript()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001985
1986 return *GetScriptWrapper(Handle<Script>::cast(script));
1987}
1988
1989
Ben Murdoch8b112d22011-06-08 16:22:53 +01001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001991 NoHandleAllocation ha;
1992 ASSERT(args.length() == 1);
1993
1994 CONVERT_CHECKED(JSFunction, f, args[0]);
1995 return f->shared()->GetSourceCode();
1996}
1997
1998
Ben Murdoch8b112d22011-06-08 16:22:53 +01001999RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002000 NoHandleAllocation ha;
2001 ASSERT(args.length() == 1);
2002
2003 CONVERT_CHECKED(JSFunction, fun, args[0]);
2004 int pos = fun->shared()->start_position();
2005 return Smi::FromInt(pos);
2006}
2007
2008
Ben Murdoch8b112d22011-06-08 16:22:53 +01002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002010 ASSERT(args.length() == 2);
2011
Ben Murdochb0fe1622011-05-05 13:52:32 +01002012 CONVERT_CHECKED(Code, code, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2014
Steve Blocka7e24c12009-10-30 11:49:00 +00002015 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2016
2017 Address pc = code->address() + offset;
Ben Murdochb0fe1622011-05-05 13:52:32 +01002018 return Smi::FromInt(code->SourcePosition(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00002019}
2020
2021
Ben Murdoch8b112d22011-06-08 16:22:53 +01002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002023 NoHandleAllocation ha;
2024 ASSERT(args.length() == 2);
2025
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(String, name, args[1]);
2028 fun->SetInstanceClassName(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002029 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002030}
2031
2032
Ben Murdoch8b112d22011-06-08 16:22:53 +01002033RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002034 NoHandleAllocation ha;
2035 ASSERT(args.length() == 2);
2036
2037 CONVERT_CHECKED(JSFunction, fun, args[0]);
2038 CONVERT_CHECKED(Smi, length, args[1]);
2039 fun->shared()->set_length(length->value());
2040 return length;
2041}
2042
2043
Ben Murdoch8b112d22011-06-08 16:22:53 +01002044RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002045 NoHandleAllocation ha;
2046 ASSERT(args.length() == 2);
2047
2048 CONVERT_CHECKED(JSFunction, fun, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01002049 ASSERT(fun->should_have_prototype());
John Reck59135872010-11-02 12:39:01 -07002050 Object* obj;
2051 { MaybeObject* maybe_obj =
2052 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2053 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2054 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 return args[0]; // return TOS
2056}
2057
2058
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2060 NoHandleAllocation ha;
2061 RUNTIME_ASSERT(args.length() == 1);
2062 CONVERT_CHECKED(JSFunction, function, args[0]);
2063
2064 MaybeObject* maybe_name =
2065 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2066 String* name;
2067 if (!maybe_name->To(&name)) return maybe_name;
2068
2069 if (function->HasFastProperties()) {
2070 // Construct a new field descriptor with updated attributes.
2071 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2072 int index = instance_desc->Search(name);
2073 ASSERT(index != DescriptorArray::kNotFound);
2074 PropertyDetails details(instance_desc->GetDetails(index));
2075 CallbacksDescriptor new_desc(name,
2076 instance_desc->GetValue(index),
2077 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2078 details.index());
2079 // Construct a new field descriptors array containing the new descriptor.
2080 Object* descriptors_unchecked;
2081 { MaybeObject* maybe_descriptors_unchecked =
2082 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2083 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2084 return maybe_descriptors_unchecked;
2085 }
2086 }
2087 DescriptorArray* new_descriptors =
2088 DescriptorArray::cast(descriptors_unchecked);
2089 // Create a new map featuring the new field descriptors array.
2090 Object* map_unchecked;
2091 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2092 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2093 return maybe_map_unchecked;
2094 }
2095 }
2096 Map* new_map = Map::cast(map_unchecked);
2097 new_map->set_instance_descriptors(new_descriptors);
2098 function->set_map(new_map);
2099 } else { // Dictionary properties.
2100 // Directly manipulate the property details.
2101 int entry = function->property_dictionary()->FindEntry(name);
2102 ASSERT(entry != StringDictionary::kNotFound);
2103 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2104 PropertyDetails new_details(
2105 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2106 details.type(),
2107 details.index());
2108 function->property_dictionary()->DetailsAtPut(entry, new_details);
2109 }
2110 return function;
2111}
2112
2113
Ben Murdoch8b112d22011-06-08 16:22:53 +01002114RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002115 NoHandleAllocation ha;
2116 ASSERT(args.length() == 1);
2117
2118 CONVERT_CHECKED(JSFunction, f, args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002119 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00002120}
2121
Steve Block44f0eee2011-05-26 01:26:41 +01002122
Ben Murdoch8b112d22011-06-08 16:22:53 +01002123RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002124 NoHandleAllocation ha;
2125 ASSERT(args.length() == 1);
2126
2127 CONVERT_CHECKED(JSFunction, f, args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002128 return isolate->heap()->ToBoolean(f->IsBuiltin());
Steve Blocka7e24c12009-10-30 11:49:00 +00002129}
2130
2131
Ben Murdoch8b112d22011-06-08 16:22:53 +01002132RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002133 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 ASSERT(args.length() == 2);
2135
2136 CONVERT_ARG_CHECKED(JSFunction, target, 0);
2137 Handle<Object> code = args.at<Object>(1);
2138
2139 Handle<Context> context(target->context());
2140
2141 if (!code->IsNull()) {
2142 RUNTIME_ASSERT(code->IsJSFunction());
2143 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Leon Clarke4515c472010-02-03 11:58:03 +00002144 Handle<SharedFunctionInfo> shared(fun->shared());
Leon Clarke4515c472010-02-03 11:58:03 +00002145
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002146 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002147 return Failure::Exception();
2148 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01002149 // Since we don't store the source for this we should never
2150 // optimize this.
2151 shared->code()->set_optimizable(false);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002152 // Set the code, scope info, formal parameter count,
2153 // and the length of the target function.
Iain Merrick75681382010-08-19 15:07:18 +01002154 target->shared()->set_code(shared->code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01002155 target->ReplaceCode(shared->code());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002156 target->shared()->set_scope_info(shared->scope_info());
Leon Clarke4515c472010-02-03 11:58:03 +00002157 target->shared()->set_length(shared->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002158 target->shared()->set_formal_parameter_count(
Leon Clarke4515c472010-02-03 11:58:03 +00002159 shared->formal_parameter_count());
Steve Blocka7e24c12009-10-30 11:49:00 +00002160 // Set the source code of the target function to undefined.
2161 // SetCode is only used for built-in constructors like String,
2162 // Array, and Object, and some web code
2163 // doesn't like seeing source code for constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01002164 target->shared()->set_script(isolate->heap()->undefined_value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01002165 target->shared()->code()->set_optimizable(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002166 // Clear the optimization hints related to the compiled code as these are no
2167 // longer valid when the code is overwritten.
2168 target->shared()->ClearThisPropertyAssignmentsInfo();
2169 context = Handle<Context>(fun->context());
2170
2171 // Make sure we get a fresh copy of the literal vector to avoid
2172 // cross context contamination.
2173 int number_of_literals = fun->NumberOfLiterals();
2174 Handle<FixedArray> literals =
Steve Block44f0eee2011-05-26 01:26:41 +01002175 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00002176 if (number_of_literals > 0) {
2177 // Insert the object, regexp and array functions in the literals
2178 // array prefix. These are the functions that will be used when
2179 // creating object, regexp and array literals.
2180 literals->set(JSFunction::kLiteralGlobalContextIndex,
2181 context->global_context());
2182 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002183 target->set_literals(*literals);
Steve Block44f0eee2011-05-26 01:26:41 +01002184 target->set_next_function_link(isolate->heap()->undefined_value());
Ben Murdoch589d6972011-11-30 16:04:58 +00002185
2186 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2187 isolate->logger()->LogExistingFunction(
2188 shared, Handle<Code>(shared->code()));
2189 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002190 }
2191
2192 target->set_context(*context);
2193 return *target;
2194}
2195
2196
Ben Murdoch8b112d22011-06-08 16:22:53 +01002197RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01002198 HandleScope scope(isolate);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002199 ASSERT(args.length() == 2);
2200 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002201 CONVERT_SMI_ARG_CHECKED(num, 1);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002202 RUNTIME_ASSERT(num >= 0);
2203 SetExpectedNofProperties(function, num);
Steve Block44f0eee2011-05-26 01:26:41 +01002204 return isolate->heap()->undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002205}
2206
2207
Steve Block44f0eee2011-05-26 01:26:41 +01002208MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2209 Object* char_code) {
Leon Clarkee46be812010-01-19 14:06:41 +00002210 uint32_t code;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002211 if (char_code->ToArrayIndex(&code)) {
Leon Clarkee46be812010-01-19 14:06:41 +00002212 if (code <= 0xffff) {
Steve Block44f0eee2011-05-26 01:26:41 +01002213 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
Leon Clarkee46be812010-01-19 14:06:41 +00002214 }
2215 }
Steve Block44f0eee2011-05-26 01:26:41 +01002216 return isolate->heap()->empty_string();
Leon Clarkee46be812010-01-19 14:06:41 +00002217}
2218
2219
Ben Murdoch8b112d22011-06-08 16:22:53 +01002220RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 NoHandleAllocation ha;
2222 ASSERT(args.length() == 2);
2223
2224 CONVERT_CHECKED(String, subject, args[0]);
2225 Object* index = args[1];
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002226 RUNTIME_ASSERT(index->IsNumber());
Steve Blocka7e24c12009-10-30 11:49:00 +00002227
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002228 uint32_t i = 0;
2229 if (index->IsSmi()) {
2230 int value = Smi::cast(index)->value();
Steve Block44f0eee2011-05-26 01:26:41 +01002231 if (value < 0) return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002232 i = value;
2233 } else {
2234 ASSERT(index->IsHeapNumber());
2235 double value = HeapNumber::cast(index)->value();
2236 i = static_cast<uint32_t>(DoubleToInteger(value));
Leon Clarkee46be812010-01-19 14:06:41 +00002237 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002238
2239 // Flatten the string. If someone wants to get a char at an index
2240 // in a cons string, it is likely that more indices will be
2241 // accessed.
John Reck59135872010-11-02 12:39:01 -07002242 Object* flat;
2243 { MaybeObject* maybe_flat = subject->TryFlatten();
2244 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2245 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002246 subject = String::cast(flat);
2247
2248 if (i >= static_cast<uint32_t>(subject->length())) {
Steve Block44f0eee2011-05-26 01:26:41 +01002249 return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002250 }
2251
2252 return Smi::FromInt(subject->Get(i));
Leon Clarkee46be812010-01-19 14:06:41 +00002253}
2254
2255
Ben Murdoch8b112d22011-06-08 16:22:53 +01002256RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002257 NoHandleAllocation ha;
2258 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01002259 return CharFromCode(isolate, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002260}
2261
Steve Block6ded16b2010-05-10 14:33:55 +01002262
2263class FixedArrayBuilder {
2264 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002265 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2266 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002267 length_(0),
2268 has_non_smi_elements_(false) {
Steve Block6ded16b2010-05-10 14:33:55 +01002269 // Require a non-zero initial size. Ensures that doubling the size to
2270 // extend the array will work.
2271 ASSERT(initial_capacity > 0);
2272 }
2273
2274 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2275 : array_(backing_store),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002276 length_(0),
2277 has_non_smi_elements_(false) {
Steve Block6ded16b2010-05-10 14:33:55 +01002278 // Require a non-zero initial size. Ensures that doubling the size to
2279 // extend the array will work.
2280 ASSERT(backing_store->length() > 0);
2281 }
2282
2283 bool HasCapacity(int elements) {
2284 int length = array_->length();
2285 int required_length = length_ + elements;
2286 return (length >= required_length);
2287 }
2288
2289 void EnsureCapacity(int elements) {
2290 int length = array_->length();
2291 int required_length = length_ + elements;
2292 if (length < required_length) {
2293 int new_length = length;
2294 do {
2295 new_length *= 2;
2296 } while (new_length < required_length);
2297 Handle<FixedArray> extended_array =
Steve Block44f0eee2011-05-26 01:26:41 +01002298 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
Steve Block6ded16b2010-05-10 14:33:55 +01002299 array_->CopyTo(0, *extended_array, 0, length_);
2300 array_ = extended_array;
2301 }
2302 }
2303
2304 void Add(Object* value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002305 ASSERT(!value->IsSmi());
Steve Block6ded16b2010-05-10 14:33:55 +01002306 ASSERT(length_ < capacity());
2307 array_->set(length_, value);
2308 length_++;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002309 has_non_smi_elements_ = true;
Steve Block6ded16b2010-05-10 14:33:55 +01002310 }
2311
2312 void Add(Smi* value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002313 ASSERT(value->IsSmi());
Steve Block6ded16b2010-05-10 14:33:55 +01002314 ASSERT(length_ < capacity());
2315 array_->set(length_, value);
2316 length_++;
2317 }
2318
2319 Handle<FixedArray> array() {
2320 return array_;
2321 }
2322
2323 int length() {
2324 return length_;
2325 }
2326
2327 int capacity() {
2328 return array_->length();
2329 }
2330
2331 Handle<JSArray> ToJSArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01002332 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
Steve Block6ded16b2010-05-10 14:33:55 +01002333 result_array->set_length(Smi::FromInt(length_));
2334 return result_array;
2335 }
2336
2337 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002338 FACTORY->SetContent(target_array, array_);
Steve Block6ded16b2010-05-10 14:33:55 +01002339 target_array->set_length(Smi::FromInt(length_));
2340 return target_array;
2341 }
2342
2343 private:
2344 Handle<FixedArray> array_;
2345 int length_;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002346 bool has_non_smi_elements_;
Steve Block6ded16b2010-05-10 14:33:55 +01002347};
2348
2349
Steve Blocka7e24c12009-10-30 11:49:00 +00002350// Forward declarations.
Steve Block6ded16b2010-05-10 14:33:55 +01002351const int kStringBuilderConcatHelperLengthBits = 11;
2352const int kStringBuilderConcatHelperPositionBits = 19;
Steve Blocka7e24c12009-10-30 11:49:00 +00002353
2354template <typename schar>
2355static inline void StringBuilderConcatHelper(String*,
2356 schar*,
2357 FixedArray*,
2358 int);
2359
Steve Block6ded16b2010-05-10 14:33:55 +01002360typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2361 StringBuilderSubstringLength;
2362typedef BitField<int,
2363 kStringBuilderConcatHelperLengthBits,
2364 kStringBuilderConcatHelperPositionBits>
2365 StringBuilderSubstringPosition;
2366
Steve Blocka7e24c12009-10-30 11:49:00 +00002367
2368class ReplacementStringBuilder {
2369 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002370 ReplacementStringBuilder(Heap* heap,
2371 Handle<String> subject,
2372 int estimated_part_count)
2373 : heap_(heap),
2374 array_builder_(heap->isolate(), estimated_part_count),
Steve Block6ded16b2010-05-10 14:33:55 +01002375 subject_(subject),
Steve Blocka7e24c12009-10-30 11:49:00 +00002376 character_count_(0),
2377 is_ascii_(subject->IsAsciiRepresentation()) {
2378 // Require a non-zero initial size. Ensures that doubling the size to
2379 // extend the array will work.
2380 ASSERT(estimated_part_count > 0);
2381 }
2382
Steve Block6ded16b2010-05-10 14:33:55 +01002383 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2384 int from,
2385 int to) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002386 ASSERT(from >= 0);
2387 int length = to - from;
2388 ASSERT(length > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002389 if (StringBuilderSubstringLength::is_valid(length) &&
2390 StringBuilderSubstringPosition::is_valid(from)) {
2391 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2392 StringBuilderSubstringPosition::encode(from);
Steve Block6ded16b2010-05-10 14:33:55 +01002393 builder->Add(Smi::FromInt(encoded_slice));
Steve Blocka7e24c12009-10-30 11:49:00 +00002394 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002395 // Otherwise encode as two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01002396 builder->Add(Smi::FromInt(-length));
2397 builder->Add(Smi::FromInt(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00002398 }
Steve Block6ded16b2010-05-10 14:33:55 +01002399 }
2400
2401
2402 void EnsureCapacity(int elements) {
2403 array_builder_.EnsureCapacity(elements);
2404 }
2405
2406
2407 void AddSubjectSlice(int from, int to) {
2408 AddSubjectSlice(&array_builder_, from, to);
2409 IncrementCharacterCount(to - from);
Steve Blocka7e24c12009-10-30 11:49:00 +00002410 }
2411
2412
2413 void AddString(Handle<String> string) {
2414 int length = string->length();
2415 ASSERT(length > 0);
2416 AddElement(*string);
2417 if (!string->IsAsciiRepresentation()) {
2418 is_ascii_ = false;
2419 }
2420 IncrementCharacterCount(length);
2421 }
2422
2423
2424 Handle<String> ToString() {
Steve Block6ded16b2010-05-10 14:33:55 +01002425 if (array_builder_.length() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01002426 return heap_->isolate()->factory()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002427 }
2428
2429 Handle<String> joined_string;
2430 if (is_ascii_) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002431 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002432 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00002433 char* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002436 *array_builder_.array(),
2437 array_builder_.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002438 joined_string = Handle<String>::cast(seq);
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 } else {
2440 // Non-ASCII.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002441 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002442 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +00002443 uc16* char_buffer = seq->GetChars();
2444 StringBuilderConcatHelper(*subject_,
2445 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002446 *array_builder_.array(),
2447 array_builder_.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002448 joined_string = Handle<String>::cast(seq);
Steve Blocka7e24c12009-10-30 11:49:00 +00002449 }
2450 return joined_string;
2451 }
2452
2453
2454 void IncrementCharacterCount(int by) {
Leon Clarkee46be812010-01-19 14:06:41 +00002455 if (character_count_ > String::kMaxLength - by) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002456 V8::FatalProcessOutOfMemory("String.replace result too large.");
2457 }
2458 character_count_ += by;
2459 }
2460
Steve Block6ded16b2010-05-10 14:33:55 +01002461 Handle<JSArray> GetParts() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002462 return array_builder_.ToJSArray();
Steve Block6ded16b2010-05-10 14:33:55 +01002463 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002464
Steve Block6ded16b2010-05-10 14:33:55 +01002465 private:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002466 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2467 return heap_->isolate()->factory()->NewRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00002468 }
2469
2470
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002471 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2472 return heap_->isolate()->factory()->NewRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00002473 }
2474
2475
2476 void AddElement(Object* element) {
2477 ASSERT(element->IsSmi() || element->IsString());
Steve Block6ded16b2010-05-10 14:33:55 +01002478 ASSERT(array_builder_.capacity() > array_builder_.length());
2479 array_builder_.Add(element);
Steve Blocka7e24c12009-10-30 11:49:00 +00002480 }
2481
Steve Block44f0eee2011-05-26 01:26:41 +01002482 Heap* heap_;
Steve Block6ded16b2010-05-10 14:33:55 +01002483 FixedArrayBuilder array_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002484 Handle<String> subject_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002485 int character_count_;
2486 bool is_ascii_;
2487};
2488
2489
2490class CompiledReplacement {
2491 public:
2492 CompiledReplacement()
Ben Murdoch589d6972011-11-30 16:04:58 +00002493 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00002494
2495 void Compile(Handle<String> replacement,
2496 int capture_count,
2497 int subject_length);
2498
2499 void Apply(ReplacementStringBuilder* builder,
2500 int match_from,
2501 int match_to,
2502 Handle<JSArray> last_match_info);
2503
2504 // Number of distinct parts of the replacement pattern.
2505 int parts() {
2506 return parts_.length();
2507 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002508
Ben Murdoch589d6972011-11-30 16:04:58 +00002509 bool simple_hint() {
2510 return simple_hint_;
2511 }
2512
Steve Blocka7e24c12009-10-30 11:49:00 +00002513 private:
2514 enum PartType {
2515 SUBJECT_PREFIX = 1,
2516 SUBJECT_SUFFIX,
2517 SUBJECT_CAPTURE,
2518 REPLACEMENT_SUBSTRING,
2519 REPLACEMENT_STRING,
2520
2521 NUMBER_OF_PART_TYPES
2522 };
2523
2524 struct ReplacementPart {
2525 static inline ReplacementPart SubjectMatch() {
2526 return ReplacementPart(SUBJECT_CAPTURE, 0);
2527 }
2528 static inline ReplacementPart SubjectCapture(int capture_index) {
2529 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2530 }
2531 static inline ReplacementPart SubjectPrefix() {
2532 return ReplacementPart(SUBJECT_PREFIX, 0);
2533 }
2534 static inline ReplacementPart SubjectSuffix(int subject_length) {
2535 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2536 }
2537 static inline ReplacementPart ReplacementString() {
2538 return ReplacementPart(REPLACEMENT_STRING, 0);
2539 }
2540 static inline ReplacementPart ReplacementSubString(int from, int to) {
2541 ASSERT(from >= 0);
2542 ASSERT(to > from);
2543 return ReplacementPart(-from, to);
2544 }
2545
2546 // If tag <= 0 then it is the negation of a start index of a substring of
2547 // the replacement pattern, otherwise it's a value from PartType.
2548 ReplacementPart(int tag, int data)
2549 : tag(tag), data(data) {
2550 // Must be non-positive or a PartType value.
2551 ASSERT(tag < NUMBER_OF_PART_TYPES);
2552 }
2553 // Either a value of PartType or a non-positive number that is
2554 // the negation of an index into the replacement string.
2555 int tag;
2556 // The data value's interpretation depends on the value of tag:
2557 // tag == SUBJECT_PREFIX ||
2558 // tag == SUBJECT_SUFFIX: data is unused.
2559 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2560 // tag == REPLACEMENT_SUBSTRING ||
2561 // tag == REPLACEMENT_STRING: data is index into array of substrings
2562 // of the replacement string.
2563 // tag <= 0: Temporary representation of the substring of the replacement
2564 // string ranging over -tag .. data.
2565 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2566 // substring objects.
2567 int data;
2568 };
2569
2570 template<typename Char>
Ben Murdoch589d6972011-11-30 16:04:58 +00002571 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
Steve Blocka7e24c12009-10-30 11:49:00 +00002572 Vector<Char> characters,
2573 int capture_count,
2574 int subject_length) {
2575 int length = characters.length();
2576 int last = 0;
2577 for (int i = 0; i < length; i++) {
2578 Char c = characters[i];
2579 if (c == '$') {
2580 int next_index = i + 1;
2581 if (next_index == length) { // No next character!
2582 break;
2583 }
2584 Char c2 = characters[next_index];
2585 switch (c2) {
2586 case '$':
2587 if (i > last) {
2588 // There is a substring before. Include the first "$".
2589 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2590 last = next_index + 1; // Continue after the second "$".
2591 } else {
2592 // Let the next substring start with the second "$".
2593 last = next_index;
2594 }
2595 i = next_index;
2596 break;
2597 case '`':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectPrefix());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '\'':
2606 if (i > last) {
2607 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2608 }
2609 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2610 i = next_index;
2611 last = i + 1;
2612 break;
2613 case '&':
2614 if (i > last) {
2615 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2616 }
2617 parts->Add(ReplacementPart::SubjectMatch());
2618 i = next_index;
2619 last = i + 1;
2620 break;
2621 case '0':
2622 case '1':
2623 case '2':
2624 case '3':
2625 case '4':
2626 case '5':
2627 case '6':
2628 case '7':
2629 case '8':
2630 case '9': {
2631 int capture_ref = c2 - '0';
2632 if (capture_ref > capture_count) {
2633 i = next_index;
2634 continue;
2635 }
2636 int second_digit_index = next_index + 1;
2637 if (second_digit_index < length) {
2638 // Peek ahead to see if we have two digits.
2639 Char c3 = characters[second_digit_index];
2640 if ('0' <= c3 && c3 <= '9') { // Double digits.
2641 int double_digit_ref = capture_ref * 10 + c3 - '0';
2642 if (double_digit_ref <= capture_count) {
2643 next_index = second_digit_index;
2644 capture_ref = double_digit_ref;
2645 }
2646 }
2647 }
2648 if (capture_ref > 0) {
2649 if (i > last) {
2650 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2651 }
2652 ASSERT(capture_ref <= capture_count);
2653 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2654 last = next_index + 1;
2655 }
2656 i = next_index;
2657 break;
2658 }
2659 default:
2660 i = next_index;
2661 break;
2662 }
2663 }
2664 }
2665 if (length > last) {
2666 if (last == 0) {
2667 parts->Add(ReplacementPart::ReplacementString());
Ben Murdoch589d6972011-11-30 16:04:58 +00002668 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002669 } else {
2670 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2671 }
2672 }
Ben Murdoch589d6972011-11-30 16:04:58 +00002673 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00002674 }
2675
2676 ZoneList<ReplacementPart> parts_;
2677 ZoneList<Handle<String> > replacement_substrings_;
Ben Murdoch589d6972011-11-30 16:04:58 +00002678 bool simple_hint_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002679};
2680
2681
2682void CompiledReplacement::Compile(Handle<String> replacement,
2683 int capture_count,
2684 int subject_length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002685 {
Steve Blocka7e24c12009-10-30 11:49:00 +00002686 AssertNoAllocation no_alloc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002687 String::FlatContent content = replacement->GetFlatContent();
2688 ASSERT(content.IsFlat());
2689 if (content.IsAscii()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002690 simple_hint_ = ParseReplacementPattern(&parts_,
2691 content.ToAsciiVector(),
2692 capture_count,
2693 subject_length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002694 } else {
2695 ASSERT(content.IsTwoByte());
Ben Murdoch589d6972011-11-30 16:04:58 +00002696 simple_hint_ = ParseReplacementPattern(&parts_,
2697 content.ToUC16Vector(),
2698 capture_count,
2699 subject_length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002700 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002701 }
Steve Block44f0eee2011-05-26 01:26:41 +01002702 Isolate* isolate = replacement->GetIsolate();
Steve Blockd0582a62009-12-15 09:54:21 +00002703 // Find substrings of replacement string and create them as String objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002704 int substring_index = 0;
2705 for (int i = 0, n = parts_.length(); i < n; i++) {
2706 int tag = parts_[i].tag;
2707 if (tag <= 0) { // A replacement string slice.
2708 int from = -tag;
2709 int to = parts_[i].data;
Steve Block44f0eee2011-05-26 01:26:41 +01002710 replacement_substrings_.Add(
2711 isolate->factory()->NewSubString(replacement, from, to));
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 parts_[i].tag = REPLACEMENT_SUBSTRING;
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 } else if (tag == REPLACEMENT_STRING) {
2716 replacement_substrings_.Add(replacement);
2717 parts_[i].data = substring_index;
2718 substring_index++;
2719 }
2720 }
2721}
2722
2723
2724void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2725 int match_from,
2726 int match_to,
2727 Handle<JSArray> last_match_info) {
2728 for (int i = 0, n = parts_.length(); i < n; i++) {
2729 ReplacementPart part = parts_[i];
2730 switch (part.tag) {
2731 case SUBJECT_PREFIX:
2732 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2733 break;
2734 case SUBJECT_SUFFIX: {
2735 int subject_length = part.data;
2736 if (match_to < subject_length) {
2737 builder->AddSubjectSlice(match_to, subject_length);
2738 }
2739 break;
2740 }
2741 case SUBJECT_CAPTURE: {
2742 int capture = part.data;
2743 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2744 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2745 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2746 if (from >= 0 && to > from) {
2747 builder->AddSubjectSlice(from, to);
2748 }
2749 break;
2750 }
2751 case REPLACEMENT_SUBSTRING:
2752 case REPLACEMENT_STRING:
2753 builder->AddString(replacement_substrings_[part.data]);
2754 break;
2755 default:
2756 UNREACHABLE();
2757 }
2758 }
2759}
2760
2761
Ben Murdoch589d6972011-11-30 16:04:58 +00002762void FindAsciiStringIndices(Vector<const char> subject,
2763 char pattern,
2764 ZoneList<int>* indices,
2765 unsigned int limit) {
2766 ASSERT(limit > 0);
2767 // Collect indices of pattern in subject using memchr.
2768 // Stop after finding at most limit values.
2769 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2770 const char* subject_end = subject_start + subject.length();
2771 const char* pos = subject_start;
2772 while (limit > 0) {
2773 pos = reinterpret_cast<const char*>(
2774 memchr(pos, pattern, subject_end - pos));
2775 if (pos == NULL) return;
2776 indices->Add(static_cast<int>(pos - subject_start));
2777 pos++;
2778 limit--;
2779 }
2780}
2781
2782
2783template <typename SubjectChar, typename PatternChar>
2784void FindStringIndices(Isolate* isolate,
2785 Vector<const SubjectChar> subject,
2786 Vector<const PatternChar> pattern,
2787 ZoneList<int>* indices,
2788 unsigned int limit) {
2789 ASSERT(limit > 0);
2790 // Collect indices of pattern in subject.
2791 // Stop after finding at most limit values.
2792 int pattern_length = pattern.length();
2793 int index = 0;
2794 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2795 while (limit > 0) {
2796 index = search.Search(subject, index);
2797 if (index < 0) return;
2798 indices->Add(index);
2799 index += pattern_length;
2800 limit--;
2801 }
2802}
2803
2804
2805void FindStringIndicesDispatch(Isolate* isolate,
2806 String* subject,
2807 String* pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 {
2811 AssertNoAllocation no_gc;
2812 String::FlatContent subject_content = subject->GetFlatContent();
2813 String::FlatContent pattern_content = pattern->GetFlatContent();
2814 ASSERT(subject_content.IsFlat());
2815 ASSERT(pattern_content.IsFlat());
2816 if (subject_content.IsAscii()) {
2817 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2818 if (pattern_content.IsAscii()) {
2819 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2820 if (pattern_vector.length() == 1) {
2821 FindAsciiStringIndices(subject_vector,
2822 pattern_vector[0],
2823 indices,
2824 limit);
2825 } else {
2826 FindStringIndices(isolate,
2827 subject_vector,
2828 pattern_vector,
2829 indices,
2830 limit);
2831 }
2832 } else {
2833 FindStringIndices(isolate,
2834 subject_vector,
2835 pattern_content.ToUC16Vector(),
2836 indices,
2837 limit);
2838 }
2839 } else {
2840 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002841 if (pattern_content.IsAscii()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002842 FindStringIndices(isolate,
2843 subject_vector,
2844 pattern_content.ToAsciiVector(),
2845 indices,
2846 limit);
2847 } else {
2848 FindStringIndices(isolate,
2849 subject_vector,
2850 pattern_content.ToUC16Vector(),
2851 indices,
2852 limit);
2853 }
2854 }
2855 }
2856}
2857
2858
2859template<typename ResultSeqString>
2860MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2861 Isolate* isolate,
2862 Handle<String> subject,
2863 Handle<JSRegExp> pattern_regexp,
2864 Handle<String> replacement) {
2865 ASSERT(subject->IsFlat());
2866 ASSERT(replacement->IsFlat());
2867
2868 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2869 ZoneList<int> indices(8);
2870 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2871 String* pattern =
2872 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2873 int subject_len = subject->length();
2874 int pattern_len = pattern->length();
2875 int replacement_len = replacement->length();
2876
2877 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2878
2879 int matches = indices.length();
2880 if (matches == 0) return *subject;
2881
2882 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2883 int subject_pos = 0;
2884 int result_pos = 0;
2885
2886 Handle<ResultSeqString> result;
2887 if (ResultSeqString::kHasAsciiEncoding) {
2888 result = Handle<ResultSeqString>::cast(
2889 isolate->factory()->NewRawAsciiString(result_len));
2890 } else {
2891 result = Handle<ResultSeqString>::cast(
2892 isolate->factory()->NewRawTwoByteString(result_len));
2893 }
2894
2895 for (int i = 0; i < matches; i++) {
2896 // Copy non-matched subject content.
2897 if (subject_pos < indices.at(i)) {
2898 String::WriteToFlat(*subject,
2899 result->GetChars() + result_pos,
2900 subject_pos,
2901 indices.at(i));
2902 result_pos += indices.at(i) - subject_pos;
2903 }
2904
2905 // Replace match.
2906 if (replacement_len > 0) {
2907 String::WriteToFlat(*replacement,
2908 result->GetChars() + result_pos,
2909 0,
2910 replacement_len);
2911 result_pos += replacement_len;
2912 }
2913
2914 subject_pos = indices.at(i) + pattern_len;
2915 }
2916 // Add remaining subject content at the end.
2917 if (subject_pos < subject_len) {
2918 String::WriteToFlat(*subject,
2919 result->GetChars() + result_pos,
2920 subject_pos,
2921 subject_len);
2922 }
2923 return *result;
2924}
2925
Steve Blocka7e24c12009-10-30 11:49:00 +00002926
John Reck59135872010-11-02 12:39:01 -07002927MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
Steve Block44f0eee2011-05-26 01:26:41 +01002928 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07002929 String* subject,
2930 JSRegExp* regexp,
2931 String* replacement,
2932 JSArray* last_match_info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002933 ASSERT(subject->IsFlat());
2934 ASSERT(replacement->IsFlat());
2935
Steve Block44f0eee2011-05-26 01:26:41 +01002936 HandleScope handles(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002937
2938 int length = subject->length();
2939 Handle<String> subject_handle(subject);
2940 Handle<JSRegExp> regexp_handle(regexp);
2941 Handle<String> replacement_handle(replacement);
2942 Handle<JSArray> last_match_info_handle(last_match_info);
2943 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2944 subject_handle,
2945 0,
2946 last_match_info_handle);
2947 if (match.is_null()) {
2948 return Failure::Exception();
2949 }
2950 if (match->IsNull()) {
2951 return *subject_handle;
2952 }
2953
2954 int capture_count = regexp_handle->CaptureCount();
2955
2956 // CompiledReplacement uses zone allocation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002957 ZoneScope zone(isolate, DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +00002958 CompiledReplacement compiled_replacement;
2959 compiled_replacement.Compile(replacement_handle,
2960 capture_count,
2961 length);
2962
2963 bool is_global = regexp_handle->GetFlags().is_global();
2964
Ben Murdoch589d6972011-11-30 16:04:58 +00002965 // Shortcut for simple non-regexp global replacements
2966 if (is_global &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002967 regexp_handle->TypeTag() == JSRegExp::ATOM &&
Ben Murdoch589d6972011-11-30 16:04:58 +00002968 compiled_replacement.simple_hint()) {
2969 if (subject_handle->HasOnlyAsciiChars() &&
2970 replacement_handle->HasOnlyAsciiChars()) {
2971 return StringReplaceStringWithString<SeqAsciiString>(
2972 isolate, subject_handle, regexp_handle, replacement_handle);
2973 } else {
2974 return StringReplaceStringWithString<SeqTwoByteString>(
2975 isolate, subject_handle, regexp_handle, replacement_handle);
2976 }
2977 }
2978
Steve Blocka7e24c12009-10-30 11:49:00 +00002979 // Guessing the number of parts that the final result string is built
2980 // from. Global regexps can match any number of times, so we guess
2981 // conservatively.
2982 int expected_parts =
2983 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002984 ReplacementStringBuilder builder(isolate->heap(),
2985 subject_handle,
2986 expected_parts);
Steve Blocka7e24c12009-10-30 11:49:00 +00002987
2988 // Index of end of last match.
2989 int prev = 0;
2990
Steve Blockd0582a62009-12-15 09:54:21 +00002991 // Number of parts added by compiled replacement plus preceeding
2992 // string and possibly suffix after last match. It is possible for
2993 // all components to use two elements when encoded as two smis.
2994 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002995 bool matched = true;
2996 do {
2997 ASSERT(last_match_info_handle->HasFastElements());
2998 // Increase the capacity of the builder before entering local handle-scope,
2999 // so its internal buffer can safely allocate a new handle if it grows.
3000 builder.EnsureCapacity(parts_added_per_loop);
3001
Steve Block44f0eee2011-05-26 01:26:41 +01003002 HandleScope loop_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003003 int start, end;
3004 {
3005 AssertNoAllocation match_info_array_is_not_in_a_handle;
3006 FixedArray* match_info_array =
3007 FixedArray::cast(last_match_info_handle->elements());
3008
3009 ASSERT_EQ(capture_count * 2 + 2,
3010 RegExpImpl::GetLastCaptureCount(match_info_array));
3011 start = RegExpImpl::GetCapture(match_info_array, 0);
3012 end = RegExpImpl::GetCapture(match_info_array, 1);
3013 }
3014
3015 if (prev < start) {
3016 builder.AddSubjectSlice(prev, start);
3017 }
3018 compiled_replacement.Apply(&builder,
3019 start,
3020 end,
3021 last_match_info_handle);
3022 prev = end;
3023
3024 // Only continue checking for global regexps.
3025 if (!is_global) break;
3026
3027 // Continue from where the match ended, unless it was an empty match.
3028 int next = end;
3029 if (start == end) {
3030 next = end + 1;
3031 if (next > length) break;
3032 }
3033
3034 match = RegExpImpl::Exec(regexp_handle,
3035 subject_handle,
3036 next,
3037 last_match_info_handle);
3038 if (match.is_null()) {
3039 return Failure::Exception();
3040 }
3041 matched = !match->IsNull();
3042 } while (matched);
3043
3044 if (prev < length) {
3045 builder.AddSubjectSlice(prev, length);
3046 }
3047
3048 return *(builder.ToString());
3049}
3050
3051
Leon Clarkeac952652010-07-15 11:15:24 +01003052template <typename ResultSeqString>
John Reck59135872010-11-02 12:39:01 -07003053MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
Steve Block44f0eee2011-05-26 01:26:41 +01003054 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07003055 String* subject,
3056 JSRegExp* regexp,
3057 JSArray* last_match_info) {
Leon Clarkeac952652010-07-15 11:15:24 +01003058 ASSERT(subject->IsFlat());
3059
Steve Block44f0eee2011-05-26 01:26:41 +01003060 HandleScope handles(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01003061
3062 Handle<String> subject_handle(subject);
3063 Handle<JSRegExp> regexp_handle(regexp);
Ben Murdoch589d6972011-11-30 16:04:58 +00003064
3065 // Shortcut for simple non-regexp global replacements
3066 if (regexp_handle->GetFlags().is_global() &&
3067 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3068 Handle<String> empty_string_handle(HEAP->empty_string());
3069 if (subject_handle->HasOnlyAsciiChars()) {
3070 return StringReplaceStringWithString<SeqAsciiString>(
3071 isolate, subject_handle, regexp_handle, empty_string_handle);
3072 } else {
3073 return StringReplaceStringWithString<SeqTwoByteString>(
3074 isolate, subject_handle, regexp_handle, empty_string_handle);
3075 }
3076 }
3077
Leon Clarkeac952652010-07-15 11:15:24 +01003078 Handle<JSArray> last_match_info_handle(last_match_info);
3079 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3080 subject_handle,
3081 0,
3082 last_match_info_handle);
3083 if (match.is_null()) return Failure::Exception();
3084 if (match->IsNull()) return *subject_handle;
3085
3086 ASSERT(last_match_info_handle->HasFastElements());
3087
Leon Clarkeac952652010-07-15 11:15:24 +01003088 int start, end;
3089 {
3090 AssertNoAllocation match_info_array_is_not_in_a_handle;
3091 FixedArray* match_info_array =
3092 FixedArray::cast(last_match_info_handle->elements());
3093
3094 start = RegExpImpl::GetCapture(match_info_array, 0);
3095 end = RegExpImpl::GetCapture(match_info_array, 1);
3096 }
3097
Steve Block053d10c2011-06-13 19:13:29 +01003098 int length = subject_handle->length();
Leon Clarkeac952652010-07-15 11:15:24 +01003099 int new_length = length - (end - start);
3100 if (new_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003101 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01003102 }
3103 Handle<ResultSeqString> answer;
3104 if (ResultSeqString::kHasAsciiEncoding) {
Steve Block44f0eee2011-05-26 01:26:41 +01003105 answer = Handle<ResultSeqString>::cast(
3106 isolate->factory()->NewRawAsciiString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01003107 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003108 answer = Handle<ResultSeqString>::cast(
3109 isolate->factory()->NewRawTwoByteString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01003110 }
3111
3112 // If the regexp isn't global, only match once.
3113 if (!regexp_handle->GetFlags().is_global()) {
3114 if (start > 0) {
3115 String::WriteToFlat(*subject_handle,
3116 answer->GetChars(),
3117 0,
3118 start);
3119 }
3120 if (end < length) {
3121 String::WriteToFlat(*subject_handle,
3122 answer->GetChars() + start,
3123 end,
3124 length);
3125 }
3126 return *answer;
3127 }
3128
3129 int prev = 0; // Index of end of last match.
3130 int next = 0; // Start of next search (prev unless last match was empty).
3131 int position = 0;
3132
3133 do {
3134 if (prev < start) {
3135 // Add substring subject[prev;start] to answer string.
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars() + position,
3138 prev,
3139 start);
3140 position += start - prev;
3141 }
3142 prev = end;
3143 next = end;
3144 // Continue from where the match ended, unless it was an empty match.
3145 if (start == end) {
3146 next++;
3147 if (next > length) break;
3148 }
3149 match = RegExpImpl::Exec(regexp_handle,
3150 subject_handle,
3151 next,
3152 last_match_info_handle);
3153 if (match.is_null()) return Failure::Exception();
3154 if (match->IsNull()) break;
3155
3156 ASSERT(last_match_info_handle->HasFastElements());
Steve Block44f0eee2011-05-26 01:26:41 +01003157 HandleScope loop_scope(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01003158 {
3159 AssertNoAllocation match_info_array_is_not_in_a_handle;
3160 FixedArray* match_info_array =
3161 FixedArray::cast(last_match_info_handle->elements());
3162 start = RegExpImpl::GetCapture(match_info_array, 0);
3163 end = RegExpImpl::GetCapture(match_info_array, 1);
3164 }
3165 } while (true);
3166
3167 if (prev < length) {
3168 // Add substring subject[prev;length] to answer string.
3169 String::WriteToFlat(*subject_handle,
3170 answer->GetChars() + position,
3171 prev,
3172 length);
3173 position += length - prev;
3174 }
3175
3176 if (position == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003177 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01003178 }
3179
3180 // Shorten string and fill
3181 int string_size = ResultSeqString::SizeFor(position);
3182 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3183 int delta = allocated_string_size - string_size;
3184
3185 answer->set_length(position);
3186 if (delta == 0) return *answer;
3187
3188 Address end_of_string = answer->address() + string_size;
Steve Block44f0eee2011-05-26 01:26:41 +01003189 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003190 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003191 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003192 }
Leon Clarkeac952652010-07-15 11:15:24 +01003193
3194 return *answer;
3195}
3196
3197
Ben Murdoch8b112d22011-06-08 16:22:53 +01003198RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003199 ASSERT(args.length() == 4);
3200
3201 CONVERT_CHECKED(String, subject, args[0]);
3202 if (!subject->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07003203 Object* flat_subject;
3204 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3205 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3206 return maybe_flat_subject;
3207 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003208 }
3209 subject = String::cast(flat_subject);
3210 }
3211
3212 CONVERT_CHECKED(String, replacement, args[2]);
3213 if (!replacement->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07003214 Object* flat_replacement;
3215 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3216 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3217 return maybe_flat_replacement;
3218 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003219 }
3220 replacement = String::cast(flat_replacement);
3221 }
3222
3223 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3224 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3225
3226 ASSERT(last_match_info->HasFastElements());
3227
Leon Clarkeac952652010-07-15 11:15:24 +01003228 if (replacement->length() == 0) {
3229 if (subject->HasOnlyAsciiChars()) {
3230 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
Steve Block44f0eee2011-05-26 01:26:41 +01003231 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01003232 } else {
3233 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
Steve Block44f0eee2011-05-26 01:26:41 +01003234 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01003235 }
3236 }
3237
Steve Block44f0eee2011-05-26 01:26:41 +01003238 return StringReplaceRegExpWithString(isolate,
3239 subject,
Steve Blocka7e24c12009-10-30 11:49:00 +00003240 regexp,
3241 replacement,
3242 last_match_info);
3243}
3244
3245
Ben Murdochc7cc0282012-03-05 14:35:55 +00003246Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3247 Handle<String> subject,
3248 Handle<String> search,
3249 Handle<String> replace,
3250 bool* found,
3251 int recursion_limit) {
3252 if (recursion_limit == 0) return Handle<String>::null();
3253 if (subject->IsConsString()) {
3254 ConsString* cons = ConsString::cast(*subject);
3255 Handle<String> first = Handle<String>(cons->first());
3256 Handle<String> second = Handle<String>(cons->second());
3257 Handle<String> new_first =
3258 StringReplaceOneCharWithString(isolate,
3259 first,
3260 search,
3261 replace,
3262 found,
3263 recursion_limit - 1);
3264 if (*found) return isolate->factory()->NewConsString(new_first, second);
3265 if (new_first.is_null()) return new_first;
3266
3267 Handle<String> new_second =
3268 StringReplaceOneCharWithString(isolate,
3269 second,
3270 search,
3271 replace,
3272 found,
3273 recursion_limit - 1);
3274 if (*found) return isolate->factory()->NewConsString(first, new_second);
3275 if (new_second.is_null()) return new_second;
3276
3277 return subject;
3278 } else {
3279 int index = StringMatch(isolate, subject, search, 0);
3280 if (index == -1) return subject;
3281 *found = true;
3282 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3283 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3284 Handle<String> second =
3285 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3286 return isolate->factory()->NewConsString(cons1, second);
3287 }
3288}
3289
3290
3291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3292 ASSERT(args.length() == 3);
3293 HandleScope scope(isolate);
3294 CONVERT_ARG_CHECKED(String, subject, 0);
3295 CONVERT_ARG_CHECKED(String, search, 1);
3296 CONVERT_ARG_CHECKED(String, replace, 2);
3297
3298 // If the cons string tree is too deep, we simply abort the recursion and
3299 // retry with a flattened subject string.
3300 const int kRecursionLimit = 0x1000;
3301 bool found = false;
3302 Handle<String> result =
3303 Runtime::StringReplaceOneCharWithString(isolate,
3304 subject,
3305 search,
3306 replace,
3307 &found,
3308 kRecursionLimit);
3309 if (!result.is_null()) return *result;
3310 return *Runtime::StringReplaceOneCharWithString(isolate,
3311 FlattenGetString(subject),
3312 search,
3313 replace,
3314 &found,
3315 kRecursionLimit);
3316}
3317
3318
Steve Blocka7e24c12009-10-30 11:49:00 +00003319// Perform string match of pattern on subject, starting at start index.
3320// Caller must ensure that 0 <= start_index <= sub->length(),
Ben Murdochb0fe1622011-05-05 13:52:32 +01003321// and should check that pat->length() + start_index <= sub->length().
Steve Block44f0eee2011-05-26 01:26:41 +01003322int Runtime::StringMatch(Isolate* isolate,
3323 Handle<String> sub,
Steve Blocka7e24c12009-10-30 11:49:00 +00003324 Handle<String> pat,
3325 int start_index) {
3326 ASSERT(0 <= start_index);
3327 ASSERT(start_index <= sub->length());
3328
3329 int pattern_length = pat->length();
3330 if (pattern_length == 0) return start_index;
3331
3332 int subject_length = sub->length();
3333 if (start_index + pattern_length > subject_length) return -1;
3334
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003335 if (!sub->IsFlat()) FlattenString(sub);
3336 if (!pat->IsFlat()) FlattenString(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +00003337
3338 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
Steve Block8defd9f2010-07-08 12:39:36 +01003339 // Extract flattened substrings of cons strings before determining asciiness.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003340 String::FlatContent seq_sub = sub->GetFlatContent();
3341 String::FlatContent seq_pat = pat->GetFlatContent();
Steve Block8defd9f2010-07-08 12:39:36 +01003342
Steve Blocka7e24c12009-10-30 11:49:00 +00003343 // dispatch on type of strings
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003344 if (seq_pat.IsAscii()) {
3345 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3346 if (seq_sub.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003347 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003348 seq_sub.ToAsciiVector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003349 pat_vector,
3350 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003351 }
Steve Block44f0eee2011-05-26 01:26:41 +01003352 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003353 seq_sub.ToUC16Vector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003354 pat_vector,
3355 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003356 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003357 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3358 if (seq_sub.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003359 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003360 seq_sub.ToAsciiVector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003361 pat_vector,
3362 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003363 }
Steve Block44f0eee2011-05-26 01:26:41 +01003364 return SearchString(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003365 seq_sub.ToUC16Vector(),
Steve Block44f0eee2011-05-26 01:26:41 +01003366 pat_vector,
3367 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003368}
3369
3370
Ben Murdoch8b112d22011-06-08 16:22:53 +01003371RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01003372 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00003373 ASSERT(args.length() == 3);
3374
3375 CONVERT_ARG_CHECKED(String, sub, 0);
3376 CONVERT_ARG_CHECKED(String, pat, 1);
3377
3378 Object* index = args[2];
3379 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003380 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003381
3382 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
Steve Block44f0eee2011-05-26 01:26:41 +01003383 int position =
3384 Runtime::StringMatch(isolate, sub, pat, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003385 return Smi::FromInt(position);
3386}
3387
3388
Andrei Popescu402d9372010-02-26 13:31:12 +00003389template <typename schar, typename pchar>
Steve Block59151502010-09-22 15:07:15 +01003390static int StringMatchBackwards(Vector<const schar> subject,
3391 Vector<const pchar> pattern,
Andrei Popescu402d9372010-02-26 13:31:12 +00003392 int idx) {
Steve Block59151502010-09-22 15:07:15 +01003393 int pattern_length = pattern.length();
3394 ASSERT(pattern_length >= 1);
3395 ASSERT(idx + pattern_length <= subject.length());
Andrei Popescu402d9372010-02-26 13:31:12 +00003396
3397 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
Steve Block59151502010-09-22 15:07:15 +01003398 for (int i = 0; i < pattern_length; i++) {
3399 uc16 c = pattern[i];
Andrei Popescu402d9372010-02-26 13:31:12 +00003400 if (c > String::kMaxAsciiCharCode) {
3401 return -1;
3402 }
3403 }
3404 }
3405
Steve Block59151502010-09-22 15:07:15 +01003406 pchar pattern_first_char = pattern[0];
Andrei Popescu402d9372010-02-26 13:31:12 +00003407 for (int i = idx; i >= 0; i--) {
Steve Block59151502010-09-22 15:07:15 +01003408 if (subject[i] != pattern_first_char) continue;
Andrei Popescu402d9372010-02-26 13:31:12 +00003409 int j = 1;
Steve Block59151502010-09-22 15:07:15 +01003410 while (j < pattern_length) {
3411 if (pattern[j] != subject[i+j]) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003412 break;
3413 }
3414 j++;
3415 }
Steve Block59151502010-09-22 15:07:15 +01003416 if (j == pattern_length) {
Andrei Popescu402d9372010-02-26 13:31:12 +00003417 return i;
3418 }
3419 }
3420 return -1;
3421}
3422
Ben Murdoch8b112d22011-06-08 16:22:53 +01003423RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01003424 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00003425 ASSERT(args.length() == 3);
3426
Andrei Popescu402d9372010-02-26 13:31:12 +00003427 CONVERT_ARG_CHECKED(String, sub, 0);
3428 CONVERT_ARG_CHECKED(String, pat, 1);
3429
Steve Blocka7e24c12009-10-30 11:49:00 +00003430 Object* index = args[2];
Steve Blocka7e24c12009-10-30 11:49:00 +00003431 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003432 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00003433
Andrei Popescu402d9372010-02-26 13:31:12 +00003434 uint32_t pat_length = pat->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00003435 uint32_t sub_length = sub->length();
3436
Andrei Popescu402d9372010-02-26 13:31:12 +00003437 if (start_index + pat_length > sub_length) {
3438 start_index = sub_length - pat_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00003439 }
3440
Andrei Popescu402d9372010-02-26 13:31:12 +00003441 if (pat_length == 0) {
3442 return Smi::FromInt(start_index);
3443 }
3444
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003445 if (!sub->IsFlat()) FlattenString(sub);
3446 if (!pat->IsFlat()) FlattenString(pat);
Andrei Popescu402d9372010-02-26 13:31:12 +00003447
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003448 int position = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00003449 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3450
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003451 String::FlatContent sub_content = sub->GetFlatContent();
3452 String::FlatContent pat_content = pat->GetFlatContent();
Andrei Popescu402d9372010-02-26 13:31:12 +00003453
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003454 if (pat_content.IsAscii()) {
3455 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3456 if (sub_content.IsAscii()) {
3457 position = StringMatchBackwards(sub_content.ToAsciiVector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003458 pat_vector,
3459 start_index);
3460 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003461 position = StringMatchBackwards(sub_content.ToUC16Vector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003462 pat_vector,
3463 start_index);
3464 }
3465 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003466 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3467 if (sub_content.IsAscii()) {
3468 position = StringMatchBackwards(sub_content.ToAsciiVector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003469 pat_vector,
3470 start_index);
3471 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003472 position = StringMatchBackwards(sub_content.ToUC16Vector(),
Andrei Popescu402d9372010-02-26 13:31:12 +00003473 pat_vector,
3474 start_index);
3475 }
3476 }
3477
3478 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +00003479}
3480
3481
Ben Murdoch8b112d22011-06-08 16:22:53 +01003482RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003483 NoHandleAllocation ha;
3484 ASSERT(args.length() == 2);
3485
3486 CONVERT_CHECKED(String, str1, args[0]);
3487 CONVERT_CHECKED(String, str2, args[1]);
3488
3489 if (str1 == str2) return Smi::FromInt(0); // Equal.
3490 int str1_length = str1->length();
3491 int str2_length = str2->length();
3492
3493 // Decide trivial cases without flattening.
3494 if (str1_length == 0) {
3495 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3496 return Smi::FromInt(-str2_length);
3497 } else {
3498 if (str2_length == 0) return Smi::FromInt(str1_length);
3499 }
3500
3501 int end = str1_length < str2_length ? str1_length : str2_length;
3502
3503 // No need to flatten if we are going to find the answer on the first
3504 // character. At this point we know there is at least one character
3505 // in each string, due to the trivial case handling above.
3506 int d = str1->Get(0) - str2->Get(0);
3507 if (d != 0) return Smi::FromInt(d);
3508
Steve Block6ded16b2010-05-10 14:33:55 +01003509 str1->TryFlatten();
3510 str2->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003511
Steve Block44f0eee2011-05-26 01:26:41 +01003512 StringInputBuffer& buf1 =
3513 *isolate->runtime_state()->string_locale_compare_buf1();
3514 StringInputBuffer& buf2 =
3515 *isolate->runtime_state()->string_locale_compare_buf2();
Steve Blocka7e24c12009-10-30 11:49:00 +00003516
3517 buf1.Reset(str1);
3518 buf2.Reset(str2);
3519
3520 for (int i = 0; i < end; i++) {
3521 uint16_t char1 = buf1.GetNext();
3522 uint16_t char2 = buf2.GetNext();
3523 if (char1 != char2) return Smi::FromInt(char1 - char2);
3524 }
3525
3526 return Smi::FromInt(str1_length - str2_length);
3527}
3528
3529
Ben Murdoch8b112d22011-06-08 16:22:53 +01003530RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003531 NoHandleAllocation ha;
3532 ASSERT(args.length() == 3);
3533
3534 CONVERT_CHECKED(String, value, args[0]);
Steve Blockd0582a62009-12-15 09:54:21 +00003535 int start, end;
3536 // We have a fast integer-only case here to avoid a conversion to double in
3537 // the common case where from and to are Smis.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003538 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3539 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3540 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3541 start = from_number;
3542 end = to_number;
Steve Blockd0582a62009-12-15 09:54:21 +00003543 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003544 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3545 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
Steve Blockd0582a62009-12-15 09:54:21 +00003546 start = FastD2I(from_number);
3547 end = FastD2I(to_number);
3548 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003549 RUNTIME_ASSERT(end >= start);
3550 RUNTIME_ASSERT(start >= 0);
3551 RUNTIME_ASSERT(end <= value->length());
Steve Block44f0eee2011-05-26 01:26:41 +01003552 isolate->counters()->sub_string_runtime()->Increment();
Steve Blockd0582a62009-12-15 09:54:21 +00003553 return value->SubString(start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +00003554}
3555
3556
Ben Murdoch8b112d22011-06-08 16:22:53 +01003557RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003558 ASSERT_EQ(3, args.length());
3559
3560 CONVERT_ARG_CHECKED(String, subject, 0);
3561 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3562 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3563 HandleScope handles;
3564
3565 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3566
3567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 if (match->IsNull()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003571 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003572 }
3573 int length = subject->length();
3574
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003575 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +00003576 ZoneList<int> offsets(8);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003577 int start;
3578 int end;
Steve Blocka7e24c12009-10-30 11:49:00 +00003579 do {
Steve Blocka7e24c12009-10-30 11:49:00 +00003580 {
3581 AssertNoAllocation no_alloc;
3582 FixedArray* elements = FixedArray::cast(regexp_info->elements());
3583 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3584 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3585 }
3586 offsets.Add(start);
3587 offsets.Add(end);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003588 if (start == end) if (++end > length) break;
3589 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00003590 if (match.is_null()) {
3591 return Failure::Exception();
3592 }
3593 } while (!match->IsNull());
3594 int matches = offsets.length() / 2;
Steve Block44f0eee2011-05-26 01:26:41 +01003595 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003596 Handle<String> substring = isolate->factory()->
3597 NewSubString(subject, offsets.at(0), offsets.at(1));
3598 elements->set(0, *substring);
3599 for (int i = 1; i < matches ; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003600 int from = offsets.at(i * 2);
3601 int to = offsets.at(i * 2 + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003602 Handle<String> substring = isolate->factory()->
3603 NewProperSubString(subject, from, to);
3604 elements->set(i, *substring);
Steve Blocka7e24c12009-10-30 11:49:00 +00003605 }
Steve Block44f0eee2011-05-26 01:26:41 +01003606 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003607 result->set_length(Smi::FromInt(matches));
3608 return *result;
3609}
3610
3611
Steve Block6ded16b2010-05-10 14:33:55 +01003612// Two smis before and after the match, for very long strings.
3613const int kMaxBuilderEntriesPerRegExpMatch = 5;
3614
3615
3616static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3617 Handle<JSArray> last_match_info,
3618 int match_start,
3619 int match_end) {
3620 // Fill last_match_info with a single capture.
3621 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3622 AssertNoAllocation no_gc;
3623 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3624 RegExpImpl::SetLastCaptureCount(elements, 2);
3625 RegExpImpl::SetLastInput(elements, *subject);
3626 RegExpImpl::SetLastSubject(elements, *subject);
3627 RegExpImpl::SetCapture(elements, 0, match_start);
3628 RegExpImpl::SetCapture(elements, 1, match_end);
3629}
3630
3631
Ben Murdochf87a2032010-10-22 12:50:53 +01003632template <typename SubjectChar, typename PatternChar>
Steve Block44f0eee2011-05-26 01:26:41 +01003633static bool SearchStringMultiple(Isolate* isolate,
3634 Vector<const SubjectChar> subject,
Ben Murdochf87a2032010-10-22 12:50:53 +01003635 Vector<const PatternChar> pattern,
3636 String* pattern_string,
Steve Block6ded16b2010-05-10 14:33:55 +01003637 FixedArrayBuilder* builder,
3638 int* match_pos) {
3639 int pos = *match_pos;
3640 int subject_length = subject.length();
Ben Murdochf87a2032010-10-22 12:50:53 +01003641 int pattern_length = pattern.length();
Steve Block6ded16b2010-05-10 14:33:55 +01003642 int max_search_start = subject_length - pattern_length;
Steve Block44f0eee2011-05-26 01:26:41 +01003643 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
Ben Murdochf87a2032010-10-22 12:50:53 +01003644 while (pos <= max_search_start) {
3645 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3646 *match_pos = pos;
3647 return false;
3648 }
3649 // Position of end of previous match.
3650 int match_end = pos + pattern_length;
3651 int new_pos = search.Search(subject, match_end);
3652 if (new_pos >= 0) {
3653 // A match.
3654 if (new_pos > match_end) {
3655 ReplacementStringBuilder::AddSubjectSlice(builder,
3656 match_end,
3657 new_pos);
Steve Block6ded16b2010-05-10 14:33:55 +01003658 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003659 pos = new_pos;
3660 builder->Add(pattern_string);
3661 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003662 break;
Ben Murdochf87a2032010-10-22 12:50:53 +01003663 }
Steve Block6ded16b2010-05-10 14:33:55 +01003664 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003665
Steve Block6ded16b2010-05-10 14:33:55 +01003666 if (pos < max_search_start) {
3667 ReplacementStringBuilder::AddSubjectSlice(builder,
3668 pos + pattern_length,
3669 subject_length);
3670 }
3671 *match_pos = pos;
3672 return true;
3673}
3674
3675
Steve Block44f0eee2011-05-26 01:26:41 +01003676static bool SearchStringMultiple(Isolate* isolate,
3677 Handle<String> subject,
Steve Block6ded16b2010-05-10 14:33:55 +01003678 Handle<String> pattern,
3679 Handle<JSArray> last_match_info,
3680 FixedArrayBuilder* builder) {
3681 ASSERT(subject->IsFlat());
3682 ASSERT(pattern->IsFlat());
Steve Block6ded16b2010-05-10 14:33:55 +01003683
3684 // Treating as if a previous match was before first character.
3685 int match_pos = -pattern->length();
3686
3687 for (;;) { // Break when search complete.
3688 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3689 AssertNoAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003690 String::FlatContent subject_content = subject->GetFlatContent();
3691 String::FlatContent pattern_content = pattern->GetFlatContent();
3692 if (subject_content.IsAscii()) {
3693 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3694 if (pattern_content.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003695 if (SearchStringMultiple(isolate,
3696 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003697 pattern_content.ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003698 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003699 builder,
3700 &match_pos)) break;
3701 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003702 if (SearchStringMultiple(isolate,
3703 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003704 pattern_content.ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003705 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003706 builder,
3707 &match_pos)) break;
3708 }
3709 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003710 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3711 if (pattern_content.IsAscii()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003712 if (SearchStringMultiple(isolate,
3713 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003714 pattern_content.ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003715 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003716 builder,
3717 &match_pos)) break;
3718 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003719 if (SearchStringMultiple(isolate,
3720 subject_vector,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003721 pattern_content.ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003722 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003723 builder,
3724 &match_pos)) break;
3725 }
3726 }
3727 }
3728
3729 if (match_pos >= 0) {
3730 SetLastMatchInfoNoCaptures(subject,
3731 last_match_info,
3732 match_pos,
3733 match_pos + pattern->length());
3734 return true;
3735 }
3736 return false; // No matches at all.
3737}
3738
3739
3740static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003741 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003742 Handle<String> subject,
3743 Handle<JSRegExp> regexp,
3744 Handle<JSArray> last_match_array,
3745 FixedArrayBuilder* builder) {
3746 ASSERT(subject->IsFlat());
3747 int match_start = -1;
3748 int match_end = 0;
3749 int pos = 0;
3750 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3751 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3752
3753 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003754 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003755 int subject_length = subject->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003756 bool first = true;
Steve Block6ded16b2010-05-10 14:33:55 +01003757
3758 for (;;) { // Break on failure, return on exception.
3759 RegExpImpl::IrregexpResult result =
3760 RegExpImpl::IrregexpExecOnce(regexp,
3761 subject,
3762 pos,
3763 register_vector);
3764 if (result == RegExpImpl::RE_SUCCESS) {
3765 match_start = register_vector[0];
3766 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3767 if (match_end < match_start) {
3768 ReplacementStringBuilder::AddSubjectSlice(builder,
3769 match_end,
3770 match_start);
3771 }
3772 match_end = register_vector[1];
Steve Block44f0eee2011-05-26 01:26:41 +01003773 HandleScope loop_scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003774 if (!first) {
3775 builder->Add(*isolate->factory()->NewProperSubString(subject,
3776 match_start,
3777 match_end));
3778 } else {
3779 builder->Add(*isolate->factory()->NewSubString(subject,
3780 match_start,
3781 match_end));
3782 }
Steve Block6ded16b2010-05-10 14:33:55 +01003783 if (match_start != match_end) {
3784 pos = match_end;
3785 } else {
3786 pos = match_end + 1;
3787 if (pos > subject_length) break;
3788 }
3789 } else if (result == RegExpImpl::RE_FAILURE) {
3790 break;
3791 } else {
3792 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3793 return result;
3794 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003795 first = false;
Steve Block6ded16b2010-05-10 14:33:55 +01003796 }
3797
3798 if (match_start >= 0) {
3799 if (match_end < subject_length) {
3800 ReplacementStringBuilder::AddSubjectSlice(builder,
3801 match_end,
3802 subject_length);
3803 }
3804 SetLastMatchInfoNoCaptures(subject,
3805 last_match_array,
3806 match_start,
3807 match_end);
3808 return RegExpImpl::RE_SUCCESS;
3809 } else {
3810 return RegExpImpl::RE_FAILURE; // No matches at all.
3811 }
3812}
3813
3814
3815static RegExpImpl::IrregexpResult SearchRegExpMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003816 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003817 Handle<String> subject,
3818 Handle<JSRegExp> regexp,
3819 Handle<JSArray> last_match_array,
3820 FixedArrayBuilder* builder) {
3821
3822 ASSERT(subject->IsFlat());
3823 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3824 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3825
3826 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003827 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003828
3829 RegExpImpl::IrregexpResult result =
3830 RegExpImpl::IrregexpExecOnce(regexp,
3831 subject,
3832 0,
3833 register_vector);
3834
3835 int capture_count = regexp->CaptureCount();
3836 int subject_length = subject->length();
3837
3838 // Position to search from.
3839 int pos = 0;
3840 // End of previous match. Differs from pos if match was empty.
3841 int match_end = 0;
3842 if (result == RegExpImpl::RE_SUCCESS) {
3843 // Need to keep a copy of the previous match for creating last_match_info
3844 // at the end, so we have two vectors that we swap between.
3845 OffsetsVector registers2(required_registers);
3846 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003847 bool first = true;
Steve Block6ded16b2010-05-10 14:33:55 +01003848 do {
3849 int match_start = register_vector[0];
3850 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3851 if (match_end < match_start) {
3852 ReplacementStringBuilder::AddSubjectSlice(builder,
3853 match_end,
3854 match_start);
3855 }
3856 match_end = register_vector[1];
3857
3858 {
3859 // Avoid accumulating new handles inside loop.
Steve Block44f0eee2011-05-26 01:26:41 +01003860 HandleScope temp_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003861 // Arguments array to replace function is match, captures, index and
3862 // subject, i.e., 3 + capture count in total.
Steve Block44f0eee2011-05-26 01:26:41 +01003863 Handle<FixedArray> elements =
3864 isolate->factory()->NewFixedArray(3 + capture_count);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003865 Handle<String> match;
3866 if (!first) {
3867 match = isolate->factory()->NewProperSubString(subject,
3868 match_start,
3869 match_end);
3870 } else {
3871 match = isolate->factory()->NewSubString(subject,
3872 match_start,
3873 match_end);
3874 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003875 elements->set(0, *match);
Steve Block6ded16b2010-05-10 14:33:55 +01003876 for (int i = 1; i <= capture_count; i++) {
3877 int start = register_vector[i * 2];
3878 if (start >= 0) {
3879 int end = register_vector[i * 2 + 1];
3880 ASSERT(start <= end);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003881 Handle<String> substring;
3882 if (!first) {
3883 substring = isolate->factory()->NewProperSubString(subject,
3884 start,
3885 end);
3886 } else {
3887 substring = isolate->factory()->NewSubString(subject, start, end);
3888 }
Steve Block6ded16b2010-05-10 14:33:55 +01003889 elements->set(i, *substring);
3890 } else {
3891 ASSERT(register_vector[i * 2 + 1] < 0);
Steve Block44f0eee2011-05-26 01:26:41 +01003892 elements->set(i, isolate->heap()->undefined_value());
Steve Block6ded16b2010-05-10 14:33:55 +01003893 }
3894 }
3895 elements->set(capture_count + 1, Smi::FromInt(match_start));
3896 elements->set(capture_count + 2, *subject);
Steve Block44f0eee2011-05-26 01:26:41 +01003897 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
Steve Block6ded16b2010-05-10 14:33:55 +01003898 }
3899 // Swap register vectors, so the last successful match is in
3900 // prev_register_vector.
Steve Block791712a2010-08-27 10:21:07 +01003901 Vector<int32_t> tmp = prev_register_vector;
Steve Block6ded16b2010-05-10 14:33:55 +01003902 prev_register_vector = register_vector;
3903 register_vector = tmp;
3904
3905 if (match_end > match_start) {
3906 pos = match_end;
3907 } else {
3908 pos = match_end + 1;
3909 if (pos > subject_length) {
3910 break;
3911 }
3912 }
3913
3914 result = RegExpImpl::IrregexpExecOnce(regexp,
3915 subject,
3916 pos,
3917 register_vector);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003918 first = false;
Steve Block6ded16b2010-05-10 14:33:55 +01003919 } while (result == RegExpImpl::RE_SUCCESS);
3920
3921 if (result != RegExpImpl::RE_EXCEPTION) {
3922 // Finished matching, with at least one match.
3923 if (match_end < subject_length) {
3924 ReplacementStringBuilder::AddSubjectSlice(builder,
3925 match_end,
3926 subject_length);
3927 }
3928
3929 int last_match_capture_count = (capture_count + 1) * 2;
3930 int last_match_array_size =
3931 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3932 last_match_array->EnsureSize(last_match_array_size);
3933 AssertNoAllocation no_gc;
3934 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3935 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3936 RegExpImpl::SetLastSubject(elements, *subject);
3937 RegExpImpl::SetLastInput(elements, *subject);
3938 for (int i = 0; i < last_match_capture_count; i++) {
3939 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3940 }
3941 return RegExpImpl::RE_SUCCESS;
3942 }
3943 }
3944 // No matches at all, return failure or exception result directly.
3945 return result;
3946}
3947
3948
Ben Murdoch8b112d22011-06-08 16:22:53 +01003949RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
Steve Block6ded16b2010-05-10 14:33:55 +01003950 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01003951 HandleScope handles(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003952
3953 CONVERT_ARG_CHECKED(String, subject, 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003954 if (!subject->IsFlat()) FlattenString(subject);
Steve Block6ded16b2010-05-10 14:33:55 +01003955 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3956 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3957 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3958
3959 ASSERT(last_match_info->HasFastElements());
3960 ASSERT(regexp->GetFlags().is_global());
3961 Handle<FixedArray> result_elements;
3962 if (result_array->HasFastElements()) {
3963 result_elements =
3964 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003965 }
3966 if (result_elements.is_null() || result_elements->length() < 16) {
Steve Block44f0eee2011-05-26 01:26:41 +01003967 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
Steve Block6ded16b2010-05-10 14:33:55 +01003968 }
3969 FixedArrayBuilder builder(result_elements);
3970
3971 if (regexp->TypeTag() == JSRegExp::ATOM) {
3972 Handle<String> pattern(
3973 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003974 ASSERT(pattern->IsFlat());
Steve Block44f0eee2011-05-26 01:26:41 +01003975 if (SearchStringMultiple(isolate, subject, pattern,
3976 last_match_info, &builder)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003977 return *builder.ToJSArray(result_array);
3978 }
Steve Block44f0eee2011-05-26 01:26:41 +01003979 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003980 }
3981
3982 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3983
3984 RegExpImpl::IrregexpResult result;
3985 if (regexp->CaptureCount() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003986 result = SearchRegExpNoCaptureMultiple(isolate,
3987 subject,
Steve Block6ded16b2010-05-10 14:33:55 +01003988 regexp,
3989 last_match_info,
3990 &builder);
3991 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003992 result = SearchRegExpMultiple(isolate,
3993 subject,
3994 regexp,
3995 last_match_info,
3996 &builder);
Steve Block6ded16b2010-05-10 14:33:55 +01003997 }
3998 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
Steve Block44f0eee2011-05-26 01:26:41 +01003999 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004000 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4001 return Failure::Exception();
4002}
4003
4004
Ben Murdoch8b112d22011-06-08 16:22:53 +01004005RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004006 NoHandleAllocation ha;
4007 ASSERT(args.length() == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004008 CONVERT_SMI_ARG_CHECKED(radix, 1);
4009 RUNTIME_ASSERT(2 <= radix && radix <= 36);
Steve Blocka7e24c12009-10-30 11:49:00 +00004010
4011 // Fast case where the result is a one character string.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004012 if (args[0]->IsSmi()) {
4013 int value = args.smi_at(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004014 if (value >= 0 && value < radix) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004015 // Character array used for conversion.
4016 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
Steve Block44f0eee2011-05-26 01:26:41 +01004017 return isolate->heap()->
4018 LookupSingleCharacterStringFromCode(kCharTable[value]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004019 }
4020 }
4021
4022 // Slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004023 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004024 if (isnan(value)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004025 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004026 }
4027 if (isinf(value)) {
4028 if (value < 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004029 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004030 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004031 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004032 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004033 char* str = DoubleToRadixCString(value, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01004034 MaybeObject* result =
4035 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004036 DeleteArray(str);
4037 return result;
4038}
4039
4040
Ben Murdoch8b112d22011-06-08 16:22:53 +01004041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004042 NoHandleAllocation ha;
4043 ASSERT(args.length() == 2);
4044
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004045 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004046 if (isnan(value)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004047 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004048 }
4049 if (isinf(value)) {
4050 if (value < 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004051 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004052 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004053 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004054 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004055 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004056 int f = FastD2I(f_number);
4057 RUNTIME_ASSERT(f >= 0);
4058 char* str = DoubleToFixedCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004059 MaybeObject* res =
4060 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004061 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004062 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004063}
4064
4065
Ben Murdoch8b112d22011-06-08 16:22:53 +01004066RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004067 NoHandleAllocation ha;
4068 ASSERT(args.length() == 2);
4069
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004070 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004071 if (isnan(value)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004072 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004073 }
4074 if (isinf(value)) {
4075 if (value < 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004076 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004077 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004078 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004079 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004080 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004081 int f = FastD2I(f_number);
4082 RUNTIME_ASSERT(f >= -1 && f <= 20);
4083 char* str = DoubleToExponentialCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004084 MaybeObject* res =
4085 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004086 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004087 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004088}
4089
4090
Ben Murdoch8b112d22011-06-08 16:22:53 +01004091RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004092 NoHandleAllocation ha;
4093 ASSERT(args.length() == 2);
4094
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004095 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004096 if (isnan(value)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004097 return *isolate->factory()->nan_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004098 }
4099 if (isinf(value)) {
4100 if (value < 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004101 return *isolate->factory()->minus_infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004102 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004103 return *isolate->factory()->infinity_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004104 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004105 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004106 int f = FastD2I(f_number);
4107 RUNTIME_ASSERT(f >= 1 && f <= 21);
4108 char* str = DoubleToPrecisionCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01004109 MaybeObject* res =
4110 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00004111 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01004112 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00004113}
4114
4115
4116// Returns a single character string where first character equals
4117// string->Get(index).
4118static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4119 if (index < static_cast<uint32_t>(string->length())) {
Steve Block6ded16b2010-05-10 14:33:55 +01004120 string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004121 return LookupSingleCharacterStringFromCode(
4122 string->Get(index));
4123 }
4124 return Execution::CharAt(string, index);
4125}
4126
4127
Steve Block44f0eee2011-05-26 01:26:41 +01004128MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4129 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004130 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004131 // Handle [] indexing on Strings
4132 if (object->IsString()) {
4133 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4134 if (!result->IsUndefined()) return *result;
4135 }
4136
4137 // Handle [] indexing on String objects
4138 if (object->IsStringObjectWithCharacterAt(index)) {
4139 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4140 Handle<Object> result =
4141 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4142 if (!result->IsUndefined()) return *result;
4143 }
4144
4145 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004146 return object->GetPrototype()->GetElement(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004147 }
4148
4149 return object->GetElement(index);
4150}
4151
4152
Steve Block44f0eee2011-05-26 01:26:41 +01004153MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4154 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004155 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004156 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004157
4158 if (object->IsUndefined() || object->IsNull()) {
4159 Handle<Object> args[2] = { key, object };
4160 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01004161 isolate->factory()->NewTypeError("non_object_property_load",
4162 HandleVector(args, 2));
4163 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00004164 }
4165
4166 // Check if the given key is an array index.
4167 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004168 if (key->ToArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004169 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004170 }
4171
4172 // Convert the key to a string - possibly by calling back into JavaScript.
4173 Handle<String> name;
4174 if (key->IsString()) {
4175 name = Handle<String>::cast(key);
4176 } else {
4177 bool has_pending_exception = false;
4178 Handle<Object> converted =
4179 Execution::ToString(key, &has_pending_exception);
4180 if (has_pending_exception) return Failure::Exception();
4181 name = Handle<String>::cast(converted);
4182 }
4183
4184 // Check if the name is trivially convertible to an index and get
4185 // the element if so.
4186 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004187 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004188 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004189 return object->GetProperty(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +00004190 }
4191}
4192
4193
Ben Murdoch8b112d22011-06-08 16:22:53 +01004194RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004195 NoHandleAllocation ha;
4196 ASSERT(args.length() == 2);
4197
4198 Handle<Object> object = args.at<Object>(0);
4199 Handle<Object> key = args.at<Object>(1);
4200
Steve Block44f0eee2011-05-26 01:26:41 +01004201 return Runtime::GetObjectProperty(isolate, object, key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004202}
4203
4204
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004205MaybeObject* TransitionElements(Handle<Object> object,
4206 ElementsKind to_kind,
4207 Isolate* isolate) {
4208 HandleScope scope(isolate);
4209 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4210 ElementsKind from_kind =
4211 Handle<JSObject>::cast(object)->map()->elements_kind();
4212 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004213 Handle<Object> result = JSObject::TransitionElementsKind(
4214 Handle<JSObject>::cast(object), to_kind);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004215 if (result.is_null()) return isolate->ThrowIllegalOperation();
4216 return *result;
4217 }
4218 return isolate->ThrowIllegalOperation();
4219}
4220
4221
Steve Blocka7e24c12009-10-30 11:49:00 +00004222// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004223RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004224 NoHandleAllocation ha;
4225 ASSERT(args.length() == 2);
4226
4227 // Fast cases for getting named properties of the receiver JSObject
4228 // itself.
4229 //
4230 // The global proxy objects has to be excluded since LocalLookup on
4231 // the global proxy object can return a valid result even though the
4232 // global proxy object never has properties. This is the case
4233 // because the global proxy object forwards everything to its hidden
4234 // prototype including local lookups.
4235 //
4236 // Additionally, we need to make sure that we do not cache results
4237 // for objects that require access checks.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004238 if (args[0]->IsJSObject()) {
4239 if (!args[0]->IsJSGlobalProxy() &&
4240 !args[0]->IsAccessCheckNeeded() &&
4241 args[1]->IsString()) {
4242 JSObject* receiver = JSObject::cast(args[0]);
4243 String* key = String::cast(args[1]);
4244 if (receiver->HasFastProperties()) {
4245 // Attempt to use lookup cache.
4246 Map* receiver_map = receiver->map();
4247 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4248 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4249 if (offset != -1) {
4250 Object* value = receiver->FastPropertyAt(offset);
4251 return value->IsTheHole()
4252 ? isolate->heap()->undefined_value()
4253 : value;
4254 }
4255 // Lookup cache miss. Perform lookup and update the cache if
4256 // appropriate.
4257 LookupResult result(isolate);
4258 receiver->LocalLookup(key, &result);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004259 if (result.IsFound() && result.type() == FIELD) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004260 int offset = result.GetFieldIndex();
4261 keyed_lookup_cache->Update(receiver_map, key, offset);
4262 return receiver->FastPropertyAt(offset);
4263 }
4264 } else {
4265 // Attempt dictionary lookup.
4266 StringDictionary* dictionary = receiver->property_dictionary();
4267 int entry = dictionary->FindEntry(key);
4268 if ((entry != StringDictionary::kNotFound) &&
4269 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4270 Object* value = dictionary->ValueAt(entry);
4271 if (!receiver->IsGlobalObject()) return value;
4272 value = JSGlobalPropertyCell::cast(value)->value();
4273 if (!value->IsTheHole()) return value;
4274 // If value is the hole do the general lookup.
4275 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004276 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004277 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4278 // JSObject without a string key. If the key is a Smi, check for a
4279 // definite out-of-bounds access to elements, which is a strong indicator
4280 // that subsequent accesses will also call the runtime. Proactively
4281 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4282 // doubles for those future calls in the case that the elements would
4283 // become FAST_DOUBLE_ELEMENTS.
4284 Handle<JSObject> js_object(args.at<JSObject>(0));
4285 ElementsKind elements_kind = js_object->GetElementsKind();
4286 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4287 elements_kind == FAST_DOUBLE_ELEMENTS) {
4288 FixedArrayBase* elements = js_object->elements();
4289 if (args.at<Smi>(1)->value() >= elements->length()) {
4290 MaybeObject* maybe_object = TransitionElements(js_object,
4291 FAST_ELEMENTS,
4292 isolate);
4293 if (maybe_object->IsFailure()) return maybe_object;
4294 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004295 }
4296 }
Leon Clarkee46be812010-01-19 14:06:41 +00004297 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4298 // Fast case for string indexing using [] with a smi index.
Steve Block44f0eee2011-05-26 01:26:41 +01004299 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004300 Handle<String> str = args.at<String>(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004301 int index = args.smi_at(1);
Steve Block1e0659c2011-05-24 12:43:12 +01004302 if (index >= 0 && index < str->length()) {
4303 Handle<Object> result = GetCharAt(str, index);
4304 return *result;
4305 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004306 }
4307
4308 // Fall back to GetObjectProperty.
Steve Block44f0eee2011-05-26 01:26:41 +01004309 return Runtime::GetObjectProperty(isolate,
4310 args.at<Object>(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00004311 args.at<Object>(1));
4312}
4313
Steve Block1e0659c2011-05-24 12:43:12 +01004314// Implements part of 8.12.9 DefineOwnProperty.
4315// There are 3 cases that lead here:
4316// Step 4b - define a new accessor property.
4317// Steps 9c & 12 - replace an existing data property with an accessor property.
4318// Step 12 - update an existing accessor property with an accessor or generic
4319// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004320RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00004321 ASSERT(args.length() == 5);
Steve Block44f0eee2011-05-26 01:26:41 +01004322 HandleScope scope(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00004323 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4324 CONVERT_CHECKED(String, name, args[1]);
4325 CONVERT_CHECKED(Smi, flag_setter, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004326 Object* fun = args[3];
Andrei Popescu31002712010-02-23 13:46:05 +00004327 CONVERT_CHECKED(Smi, flag_attr, args[4]);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004328
Andrei Popescu31002712010-02-23 13:46:05 +00004329 int unchecked = flag_attr->value();
4330 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Andrei Popescu31002712010-02-23 13:46:05 +00004331 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004332
4333 RUNTIME_ASSERT(!obj->IsNull());
4334 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
Andrei Popescu31002712010-02-23 13:46:05 +00004335 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4336}
4337
Steve Block1e0659c2011-05-24 12:43:12 +01004338// Implements part of 8.12.9 DefineOwnProperty.
4339// There are 3 cases that lead here:
4340// Step 4a - define a new data property.
4341// Steps 9b & 12 - replace an existing accessor property with a data property.
4342// Step 12 - update an existing data property with a data or generic
4343// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004344RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00004345 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01004346 HandleScope scope(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00004347 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4348 CONVERT_ARG_CHECKED(String, name, 1);
4349 Handle<Object> obj_value = args.at<Object>(2);
Andrei Popescu31002712010-02-23 13:46:05 +00004350 CONVERT_CHECKED(Smi, flag, args[3]);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004351
Andrei Popescu31002712010-02-23 13:46:05 +00004352 int unchecked = flag->value();
4353 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004354 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4355
4356 // Check if this is an element.
4357 uint32_t index;
4358 bool is_element = name->AsArrayIndex(&index);
4359
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004360 // Special case for elements if any of the flags might be involved.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004361 // If elements are in fast case we always implicitly assume that:
4362 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004363 if (is_element && (attr != NONE ||
4364 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004365 // Normalize the elements to enable attributes on the property.
Steve Block1e0659c2011-05-24 12:43:12 +01004366 if (js_object->IsJSGlobalProxy()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004367 // We do not need to do access checks here since these has already
4368 // been performed by the call to GetOwnProperty.
Steve Block1e0659c2011-05-24 12:43:12 +01004369 Handle<Object> proto(js_object->GetPrototype());
4370 // If proxy is detached, ignore the assignment. Alternatively,
4371 // we could throw an exception.
4372 if (proto->IsNull()) return *obj_value;
4373 js_object = Handle<JSObject>::cast(proto);
4374 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004375
4376 // Don't allow element properties to be redefined on objects with external
4377 // array elements.
4378 if (js_object->HasExternalArrayElements()) {
4379 Handle<Object> args[2] = { js_object, name };
4380 Handle<Object> error =
4381 isolate->factory()->NewTypeError("redef_external_array_element",
4382 HandleVector(args, 2));
4383 return isolate->Throw(*error);
4384 }
4385
Ben Murdochc7cc0282012-03-05 14:35:55 +00004386 Handle<SeededNumberDictionary> dictionary =
4387 JSObject::NormalizeElements(js_object);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004388 // Make sure that we never go back to fast case.
4389 dictionary->set_requires_slow_elements();
4390 PropertyDetails details = PropertyDetails(attr, NORMAL);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004391 Handle<SeededNumberDictionary> extended_dictionary =
4392 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004393 if (*extended_dictionary != *dictionary) {
Ben Murdoch589d6972011-11-30 16:04:58 +00004394 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004395 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4396 } else {
4397 js_object->set_elements(*extended_dictionary);
4398 }
4399 }
Steve Block1e0659c2011-05-24 12:43:12 +01004400 return *obj_value;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004401 }
4402
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004403 LookupResult result(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004404 js_object->LocalLookupRealNamedProperty(*name, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00004405
Ben Murdochc7cc0282012-03-05 14:35:55 +00004406 // Special case for callback properties.
4407 if (result.IsFound() && result.type() == CALLBACKS) {
4408 Object* callback = result.GetCallbackObject();
4409 // To be compatible with Safari we do not change the value on API objects
4410 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4411 // the value.
4412 if (callback->IsAccessorInfo()) {
4413 return isolate->heap()->undefined_value();
4414 }
4415 // Avoid redefining foreign callback as data property, just use the stored
4416 // setter to update the value instead.
4417 // TODO(mstarzinger): So far this only works if property attributes don't
4418 // change, this should be fixed once we cleanup the underlying code.
4419 if (callback->IsForeign() && result.GetAttributes() == attr) {
4420 return js_object->SetPropertyWithCallback(callback,
4421 *name,
4422 *obj_value,
4423 result.holder(),
4424 kStrictMode);
4425 }
Steve Block44f0eee2011-05-26 01:26:41 +01004426 }
4427
Andrei Popescu31002712010-02-23 13:46:05 +00004428 // Take special care when attributes are different and there is already
4429 // a property. For simplicity we normalize the property which enables us
4430 // to not worry about changing the instance_descriptor and creating a new
4431 // map. The current version of SetObjectProperty does not handle attributes
4432 // correctly in the case where a property is a field and is reset with
4433 // new attributes.
Ben Murdochb0fe1622011-05-05 13:52:32 +01004434 if (result.IsProperty() &&
4435 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
Andrei Popescu31002712010-02-23 13:46:05 +00004436 // New attributes - normalize to avoid writing to instance descriptor
Steve Block1e0659c2011-05-24 12:43:12 +01004437 if (js_object->IsJSGlobalProxy()) {
4438 // Since the result is a property, the prototype will exist so
4439 // we don't have to check for null.
4440 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
4441 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004442 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00004443 // Use IgnoreAttributes version since a readonly property may be
4444 // overridden and SetProperty does not allow this.
Ben Murdoch086aeea2011-05-13 15:57:08 +01004445 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4446 *obj_value,
4447 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00004448 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01004449
Steve Block44f0eee2011-05-26 01:26:41 +01004450 return Runtime::ForceSetObjectProperty(isolate,
4451 js_object,
4452 name,
4453 obj_value,
4454 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00004455}
4456
4457
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004458// Special case for elements if any of the flags are true.
4459// If elements are in fast case we always implicitly assume that:
4460// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4461static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4462 Handle<JSObject> js_object,
4463 uint32_t index,
4464 Handle<Object> value,
4465 PropertyAttributes attr) {
4466 // Normalize the elements to enable attributes on the property.
Ben Murdochc7cc0282012-03-05 14:35:55 +00004467 Handle<SeededNumberDictionary> dictionary =
4468 JSObject::NormalizeElements(js_object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004469 // Make sure that we never go back to fast case.
4470 dictionary->set_requires_slow_elements();
4471 PropertyDetails details = PropertyDetails(attr, NORMAL);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004472 Handle<SeededNumberDictionary> extended_dictionary =
4473 SeededNumberDictionary::Set(dictionary, index, value, details);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004474 if (*extended_dictionary != *dictionary) {
4475 js_object->set_elements(*extended_dictionary);
4476 }
4477 return *value;
4478}
4479
4480
Steve Block44f0eee2011-05-26 01:26:41 +01004481MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4482 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07004483 Handle<Object> key,
4484 Handle<Object> value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004485 PropertyAttributes attr,
4486 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01004487 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004488
4489 if (object->IsUndefined() || object->IsNull()) {
4490 Handle<Object> args[2] = { key, object };
4491 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01004492 isolate->factory()->NewTypeError("non_object_property_store",
4493 HandleVector(args, 2));
4494 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00004495 }
4496
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004497 if (object->IsJSProxy()) {
4498 bool has_pending_exception = false;
4499 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4500 if (has_pending_exception) return Failure::Exception();
4501 return JSProxy::cast(*object)->SetProperty(
4502 String::cast(*name), *value, attr, strict_mode);
4503 }
4504
Steve Blocka7e24c12009-10-30 11:49:00 +00004505 // If the object isn't a JavaScript object, we ignore the store.
4506 if (!object->IsJSObject()) return *value;
4507
4508 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4509
4510 // Check if the given key is an array index.
4511 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004512 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004513 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4514 // of a string using [] notation. We need to support this too in
4515 // JavaScript.
4516 // In the case of a String object we just need to redirect the assignment to
4517 // the underlying string if the index is in range. Since the underlying
4518 // string does nothing with the assignment then we can ignore such
4519 // assignments.
4520 if (js_object->IsStringObjectWithCharacterAt(index)) {
4521 return *value;
4522 }
4523
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004524 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4525 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4526 }
4527
Ben Murdochc7cc0282012-03-05 14:35:55 +00004528 Handle<Object> result =
4529 JSObject::SetElement(js_object, index, value, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004530 if (result.is_null()) return Failure::Exception();
4531 return *value;
4532 }
4533
4534 if (key->IsString()) {
4535 Handle<Object> result;
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004537 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4538 return NormalizeObjectSetElement(isolate,
4539 js_object,
4540 index,
4541 value,
4542 attr);
4543 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004544 result =
4545 JSObject::SetElement(js_object, index, value, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004546 } else {
4547 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01004548 key_string->TryFlatten();
Ben Murdochc7cc0282012-03-05 14:35:55 +00004549 result = JSReceiver::SetProperty(
4550 js_object, key_string, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004551 }
4552 if (result.is_null()) return Failure::Exception();
4553 return *value;
4554 }
4555
4556 // Call-back into JavaScript to convert the key to a string.
4557 bool has_pending_exception = false;
4558 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4559 if (has_pending_exception) return Failure::Exception();
4560 Handle<String> name = Handle<String>::cast(converted);
4561
4562 if (name->AsArrayIndex(&index)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004563 return js_object->SetElement(index, *value, strict_mode, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004564 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004565 return js_object->SetProperty(*name, *value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004566 }
4567}
4568
4569
Steve Block44f0eee2011-05-26 01:26:41 +01004570MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4571 Handle<JSObject> js_object,
John Reck59135872010-11-02 12:39:01 -07004572 Handle<Object> key,
4573 Handle<Object> value,
4574 PropertyAttributes attr) {
Steve Block44f0eee2011-05-26 01:26:41 +01004575 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004576
4577 // Check if the given key is an array index.
4578 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004579 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004580 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4581 // of a string using [] notation. We need to support this too in
4582 // JavaScript.
4583 // In the case of a String object we just need to redirect the assignment to
4584 // the underlying string if the index is in range. Since the underlying
4585 // string does nothing with the assignment then we can ignore such
4586 // assignments.
4587 if (js_object->IsStringObjectWithCharacterAt(index)) {
4588 return *value;
4589 }
4590
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004591 return js_object->SetElement(index, *value, kNonStrictMode, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004592 }
4593
4594 if (key->IsString()) {
4595 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004596 return js_object->SetElement(index, *value, kNonStrictMode, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004597 } else {
4598 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01004599 key_string->TryFlatten();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004600 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4601 *value,
4602 attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004603 }
4604 }
4605
4606 // Call-back into JavaScript to convert the key to a string.
4607 bool has_pending_exception = false;
4608 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4609 if (has_pending_exception) return Failure::Exception();
4610 Handle<String> name = Handle<String>::cast(converted);
4611
4612 if (name->AsArrayIndex(&index)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004613 return js_object->SetElement(index, *value, kNonStrictMode, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00004614 } else {
Ben Murdoch086aeea2011-05-13 15:57:08 +01004615 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004616 }
4617}
4618
4619
Steve Block44f0eee2011-05-26 01:26:41 +01004620MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004621 Handle<JSReceiver> receiver,
John Reck59135872010-11-02 12:39:01 -07004622 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004623 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004624
4625 // Check if the given key is an array index.
4626 uint32_t index;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004627 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004628 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4629 // characters of a string using [] notation. In the case of a
4630 // String object we just need to redirect the deletion to the
4631 // underlying string if the index is in range. Since the
4632 // underlying string does nothing with the deletion, we can ignore
4633 // such deletions.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004634 if (receiver->IsStringObjectWithCharacterAt(index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004635 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004636 }
4637
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004638 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004639 }
4640
4641 Handle<String> key_string;
4642 if (key->IsString()) {
4643 key_string = Handle<String>::cast(key);
4644 } else {
4645 // Call-back into JavaScript to convert the key to a string.
4646 bool has_pending_exception = false;
4647 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4648 if (has_pending_exception) return Failure::Exception();
4649 key_string = Handle<String>::cast(converted);
4650 }
4651
Steve Block6ded16b2010-05-10 14:33:55 +01004652 key_string->TryFlatten();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004653 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004654}
4655
4656
Ben Murdoch8b112d22011-06-08 16:22:53 +01004657RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004658 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004659 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00004660
4661 Handle<Object> object = args.at<Object>(0);
4662 Handle<Object> key = args.at<Object>(1);
4663 Handle<Object> value = args.at<Object>(2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004664 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004665 RUNTIME_ASSERT(
4666 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004667 // Compute attributes.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004668 PropertyAttributes attributes =
4669 static_cast<PropertyAttributes>(unchecked_attributes);
4670
4671 StrictModeFlag strict_mode = kNonStrictMode;
4672 if (args.length() == 5) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004673 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4674 strict_mode = strict_mode_flag;
Steve Blocka7e24c12009-10-30 11:49:00 +00004675 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004676
Steve Block44f0eee2011-05-26 01:26:41 +01004677 return Runtime::SetObjectProperty(isolate,
4678 object,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004679 key,
4680 value,
4681 attributes,
4682 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004683}
4684
4685
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4687 NoHandleAllocation ha;
4688 RUNTIME_ASSERT(args.length() == 1);
4689 Handle<Object> object = args.at<Object>(0);
4690 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4691}
4692
4693
4694RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4695 NoHandleAllocation ha;
4696 RUNTIME_ASSERT(args.length() == 1);
4697 Handle<Object> object = args.at<Object>(0);
4698 return TransitionElements(object, FAST_ELEMENTS, isolate);
4699}
4700
4701
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004702// Set the native flag on the function.
Ben Murdoch257744e2011-11-30 15:57:28 +00004703// This is used to decide if we should transform null and undefined
4704// into the global object when doing call and apply.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004705RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
Ben Murdoch257744e2011-11-30 15:57:28 +00004706 NoHandleAllocation ha;
4707 RUNTIME_ASSERT(args.length() == 1);
4708
4709 Handle<Object> object = args.at<Object>(0);
4710
4711 if (object->IsJSFunction()) {
4712 JSFunction* func = JSFunction::cast(*object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004713 func->shared()->set_native(true);
Ben Murdoch257744e2011-11-30 15:57:28 +00004714 }
4715 return isolate->heap()->undefined_value();
4716}
4717
4718
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004719RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4720 RUNTIME_ASSERT(args.length() == 5);
4721 CONVERT_ARG_CHECKED(JSObject, object, 0);
4722 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4723 Handle<Object> value = args.at<Object>(2);
4724 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4725 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4726 HandleScope scope;
4727
4728 Object* raw_boilerplate_object = literals->get(literal_index);
4729 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4730#if DEBUG
4731 ElementsKind elements_kind = object->GetElementsKind();
4732#endif
4733 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4734 // Smis should never trigger transitions.
4735 ASSERT(!value->IsSmi());
4736
4737 if (value->IsNumber()) {
4738 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004739 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4740 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004741 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4742 FixedDoubleArray* double_array =
4743 FixedDoubleArray::cast(object->elements());
4744 HeapNumber* number = HeapNumber::cast(*value);
4745 double_array->set(store_index, number->Number());
4746 } else {
4747 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4748 elements_kind == FAST_DOUBLE_ELEMENTS);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004749 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4750 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004751 FixedArray* object_array =
4752 FixedArray::cast(object->elements());
4753 object_array->set(store_index, *value);
4754 }
4755 return *object;
4756}
4757
4758
Steve Blocka7e24c12009-10-30 11:49:00 +00004759// Set a local property, even if it is READ_ONLY. If the property does not
4760// exist, it will be added with attributes NONE.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004761RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004762 NoHandleAllocation ha;
4763 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
4764 CONVERT_CHECKED(JSObject, object, args[0]);
4765 CONVERT_CHECKED(String, name, args[1]);
4766 // Compute attributes.
4767 PropertyAttributes attributes = NONE;
4768 if (args.length() == 4) {
4769 CONVERT_CHECKED(Smi, value_obj, args[3]);
4770 int unchecked_value = value_obj->value();
4771 // Only attribute bits should be set.
4772 RUNTIME_ASSERT(
4773 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4774 attributes = static_cast<PropertyAttributes>(unchecked_value);
4775 }
4776
4777 return object->
Ben Murdoch086aeea2011-05-13 15:57:08 +01004778 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004779}
4780
4781
Ben Murdoch8b112d22011-06-08 16:22:53 +01004782RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004783 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004784 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00004785
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004786 CONVERT_CHECKED(JSReceiver, object, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004787 CONVERT_CHECKED(String, key, args[1]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004788 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4789 return object->DeleteProperty(key, (strict_mode == kStrictMode)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004790 ? JSReceiver::STRICT_DELETION
4791 : JSReceiver::NORMAL_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004792}
4793
4794
Steve Block44f0eee2011-05-26 01:26:41 +01004795static Object* HasLocalPropertyImplementation(Isolate* isolate,
4796 Handle<JSObject> object,
Steve Blocka7e24c12009-10-30 11:49:00 +00004797 Handle<String> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004798 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004799 // Handle hidden prototypes. If there's a hidden prototype above this thing
4800 // then we have to check it for properties, because they are supposed to
4801 // look like they are on this object.
4802 Handle<Object> proto(object->GetPrototype());
4803 if (proto->IsJSObject() &&
4804 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004805 return HasLocalPropertyImplementation(isolate,
4806 Handle<JSObject>::cast(proto),
4807 key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004808 }
Steve Block44f0eee2011-05-26 01:26:41 +01004809 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004810}
4811
4812
Ben Murdoch8b112d22011-06-08 16:22:53 +01004813RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004814 NoHandleAllocation ha;
4815 ASSERT(args.length() == 2);
4816 CONVERT_CHECKED(String, key, args[1]);
4817
Ben Murdoch257744e2011-11-30 15:57:28 +00004818 uint32_t index;
4819 const bool key_is_array_index = key->AsArrayIndex(&index);
4820
Steve Blocka7e24c12009-10-30 11:49:00 +00004821 Object* obj = args[0];
4822 // Only JS objects can have properties.
4823 if (obj->IsJSObject()) {
4824 JSObject* object = JSObject::cast(obj);
Ben Murdoch257744e2011-11-30 15:57:28 +00004825 // Fast case: either the key is a real named property or it is not
4826 // an array index and there are no interceptors or hidden
4827 // prototypes.
Steve Block44f0eee2011-05-26 01:26:41 +01004828 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
Ben Murdoch257744e2011-11-30 15:57:28 +00004829 Map* map = object->map();
4830 if (!key_is_array_index &&
4831 !map->has_named_interceptor() &&
4832 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4833 return isolate->heap()->false_value();
4834 }
4835 // Slow case.
Steve Block44f0eee2011-05-26 01:26:41 +01004836 HandleScope scope(isolate);
4837 return HasLocalPropertyImplementation(isolate,
4838 Handle<JSObject>(object),
Steve Blocka7e24c12009-10-30 11:49:00 +00004839 Handle<String>(key));
Ben Murdoch257744e2011-11-30 15:57:28 +00004840 } else if (obj->IsString() && key_is_array_index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004841 // Well, there is one exception: Handle [] on strings.
Ben Murdoch257744e2011-11-30 15:57:28 +00004842 String* string = String::cast(obj);
4843 if (index < static_cast<uint32_t>(string->length())) {
4844 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004845 }
4846 }
Steve Block44f0eee2011-05-26 01:26:41 +01004847 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004848}
4849
4850
Ben Murdoch8b112d22011-06-08 16:22:53 +01004851RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004852 NoHandleAllocation na;
4853 ASSERT(args.length() == 2);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004854 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4855 CONVERT_CHECKED(String, key, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004856
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004857 bool result = receiver->HasProperty(key);
4858 if (isolate->has_pending_exception()) return Failure::Exception();
4859 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004860}
4861
4862
Ben Murdoch8b112d22011-06-08 16:22:53 +01004863RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004864 NoHandleAllocation na;
4865 ASSERT(args.length() == 2);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004866 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4867 CONVERT_CHECKED(Smi, index, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004868
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004869 bool result = receiver->HasElement(index->value());
4870 if (isolate->has_pending_exception()) return Failure::Exception();
4871 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004872}
4873
4874
Ben Murdoch8b112d22011-06-08 16:22:53 +01004875RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004876 NoHandleAllocation ha;
4877 ASSERT(args.length() == 2);
4878
4879 CONVERT_CHECKED(JSObject, object, args[0]);
4880 CONVERT_CHECKED(String, key, args[1]);
4881
4882 uint32_t index;
4883 if (key->AsArrayIndex(&index)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004884 JSObject::LocalElementType type = object->HasLocalElement(index);
4885 switch (type) {
4886 case JSObject::UNDEFINED_ELEMENT:
4887 case JSObject::STRING_CHARACTER_ELEMENT:
4888 return isolate->heap()->false_value();
4889 case JSObject::INTERCEPTED_ELEMENT:
4890 case JSObject::FAST_ELEMENT:
4891 return isolate->heap()->true_value();
4892 case JSObject::DICTIONARY_ELEMENT: {
4893 if (object->IsJSGlobalProxy()) {
4894 Object* proto = object->GetPrototype();
4895 if (proto->IsNull()) {
4896 return isolate->heap()->false_value();
4897 }
4898 ASSERT(proto->IsJSGlobalObject());
4899 object = JSObject::cast(proto);
4900 }
4901 FixedArray* elements = FixedArray::cast(object->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00004902 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004903 if (elements->map() ==
4904 isolate->heap()->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004905 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004906 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004907 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004908 }
4909 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004910 ASSERT(entry != SeededNumberDictionary::kNotFound);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004911 PropertyDetails details = dictionary->DetailsAt(entry);
4912 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4913 }
4914 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004915 }
4916
4917 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
Steve Block44f0eee2011-05-26 01:26:41 +01004918 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004919}
4920
4921
Ben Murdoch8b112d22011-06-08 16:22:53 +01004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004923 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004924 ASSERT(args.length() == 1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004925 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4926 bool threw = false;
4927 Handle<JSArray> result = GetKeysFor(object, &threw);
4928 if (threw) return Failure::Exception();
4929 return *result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004930}
4931
4932
4933// Returns either a FixedArray as Runtime_GetPropertyNames,
4934// or, if the given object has an enum cache that contains
4935// all enumerable properties of the object and its prototypes
4936// have none, the map of the object. This is used to speed up
4937// the check for deletions during a for-in.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004938RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004939 ASSERT(args.length() == 1);
4940
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004941 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004942
4943 if (raw_object->IsSimpleEnum()) return raw_object->map();
4944
Steve Block44f0eee2011-05-26 01:26:41 +01004945 HandleScope scope(isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004946 Handle<JSReceiver> object(raw_object);
4947 bool threw = false;
4948 Handle<FixedArray> content =
4949 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4950 if (threw) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00004951
4952 // Test again, since cache may have been built by preceding call.
4953 if (object->IsSimpleEnum()) return object->map();
4954
4955 return *content;
4956}
4957
4958
Leon Clarkee46be812010-01-19 14:06:41 +00004959// Find the length of the prototype chain that is to to handled as one. If a
4960// prototype object is hidden it is to be viewed as part of the the object it
4961// is prototype for.
4962static int LocalPrototypeChainLength(JSObject* obj) {
4963 int count = 1;
4964 Object* proto = obj->GetPrototype();
4965 while (proto->IsJSObject() &&
4966 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4967 count++;
4968 proto = JSObject::cast(proto)->GetPrototype();
4969 }
4970 return count;
4971}
4972
4973
4974// Return the names of the local named properties.
4975// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004977 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004978 ASSERT(args.length() == 1);
4979 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004980 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004981 }
4982 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4983
4984 // Skip the global proxy as it has no properties and always delegates to the
4985 // real global object.
4986 if (obj->IsJSGlobalProxy()) {
Leon Clarke4515c472010-02-03 11:58:03 +00004987 // Only collect names if access is permitted.
4988 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004989 !isolate->MayNamedAccess(*obj,
4990 isolate->heap()->undefined_value(),
4991 v8::ACCESS_KEYS)) {
4992 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4993 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00004994 }
Leon Clarkee46be812010-01-19 14:06:41 +00004995 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4996 }
4997
4998 // Find the number of objects making up this.
4999 int length = LocalPrototypeChainLength(*obj);
5000
5001 // Find the number of local properties for each of the objects.
Steve Block6ded16b2010-05-10 14:33:55 +01005002 ScopedVector<int> local_property_count(length);
Leon Clarkee46be812010-01-19 14:06:41 +00005003 int total_property_count = 0;
5004 Handle<JSObject> jsproto = obj;
5005 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00005006 // Only collect names if access is permitted.
5007 if (jsproto->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01005008 !isolate->MayNamedAccess(*jsproto,
5009 isolate->heap()->undefined_value(),
5010 v8::ACCESS_KEYS)) {
5011 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5012 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00005013 }
Leon Clarkee46be812010-01-19 14:06:41 +00005014 int n;
5015 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
5016 local_property_count[i] = n;
5017 total_property_count += n;
5018 if (i < length - 1) {
5019 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5020 }
5021 }
5022
5023 // Allocate an array with storage for all the property names.
Steve Block44f0eee2011-05-26 01:26:41 +01005024 Handle<FixedArray> names =
5025 isolate->factory()->NewFixedArray(total_property_count);
Leon Clarkee46be812010-01-19 14:06:41 +00005026
5027 // Get the property names.
5028 jsproto = obj;
5029 int proto_with_hidden_properties = 0;
Ben Murdoch6d7cb002011-08-04 19:25:22 +01005030 int next_copy_index = 0;
Leon Clarkee46be812010-01-19 14:06:41 +00005031 for (int i = 0; i < length; i++) {
Ben Murdoch6d7cb002011-08-04 19:25:22 +01005032 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5033 next_copy_index += local_property_count[i];
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005034 if (jsproto->HasHiddenProperties()) {
Leon Clarkee46be812010-01-19 14:06:41 +00005035 proto_with_hidden_properties++;
5036 }
5037 if (i < length - 1) {
5038 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5039 }
5040 }
5041
5042 // Filter out name of hidden propeties object.
5043 if (proto_with_hidden_properties > 0) {
5044 Handle<FixedArray> old_names = names;
Steve Block44f0eee2011-05-26 01:26:41 +01005045 names = isolate->factory()->NewFixedArray(
Leon Clarkee46be812010-01-19 14:06:41 +00005046 names->length() - proto_with_hidden_properties);
5047 int dest_pos = 0;
5048 for (int i = 0; i < total_property_count; i++) {
5049 Object* name = old_names->get(i);
Steve Block44f0eee2011-05-26 01:26:41 +01005050 if (name == isolate->heap()->hidden_symbol()) {
Leon Clarkee46be812010-01-19 14:06:41 +00005051 continue;
5052 }
5053 names->set(dest_pos++, name);
5054 }
5055 }
5056
Steve Block44f0eee2011-05-26 01:26:41 +01005057 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00005058}
5059
5060
5061// Return the names of the local indexed properties.
5062// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005063RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005064 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005065 ASSERT(args.length() == 1);
5066 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005067 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005068 }
5069 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5070
5071 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01005072 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
Leon Clarkee46be812010-01-19 14:06:41 +00005073 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01005074 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00005075}
5076
5077
5078// Return information on whether an object has a named or indexed interceptor.
5079// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005080RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01005081 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005082 ASSERT(args.length() == 1);
5083 if (!args[0]->IsJSObject()) {
5084 return Smi::FromInt(0);
5085 }
5086 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5087
5088 int result = 0;
5089 if (obj->HasNamedInterceptor()) result |= 2;
5090 if (obj->HasIndexedInterceptor()) result |= 1;
5091
5092 return Smi::FromInt(result);
5093}
5094
5095
5096// Return property names from named interceptor.
5097// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005098RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005099 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005100 ASSERT(args.length() == 1);
5101 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5102
5103 if (obj->HasNamedInterceptor()) {
5104 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5105 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5106 }
Steve Block44f0eee2011-05-26 01:26:41 +01005107 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005108}
5109
5110
5111// Return element names from indexed interceptor.
5112// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01005113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01005114 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00005115 ASSERT(args.length() == 1);
5116 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5117
5118 if (obj->HasIndexedInterceptor()) {
5119 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5120 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5121 }
Steve Block44f0eee2011-05-26 01:26:41 +01005122 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00005123}
5124
5125
Ben Murdoch8b112d22011-06-08 16:22:53 +01005126RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005127 ASSERT_EQ(args.length(), 1);
5128 CONVERT_CHECKED(JSObject, raw_object, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01005129 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005130 Handle<JSObject> object(raw_object);
Steve Block1e0659c2011-05-24 12:43:12 +01005131
5132 if (object->IsJSGlobalProxy()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005133 // Do access checks before going to the global object.
5134 if (object->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01005135 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005136 v8::ACCESS_KEYS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01005137 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5138 return *isolate->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005139 }
5140
Steve Block1e0659c2011-05-24 12:43:12 +01005141 Handle<Object> proto(object->GetPrototype());
5142 // If proxy is detached we simply return an empty array.
Steve Block44f0eee2011-05-26 01:26:41 +01005143 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
Steve Block1e0659c2011-05-24 12:43:12 +01005144 object = Handle<JSObject>::cast(proto);
5145 }
5146
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005147 bool threw = false;
5148 Handle<FixedArray> contents =
5149 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5150 if (threw) return Failure::Exception();
5151
Steve Blocka7e24c12009-10-30 11:49:00 +00005152 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5153 // property array and since the result is mutable we have to create
5154 // a fresh clone on each invocation.
5155 int length = contents->length();
Steve Block44f0eee2011-05-26 01:26:41 +01005156 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005157 for (int i = 0; i < length; i++) {
5158 Object* entry = contents->get(i);
5159 if (entry->IsString()) {
5160 copy->set(i, entry);
5161 } else {
5162 ASSERT(entry->IsNumber());
Steve Block44f0eee2011-05-26 01:26:41 +01005163 HandleScope scope(isolate);
5164 Handle<Object> entry_handle(entry, isolate);
5165 Handle<Object> entry_str =
5166 isolate->factory()->NumberToString(entry_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +00005167 copy->set(i, *entry_str);
5168 }
5169 }
Steve Block44f0eee2011-05-26 01:26:41 +01005170 return *isolate->factory()->NewJSArrayWithElements(copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00005171}
5172
5173
Ben Murdoch8b112d22011-06-08 16:22:53 +01005174RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005175 NoHandleAllocation ha;
5176 ASSERT(args.length() == 1);
5177
5178 // Compute the frame holding the arguments.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005179 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005180 it.AdvanceToArgumentsFrame();
5181 JavaScriptFrame* frame = it.frame();
5182
5183 // Get the actual number of provided arguments.
Steve Block44f0eee2011-05-26 01:26:41 +01005184 const uint32_t n = frame->ComputeParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00005185
5186 // Try to convert the key to an index. If successful and within
5187 // index return the the argument from the frame.
5188 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005189 if (args[0]->ToArrayIndex(&index) && index < n) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005190 return frame->GetParameter(index);
5191 }
5192
5193 // Convert the key to a string.
Steve Block44f0eee2011-05-26 01:26:41 +01005194 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005195 bool exception = false;
5196 Handle<Object> converted =
5197 Execution::ToString(args.at<Object>(0), &exception);
5198 if (exception) return Failure::Exception();
5199 Handle<String> key = Handle<String>::cast(converted);
5200
5201 // Try to convert the string key into an array index.
5202 if (key->AsArrayIndex(&index)) {
5203 if (index < n) {
5204 return frame->GetParameter(index);
5205 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005206 return isolate->initial_object_prototype()->GetElement(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00005207 }
5208 }
5209
5210 // Handle special arguments properties.
Steve Block44f0eee2011-05-26 01:26:41 +01005211 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5212 if (key->Equals(isolate->heap()->callee_symbol())) {
5213 Object* function = frame->function();
5214 if (function->IsJSFunction() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005215 !JSFunction::cast(function)->shared()->is_classic_mode()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005216 return isolate->Throw(*isolate->factory()->NewTypeError(
5217 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5218 }
5219 return function;
5220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005221
5222 // Lookup in the initial Object.prototype object.
Steve Block44f0eee2011-05-26 01:26:41 +01005223 return isolate->initial_object_prototype()->GetProperty(*key);
Steve Blocka7e24c12009-10-30 11:49:00 +00005224}
5225
5226
Ben Murdoch8b112d22011-06-08 16:22:53 +01005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005228 ASSERT(args.length() == 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +00005229 Object* object = args[0];
5230 return (object->IsJSObject() && !object->IsGlobalObject())
5231 ? JSObject::cast(object)->TransformToFastProperties(0)
5232 : object;
Steve Blocka7e24c12009-10-30 11:49:00 +00005233}
5234
5235
Ben Murdoch8b112d22011-06-08 16:22:53 +01005236RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005237 ASSERT(args.length() == 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +00005238 Object* obj = args[0];
5239 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5240 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5241 : obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00005242}
5243
5244
Ben Murdoch8b112d22011-06-08 16:22:53 +01005245RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005246 NoHandleAllocation ha;
5247 ASSERT(args.length() == 1);
5248
5249 return args[0]->ToBoolean();
5250}
5251
5252
5253// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5254// Possible optimizations: put the type string into the oddballs.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005255RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005256 NoHandleAllocation ha;
5257
5258 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01005259 if (obj->IsNumber()) return isolate->heap()->number_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005260 HeapObject* heap_obj = HeapObject::cast(obj);
5261
5262 // typeof an undetectable object is 'undefined'
Steve Block44f0eee2011-05-26 01:26:41 +01005263 if (heap_obj->map()->is_undetectable()) {
5264 return isolate->heap()->undefined_symbol();
5265 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005266
5267 InstanceType instance_type = heap_obj->map()->instance_type();
5268 if (instance_type < FIRST_NONSTRING_TYPE) {
Steve Block44f0eee2011-05-26 01:26:41 +01005269 return isolate->heap()->string_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005270 }
5271
5272 switch (instance_type) {
5273 case ODDBALL_TYPE:
5274 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005275 return isolate->heap()->boolean_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005276 }
5277 if (heap_obj->IsNull()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005278 return FLAG_harmony_typeof
5279 ? isolate->heap()->null_symbol()
5280 : isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005281 }
5282 ASSERT(heap_obj->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01005283 return isolate->heap()->undefined_symbol();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005284 case JS_FUNCTION_TYPE:
Ben Murdoch589d6972011-11-30 16:04:58 +00005285 case JS_FUNCTION_PROXY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01005286 return isolate->heap()->function_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005287 default:
5288 // For any kind of object not handled above, the spec rule for
5289 // host objects gives that it is okay to return "object"
Steve Block44f0eee2011-05-26 01:26:41 +01005290 return isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00005291 }
5292}
5293
5294
Steve Block6ded16b2010-05-10 14:33:55 +01005295static bool AreDigits(const char*s, int from, int to) {
5296 for (int i = from; i < to; i++) {
5297 if (s[i] < '0' || s[i] > '9') return false;
5298 }
5299
5300 return true;
5301}
5302
5303
5304static int ParseDecimalInteger(const char*s, int from, int to) {
5305 ASSERT(to - from < 10); // Overflow is not possible.
5306 ASSERT(from < to);
5307 int d = s[from] - '0';
5308
5309 for (int i = from + 1; i < to; i++) {
5310 d = 10 * d + (s[i] - '0');
5311 }
5312
5313 return d;
5314}
5315
5316
Ben Murdoch8b112d22011-06-08 16:22:53 +01005317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 1);
5320 CONVERT_CHECKED(String, subject, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01005321 subject->TryFlatten();
5322
5323 // Fast case: short integer or some sorts of junk values.
5324 int len = subject->length();
5325 if (subject->IsSeqAsciiString()) {
5326 if (len == 0) return Smi::FromInt(0);
5327
5328 char const* data = SeqAsciiString::cast(subject)->GetChars();
5329 bool minus = (data[0] == '-');
5330 int start_pos = (minus ? 1 : 0);
5331
5332 if (start_pos == len) {
Steve Block44f0eee2011-05-26 01:26:41 +01005333 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005334 } else if (data[start_pos] > '9') {
5335 // Fast check for a junk value. A valid string may start from a
5336 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5337 // the 'I' character ('Infinity'). All of that have codes not greater than
5338 // '9' except 'I'.
5339 if (data[start_pos] != 'I') {
Steve Block44f0eee2011-05-26 01:26:41 +01005340 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005341 }
5342 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5343 // The maximal/minimal smi has 10 digits. If the string has less digits we
5344 // know it will fit into the smi-data type.
5345 int d = ParseDecimalInteger(data, start_pos, len);
5346 if (minus) {
Steve Block44f0eee2011-05-26 01:26:41 +01005347 if (d == 0) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005348 d = -d;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005349 } else if (!subject->HasHashCode() &&
5350 len <= String::kMaxArrayIndexSize &&
5351 (len == 1 || data[0] != '0')) {
5352 // String hash is not calculated yet but all the data are present.
5353 // Update the hash field to speed up sequential convertions.
Iain Merrick9ac36c92010-09-13 15:29:50 +01005354 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005355#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005356 subject->Hash(); // Force hash calculation.
5357 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5358 static_cast<int>(hash));
5359#endif
5360 subject->set_hash_field(hash);
Steve Block6ded16b2010-05-10 14:33:55 +01005361 }
5362 return Smi::FromInt(d);
5363 }
5364 }
5365
5366 // Slower case.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005367 return isolate->heap()->NumberFromDouble(
5368 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
Steve Blocka7e24c12009-10-30 11:49:00 +00005369}
5370
5371
Ben Murdoch8b112d22011-06-08 16:22:53 +01005372RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005373 NoHandleAllocation ha;
5374 ASSERT(args.length() == 1);
5375
5376 CONVERT_CHECKED(JSArray, codes, args[0]);
5377 int length = Smi::cast(codes->length())->value();
5378
5379 // Check if the string can be ASCII.
5380 int i;
5381 for (i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07005382 Object* element;
5383 { MaybeObject* maybe_element = codes->GetElement(i);
5384 // We probably can't get an exception here, but just in order to enforce
5385 // the checking of inputs in the runtime calls we check here.
5386 if (!maybe_element->ToObject(&element)) return maybe_element;
5387 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005388 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5389 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5390 break;
5391 }
5392
John Reck59135872010-11-02 12:39:01 -07005393 MaybeObject* maybe_object = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00005394 if (i == length) { // The string is ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01005395 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005396 } else { // The string is not ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01005397 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00005398 }
5399
John Reck59135872010-11-02 12:39:01 -07005400 Object* object = NULL;
5401 if (!maybe_object->ToObject(&object)) return maybe_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00005402 String* result = String::cast(object);
5403 for (int i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07005404 Object* element;
5405 { MaybeObject* maybe_element = codes->GetElement(i);
5406 if (!maybe_element->ToObject(&element)) return maybe_element;
5407 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005408 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5409 result->Set(i, chr & 0xffff);
5410 }
5411 return result;
5412}
5413
5414
5415// kNotEscaped is generated by the following:
5416//
5417// #!/bin/perl
5418// for (my $i = 0; $i < 256; $i++) {
5419// print "\n" if $i % 16 == 0;
5420// my $c = chr($i);
5421// my $escaped = 1;
5422// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5423// print $escaped ? "0, " : "1, ";
5424// }
5425
5426
5427static bool IsNotEscaped(uint16_t character) {
5428 // Only for 8 bit characters, the rest are always escaped (in a different way)
5429 ASSERT(character < 256);
5430 static const char kNotEscaped[256] = {
5431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5437 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5447 };
5448 return kNotEscaped[character] != 0;
5449}
5450
5451
Ben Murdoch8b112d22011-06-08 16:22:53 +01005452RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005453 const char hex_chars[] = "0123456789ABCDEF";
5454 NoHandleAllocation ha;
5455 ASSERT(args.length() == 1);
5456 CONVERT_CHECKED(String, source, args[0]);
5457
Steve Block6ded16b2010-05-10 14:33:55 +01005458 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005459
5460 int escaped_length = 0;
5461 int length = source->length();
5462 {
Steve Block44f0eee2011-05-26 01:26:41 +01005463 Access<StringInputBuffer> buffer(
5464 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005465 buffer->Reset(source);
5466 while (buffer->has_more()) {
5467 uint16_t character = buffer->GetNext();
5468 if (character >= 256) {
5469 escaped_length += 6;
5470 } else if (IsNotEscaped(character)) {
5471 escaped_length++;
5472 } else {
5473 escaped_length += 3;
5474 }
Steve Block3ce2e202009-11-05 08:53:23 +00005475 // We don't allow strings that are longer than a maximal length.
Leon Clarkee46be812010-01-19 14:06:41 +00005476 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
Steve Block3ce2e202009-11-05 08:53:23 +00005477 if (escaped_length > String::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +01005478 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00005479 return Failure::OutOfMemoryException();
5480 }
5481 }
5482 }
5483 // No length change implies no change. Return original string if no change.
5484 if (escaped_length == length) {
5485 return source;
5486 }
John Reck59135872010-11-02 12:39:01 -07005487 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01005488 { MaybeObject* maybe_o =
5489 isolate->heap()->AllocateRawAsciiString(escaped_length);
John Reck59135872010-11-02 12:39:01 -07005490 if (!maybe_o->ToObject(&o)) return maybe_o;
5491 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005492 String* destination = String::cast(o);
5493 int dest_position = 0;
5494
Steve Block44f0eee2011-05-26 01:26:41 +01005495 Access<StringInputBuffer> buffer(
5496 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005497 buffer->Rewind();
5498 while (buffer->has_more()) {
5499 uint16_t chr = buffer->GetNext();
5500 if (chr >= 256) {
5501 destination->Set(dest_position, '%');
5502 destination->Set(dest_position+1, 'u');
5503 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5504 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5505 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5506 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
5507 dest_position += 6;
5508 } else if (IsNotEscaped(chr)) {
5509 destination->Set(dest_position, chr);
5510 dest_position++;
5511 } else {
5512 destination->Set(dest_position, '%');
5513 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5514 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
5515 dest_position += 3;
5516 }
5517 }
5518 return destination;
5519}
5520
5521
5522static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5523 static const signed char kHexValue['g'] = {
5524 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5525 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5528 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5529 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5530 -1, 10, 11, 12, 13, 14, 15 };
5531
5532 if (character1 > 'f') return -1;
5533 int hi = kHexValue[character1];
5534 if (hi == -1) return -1;
5535 if (character2 > 'f') return -1;
5536 int lo = kHexValue[character2];
5537 if (lo == -1) return -1;
5538 return (hi << 4) + lo;
5539}
5540
5541
5542static inline int Unescape(String* source,
5543 int i,
5544 int length,
5545 int* step) {
5546 uint16_t character = source->Get(i);
5547 int32_t hi = 0;
5548 int32_t lo = 0;
5549 if (character == '%' &&
5550 i <= length - 6 &&
5551 source->Get(i + 1) == 'u' &&
5552 (hi = TwoDigitHex(source->Get(i + 2),
5553 source->Get(i + 3))) != -1 &&
5554 (lo = TwoDigitHex(source->Get(i + 4),
5555 source->Get(i + 5))) != -1) {
5556 *step = 6;
5557 return (hi << 8) + lo;
5558 } else if (character == '%' &&
5559 i <= length - 3 &&
5560 (lo = TwoDigitHex(source->Get(i + 1),
5561 source->Get(i + 2))) != -1) {
5562 *step = 3;
5563 return lo;
5564 } else {
5565 *step = 1;
5566 return character;
5567 }
5568}
5569
5570
Ben Murdoch8b112d22011-06-08 16:22:53 +01005571RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005572 NoHandleAllocation ha;
5573 ASSERT(args.length() == 1);
5574 CONVERT_CHECKED(String, source, args[0]);
5575
Steve Block6ded16b2010-05-10 14:33:55 +01005576 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005577
5578 bool ascii = true;
5579 int length = source->length();
5580
5581 int unescaped_length = 0;
5582 for (int i = 0; i < length; unescaped_length++) {
5583 int step;
5584 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
5585 ascii = false;
5586 }
5587 i += step;
5588 }
5589
5590 // No length change implies no change. Return original string if no change.
5591 if (unescaped_length == length)
5592 return source;
5593
John Reck59135872010-11-02 12:39:01 -07005594 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01005595 { MaybeObject* maybe_o =
5596 ascii ?
5597 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5598 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
John Reck59135872010-11-02 12:39:01 -07005599 if (!maybe_o->ToObject(&o)) return maybe_o;
5600 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005601 String* destination = String::cast(o);
5602
5603 int dest_position = 0;
5604 for (int i = 0; i < length; dest_position++) {
5605 int step;
5606 destination->Set(dest_position, Unescape(source, i, length, &step));
5607 i += step;
5608 }
5609 return destination;
5610}
5611
5612
Ben Murdochb0fe1622011-05-05 13:52:32 +01005613static const unsigned int kQuoteTableLength = 128u;
5614
5615static const int kJsonQuotesCharactersPerEntry = 8;
5616static const char* const JsonQuotes =
5617 "\\u0000 \\u0001 \\u0002 \\u0003 "
5618 "\\u0004 \\u0005 \\u0006 \\u0007 "
5619 "\\b \\t \\n \\u000b "
5620 "\\f \\r \\u000e \\u000f "
5621 "\\u0010 \\u0011 \\u0012 \\u0013 "
5622 "\\u0014 \\u0015 \\u0016 \\u0017 "
5623 "\\u0018 \\u0019 \\u001a \\u001b "
5624 "\\u001c \\u001d \\u001e \\u001f "
5625 " ! \\\" # "
5626 "$ % & ' "
5627 "( ) * + "
5628 ", - . / "
5629 "0 1 2 3 "
5630 "4 5 6 7 "
5631 "8 9 : ; "
5632 "< = > ? "
5633 "@ A B C "
5634 "D E F G "
5635 "H I J K "
5636 "L M N O "
5637 "P Q R S "
5638 "T U V W "
5639 "X Y Z [ "
5640 "\\\\ ] ^ _ "
5641 "` a b c "
5642 "d e f g "
5643 "h i j k "
5644 "l m n o "
5645 "p q r s "
5646 "t u v w "
5647 "x y z { "
5648 "| } ~ \177 ";
5649
5650
5651// For a string that is less than 32k characters it should always be
5652// possible to allocate it in new space.
5653static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5654
5655
5656// Doing JSON quoting cannot make the string more than this many times larger.
5657static const int kJsonQuoteWorstCaseBlowup = 6;
5658
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005659static const int kSpaceForQuotesAndComma = 3;
5660static const int kSpaceForBrackets = 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005661
5662// Covers the entire ASCII range (all other characters are unchanged by JSON
5663// quoting).
5664static const byte JsonQuoteLengths[kQuoteTableLength] = {
5665 6, 6, 6, 6, 6, 6, 6, 6,
5666 2, 2, 2, 6, 2, 2, 6, 6,
5667 6, 6, 6, 6, 6, 6, 6, 6,
5668 6, 6, 6, 6, 6, 6, 6, 6,
5669 1, 1, 2, 1, 1, 1, 1, 1,
5670 1, 1, 1, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 1, 1, 1, 1,
5674 1, 1, 1, 1, 1, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 2, 1, 1, 1,
5677 1, 1, 1, 1, 1, 1, 1, 1,
5678 1, 1, 1, 1, 1, 1, 1, 1,
5679 1, 1, 1, 1, 1, 1, 1, 1,
5680 1, 1, 1, 1, 1, 1, 1, 1,
5681};
5682
5683
5684template <typename StringType>
Steve Block44f0eee2011-05-26 01:26:41 +01005685MaybeObject* AllocateRawString(Isolate* isolate, int length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005686
5687
5688template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005689MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5690 return isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005691}
5692
5693
5694template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005695MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5696 return isolate->heap()->AllocateRawAsciiString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005697}
5698
5699
Ben Murdochb8e0da22011-05-16 14:20:40 +01005700template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005701static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5702 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005703 int length = characters.length();
5704 const Char* read_cursor = characters.start();
5705 const Char* end = read_cursor + length;
Ben Murdochb8e0da22011-05-16 14:20:40 +01005706 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005707 int quoted_length = kSpaceForQuotes;
5708 while (read_cursor < end) {
5709 Char c = *(read_cursor++);
5710 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5711 quoted_length++;
5712 } else {
5713 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
5714 }
5715 }
Steve Block44f0eee2011-05-26 01:26:41 +01005716 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5717 quoted_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005718 Object* new_object;
5719 if (!new_alloc->ToObject(&new_object)) {
5720 return new_alloc;
5721 }
5722 StringType* new_string = StringType::cast(new_object);
5723
5724 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005725 new_string->address() + SeqString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005726 if (comma) *(write_cursor++) = ',';
Ben Murdochb0fe1622011-05-05 13:52:32 +01005727 *(write_cursor++) = '"';
5728
5729 read_cursor = characters.start();
5730 while (read_cursor < end) {
5731 Char c = *(read_cursor++);
5732 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5733 *(write_cursor++) = c;
5734 } else {
5735 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5736 const char* replacement = JsonQuotes +
5737 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5738 for (int i = 0; i < len; i++) {
5739 *write_cursor++ = *replacement++;
5740 }
5741 }
5742 }
5743 *(write_cursor++) = '"';
5744 return new_string;
5745}
5746
5747
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005748template <typename SinkChar, typename SourceChar>
5749static inline SinkChar* WriteQuoteJsonString(
5750 Isolate* isolate,
5751 SinkChar* write_cursor,
5752 Vector<const SourceChar> characters) {
5753 // SinkChar is only char if SourceChar is guaranteed to be char.
5754 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
5755 const SourceChar* read_cursor = characters.start();
5756 const SourceChar* end = read_cursor + characters.length();
5757 *(write_cursor++) = '"';
5758 while (read_cursor < end) {
5759 SourceChar c = *(read_cursor++);
5760 if (sizeof(SourceChar) > 1u &&
5761 static_cast<unsigned>(c) >= kQuoteTableLength) {
5762 *(write_cursor++) = static_cast<SinkChar>(c);
5763 } else {
5764 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5765 const char* replacement = JsonQuotes +
5766 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5767 write_cursor[0] = replacement[0];
5768 if (len > 1) {
5769 write_cursor[1] = replacement[1];
5770 if (len > 2) {
5771 ASSERT(len == 6);
5772 write_cursor[2] = replacement[2];
5773 write_cursor[3] = replacement[3];
5774 write_cursor[4] = replacement[4];
5775 write_cursor[5] = replacement[5];
5776 }
5777 }
5778 write_cursor += len;
5779 }
5780 }
5781 *(write_cursor++) = '"';
5782 return write_cursor;
5783}
5784
5785
Ben Murdochb8e0da22011-05-16 14:20:40 +01005786template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005787static MaybeObject* QuoteJsonString(Isolate* isolate,
5788 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005789 int length = characters.length();
Steve Block44f0eee2011-05-26 01:26:41 +01005790 isolate->counters()->quote_json_char_count()->Increment(length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005791 int worst_case_length =
5792 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
Ben Murdochb0fe1622011-05-05 13:52:32 +01005793 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
Steve Block44f0eee2011-05-26 01:26:41 +01005794 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005795 }
5796
Steve Block44f0eee2011-05-26 01:26:41 +01005797 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5798 worst_case_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005799 Object* new_object;
5800 if (!new_alloc->ToObject(&new_object)) {
5801 return new_alloc;
5802 }
Steve Block44f0eee2011-05-26 01:26:41 +01005803 if (!isolate->heap()->new_space()->Contains(new_object)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005804 // Even if our string is small enough to fit in new space we still have to
5805 // handle it being allocated in old space as may happen in the third
5806 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5807 // CEntryStub::GenerateCore.
Steve Block44f0eee2011-05-26 01:26:41 +01005808 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005809 }
5810 StringType* new_string = StringType::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01005811 ASSERT(isolate->heap()->new_space()->Contains(new_string));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005812
Ben Murdochb0fe1622011-05-05 13:52:32 +01005813 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005814 new_string->address() + SeqString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005815 if (comma) *(write_cursor++) = ',';
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005816 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5817 write_cursor,
5818 characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005819 int final_length = static_cast<int>(
5820 write_cursor - reinterpret_cast<Char*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005821 new_string->address() + SeqString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01005822 isolate->heap()->new_space()->
5823 template ShrinkStringAtAllocationBoundary<StringType>(
5824 new_string, final_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005825 return new_string;
5826}
5827
5828
Ben Murdoch8b112d22011-06-08 16:22:53 +01005829RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005830 NoHandleAllocation ha;
5831 CONVERT_CHECKED(String, str, args[0]);
5832 if (!str->IsFlat()) {
5833 MaybeObject* try_flatten = str->TryFlatten();
5834 Object* flat;
5835 if (!try_flatten->ToObject(&flat)) {
5836 return try_flatten;
5837 }
5838 str = String::cast(flat);
5839 ASSERT(str->IsFlat());
5840 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005841 String::FlatContent flat = str->GetFlatContent();
5842 ASSERT(flat.IsFlat());
5843 if (flat.IsTwoByte()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005844 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005845 flat.ToUC16Vector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005846 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005847 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005848 flat.ToAsciiVector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005849 }
5850}
5851
5852
Ben Murdoch8b112d22011-06-08 16:22:53 +01005853RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01005854 NoHandleAllocation ha;
5855 CONVERT_CHECKED(String, str, args[0]);
5856 if (!str->IsFlat()) {
5857 MaybeObject* try_flatten = str->TryFlatten();
5858 Object* flat;
5859 if (!try_flatten->ToObject(&flat)) {
5860 return try_flatten;
5861 }
5862 str = String::cast(flat);
5863 ASSERT(str->IsFlat());
5864 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005865 String::FlatContent flat = str->GetFlatContent();
5866 if (flat.IsTwoByte()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005867 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005868 flat.ToUC16Vector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005869 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005870 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005871 flat.ToAsciiVector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005872 }
5873}
5874
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005875
5876template <typename Char, typename StringType>
5877static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5878 FixedArray* array,
5879 int worst_case_length) {
5880 int length = array->length();
5881
5882 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5883 worst_case_length);
5884 Object* new_object;
5885 if (!new_alloc->ToObject(&new_object)) {
5886 return new_alloc;
5887 }
5888 if (!isolate->heap()->new_space()->Contains(new_object)) {
5889 // Even if our string is small enough to fit in new space we still have to
5890 // handle it being allocated in old space as may happen in the third
5891 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5892 // CEntryStub::GenerateCore.
5893 return isolate->heap()->undefined_value();
5894 }
5895 AssertNoAllocation no_gc;
5896 StringType* new_string = StringType::cast(new_object);
5897 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5898
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005899 Char* write_cursor = reinterpret_cast<Char*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005900 new_string->address() + SeqString::kHeaderSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005901 *(write_cursor++) = '[';
5902 for (int i = 0; i < length; i++) {
5903 if (i != 0) *(write_cursor++) = ',';
5904 String* str = String::cast(array->get(i));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005905 String::FlatContent content = str->GetFlatContent();
5906 ASSERT(content.IsFlat());
5907 if (content.IsTwoByte()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005908 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5909 write_cursor,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005910 content.ToUC16Vector());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005911 } else {
5912 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5913 write_cursor,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005914 content.ToAsciiVector());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005915 }
5916 }
5917 *(write_cursor++) = ']';
5918
5919 int final_length = static_cast<int>(
5920 write_cursor - reinterpret_cast<Char*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005921 new_string->address() + SeqString::kHeaderSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005922 isolate->heap()->new_space()->
5923 template ShrinkStringAtAllocationBoundary<StringType>(
5924 new_string, final_length);
5925 return new_string;
5926}
5927
5928
5929RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5930 NoHandleAllocation ha;
5931 ASSERT(args.length() == 1);
5932 CONVERT_CHECKED(JSArray, array, args[0]);
5933
5934 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5935 FixedArray* elements = FixedArray::cast(array->elements());
5936 int n = elements->length();
5937 bool ascii = true;
5938 int total_length = 0;
5939
5940 for (int i = 0; i < n; i++) {
5941 Object* elt = elements->get(i);
5942 if (!elt->IsString()) return isolate->heap()->undefined_value();
5943 String* element = String::cast(elt);
5944 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5945 total_length += element->length();
5946 if (ascii && element->IsTwoByteRepresentation()) {
5947 ascii = false;
5948 }
5949 }
5950
5951 int worst_case_length =
5952 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5953 + total_length * kJsonQuoteWorstCaseBlowup;
5954
5955 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5956 return isolate->heap()->undefined_value();
5957 }
5958
5959 if (ascii) {
5960 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5961 elements,
5962 worst_case_length);
5963 } else {
5964 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5965 elements,
5966 worst_case_length);
5967 }
5968}
5969
5970
Ben Murdoch8b112d22011-06-08 16:22:53 +01005971RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005972 NoHandleAllocation ha;
5973
5974 CONVERT_CHECKED(String, s, args[0]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005975 CONVERT_SMI_ARG_CHECKED(radix, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00005976
Steve Block6ded16b2010-05-10 14:33:55 +01005977 s->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005978
Steve Block6ded16b2010-05-10 14:33:55 +01005979 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
Ben Murdoch8b112d22011-06-08 16:22:53 +01005980 double value = StringToInt(isolate->unicode_cache(), s, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01005981 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005982}
5983
5984
Ben Murdoch8b112d22011-06-08 16:22:53 +01005985RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005986 NoHandleAllocation ha;
5987 CONVERT_CHECKED(String, str, args[0]);
5988
5989 // ECMA-262 section 15.1.2.3, empty string is NaN
Ben Murdoch8b112d22011-06-08 16:22:53 +01005990 double value = StringToDouble(isolate->unicode_cache(),
5991 str, ALLOW_TRAILING_JUNK, OS::nan_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005992
5993 // Create a number object from the value.
Steve Block44f0eee2011-05-26 01:26:41 +01005994 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005995}
5996
5997
Steve Blocka7e24c12009-10-30 11:49:00 +00005998template <class Converter>
John Reck59135872010-11-02 12:39:01 -07005999MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01006000 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07006001 String* s,
6002 int length,
6003 int input_string_length,
6004 unibrow::Mapping<Converter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006005 // We try this twice, once with the assumption that the result is no longer
6006 // than the input and, if that assumption breaks, again with the exact
6007 // length. This may not be pretty, but it is nicer than what was here before
6008 // and I hereby claim my vaffel-is.
6009 //
6010 // Allocate the resulting string.
6011 //
Ben Murdochc7cc0282012-03-05 14:35:55 +00006012 // NOTE: This assumes that the upper/lower case of an ASCII
6013 // character is also ASCII. This is currently the case, but it
Steve Blocka7e24c12009-10-30 11:49:00 +00006014 // might break in the future if we implement more context and locale
6015 // dependent upper/lower conversions.
John Reck59135872010-11-02 12:39:01 -07006016 Object* o;
6017 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
Steve Block44f0eee2011-05-26 01:26:41 +01006018 ? isolate->heap()->AllocateRawAsciiString(length)
6019 : isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07006020 if (!maybe_o->ToObject(&o)) return maybe_o;
6021 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006022 String* result = String::cast(o);
6023 bool has_changed_character = false;
6024
6025 // Convert all characters to upper case, assuming that they will fit
6026 // in the buffer
Steve Block44f0eee2011-05-26 01:26:41 +01006027 Access<StringInputBuffer> buffer(
6028 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00006029 buffer->Reset(s);
6030 unibrow::uchar chars[Converter::kMaxWidth];
6031 // We can assume that the string is not empty
6032 uc32 current = buffer->GetNext();
6033 for (int i = 0; i < length;) {
6034 bool has_next = buffer->has_more();
6035 uc32 next = has_next ? buffer->GetNext() : 0;
6036 int char_length = mapping->get(current, next, chars);
6037 if (char_length == 0) {
6038 // The case conversion of this character is the character itself.
6039 result->Set(i, current);
6040 i++;
6041 } else if (char_length == 1) {
6042 // Common case: converting the letter resulted in one character.
6043 ASSERT(static_cast<uc32>(chars[0]) != current);
6044 result->Set(i, chars[0]);
6045 has_changed_character = true;
6046 i++;
6047 } else if (length == input_string_length) {
6048 // We've assumed that the result would be as long as the
6049 // input but here is a character that converts to several
6050 // characters. No matter, we calculate the exact length
6051 // of the result and try the whole thing again.
6052 //
6053 // Note that this leaves room for optimization. We could just
6054 // memcpy what we already have to the result string. Also,
6055 // the result string is the last object allocated we could
6056 // "realloc" it and probably, in the vast majority of cases,
6057 // extend the existing string to be able to hold the full
6058 // result.
6059 int next_length = 0;
6060 if (has_next) {
6061 next_length = mapping->get(next, 0, chars);
6062 if (next_length == 0) next_length = 1;
6063 }
6064 int current_length = i + char_length + next_length;
6065 while (buffer->has_more()) {
6066 current = buffer->GetNext();
6067 // NOTE: we use 0 as the next character here because, while
6068 // the next character may affect what a character converts to,
6069 // it does not in any case affect the length of what it convert
6070 // to.
6071 int char_length = mapping->get(current, 0, chars);
6072 if (char_length == 0) char_length = 1;
6073 current_length += char_length;
6074 if (current_length > Smi::kMaxValue) {
Steve Block44f0eee2011-05-26 01:26:41 +01006075 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00006076 return Failure::OutOfMemoryException();
6077 }
6078 }
6079 // Try again with the real length.
6080 return Smi::FromInt(current_length);
6081 } else {
6082 for (int j = 0; j < char_length; j++) {
6083 result->Set(i, chars[j]);
6084 i++;
6085 }
6086 has_changed_character = true;
6087 }
6088 current = next;
6089 }
6090 if (has_changed_character) {
6091 return result;
6092 } else {
6093 // If we didn't actually change anything in doing the conversion
6094 // we simple return the result and let the converted string
6095 // become garbage; there is no reason to keep two identical strings
6096 // alive.
6097 return s;
6098 }
6099}
6100
6101
Steve Block6ded16b2010-05-10 14:33:55 +01006102namespace {
6103
John Reck59135872010-11-02 12:39:01 -07006104static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6105
6106
6107// Given a word and two range boundaries returns a word with high bit
6108// set in every byte iff the corresponding input byte was strictly in
6109// the range (m, n). All the other bits in the result are cleared.
6110// This function is only useful when it can be inlined and the
6111// boundaries are statically known.
6112// Requires: all bytes in the input word and the boundaries must be
Ben Murdochc7cc0282012-03-05 14:35:55 +00006113// ASCII (less than 0x7F).
John Reck59135872010-11-02 12:39:01 -07006114static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00006115 // Every byte in an ASCII string is less than or equal to 0x7F.
John Reck59135872010-11-02 12:39:01 -07006116 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6117 // Use strict inequalities since in edge cases the function could be
6118 // further simplified.
6119 ASSERT(0 < m && m < n && n < 0x7F);
6120 // Has high bit set in every w byte less than n.
6121 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6122 // Has high bit set in every w byte greater than m.
6123 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6124 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6125}
6126
6127
6128enum AsciiCaseConversion {
6129 ASCII_TO_LOWER,
6130 ASCII_TO_UPPER
6131};
6132
6133
6134template <AsciiCaseConversion dir>
6135struct FastAsciiConverter {
6136 static bool Convert(char* dst, char* src, int length) {
6137#ifdef DEBUG
6138 char* saved_dst = dst;
6139 char* saved_src = src;
6140#endif
6141 // We rely on the distance between upper and lower case letters
6142 // being a known power of 2.
6143 ASSERT('a' - 'A' == (1 << 5));
6144 // Boundaries for the range of input characters than require conversion.
6145 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6146 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6147 bool changed = false;
6148 char* const limit = src + length;
6149#ifdef V8_HOST_CAN_READ_UNALIGNED
6150 // Process the prefix of the input that requires no conversion one
6151 // (machine) word at a time.
6152 while (src <= limit - sizeof(uintptr_t)) {
6153 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6154 if (AsciiRangeMask(w, lo, hi) != 0) {
6155 changed = true;
6156 break;
6157 }
6158 *reinterpret_cast<uintptr_t*>(dst) = w;
6159 src += sizeof(uintptr_t);
6160 dst += sizeof(uintptr_t);
6161 }
6162 // Process the remainder of the input performing conversion when
6163 // required one word at a time.
6164 while (src <= limit - sizeof(uintptr_t)) {
6165 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6166 uintptr_t m = AsciiRangeMask(w, lo, hi);
6167 // The mask has high (7th) bit set in every byte that needs
6168 // conversion and we know that the distance between cases is
6169 // 1 << 5.
6170 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6171 src += sizeof(uintptr_t);
6172 dst += sizeof(uintptr_t);
6173 }
6174#endif
6175 // Process the last few bytes of the input (or the whole input if
6176 // unaligned access is not supported).
6177 while (src < limit) {
6178 char c = *src;
6179 if (lo < c && c < hi) {
6180 c ^= (1 << 5);
6181 changed = true;
6182 }
6183 *dst = c;
6184 ++src;
6185 ++dst;
6186 }
6187#ifdef DEBUG
6188 CheckConvert(saved_dst, saved_src, length, changed);
6189#endif
6190 return changed;
6191 }
6192
6193#ifdef DEBUG
6194 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6195 bool expected_changed = false;
6196 for (int i = 0; i < length; i++) {
6197 if (dst[i] == src[i]) continue;
6198 expected_changed = true;
6199 if (dir == ASCII_TO_LOWER) {
6200 ASSERT('A' <= src[i] && src[i] <= 'Z');
6201 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6202 } else {
6203 ASSERT(dir == ASCII_TO_UPPER);
6204 ASSERT('a' <= src[i] && src[i] <= 'z');
6205 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6206 }
6207 }
6208 ASSERT(expected_changed == changed);
6209 }
6210#endif
6211};
6212
6213
Steve Block6ded16b2010-05-10 14:33:55 +01006214struct ToLowerTraits {
6215 typedef unibrow::ToLowercase UnibrowConverter;
6216
John Reck59135872010-11-02 12:39:01 -07006217 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01006218};
6219
6220
6221struct ToUpperTraits {
6222 typedef unibrow::ToUppercase UnibrowConverter;
6223
John Reck59135872010-11-02 12:39:01 -07006224 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01006225};
6226
6227} // namespace
6228
6229
6230template <typename ConvertTraits>
John Reck59135872010-11-02 12:39:01 -07006231MUST_USE_RESULT static MaybeObject* ConvertCase(
Steve Block6ded16b2010-05-10 14:33:55 +01006232 Arguments args,
Steve Block44f0eee2011-05-26 01:26:41 +01006233 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01006234 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006235 NoHandleAllocation ha;
Steve Blocka7e24c12009-10-30 11:49:00 +00006236 CONVERT_CHECKED(String, s, args[0]);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006237 s = s->TryFlattenGetString();
Steve Blocka7e24c12009-10-30 11:49:00 +00006238
Steve Block6ded16b2010-05-10 14:33:55 +01006239 const int length = s->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00006240 // Assume that the string is not empty; we need this assumption later
Steve Block6ded16b2010-05-10 14:33:55 +01006241 if (length == 0) return s;
6242
Ben Murdochc7cc0282012-03-05 14:35:55 +00006243 // Simpler handling of ASCII strings.
Steve Block6ded16b2010-05-10 14:33:55 +01006244 //
Ben Murdochc7cc0282012-03-05 14:35:55 +00006245 // NOTE: This assumes that the upper/lower case of an ASCII
6246 // character is also ASCII. This is currently the case, but it
Steve Block6ded16b2010-05-10 14:33:55 +01006247 // might break in the future if we implement more context and locale
6248 // dependent upper/lower conversions.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006249 if (s->IsSeqAsciiString()) {
John Reck59135872010-11-02 12:39:01 -07006250 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01006251 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07006252 if (!maybe_o->ToObject(&o)) return maybe_o;
6253 }
Steve Block6ded16b2010-05-10 14:33:55 +01006254 SeqAsciiString* result = SeqAsciiString::cast(o);
John Reck59135872010-11-02 12:39:01 -07006255 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006256 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
Steve Block6ded16b2010-05-10 14:33:55 +01006257 return has_changed_character ? result : s;
6258 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006259
John Reck59135872010-11-02 12:39:01 -07006260 Object* answer;
Steve Block44f0eee2011-05-26 01:26:41 +01006261 { MaybeObject* maybe_answer =
6262 ConvertCaseHelper(isolate, s, length, length, mapping);
John Reck59135872010-11-02 12:39:01 -07006263 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6264 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006265 if (answer->IsSmi()) {
6266 // Retry with correct length.
John Reck59135872010-11-02 12:39:01 -07006267 { MaybeObject* maybe_answer =
Steve Block44f0eee2011-05-26 01:26:41 +01006268 ConvertCaseHelper(isolate,
6269 s, Smi::cast(answer)->value(), length, mapping);
John Reck59135872010-11-02 12:39:01 -07006270 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6271 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006272 }
John Reck59135872010-11-02 12:39:01 -07006273 return answer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006274}
6275
6276
Ben Murdoch8b112d22011-06-08 16:22:53 +01006277RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01006278 return ConvertCase<ToLowerTraits>(
6279 args, isolate, isolate->runtime_state()->to_lower_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00006280}
6281
6282
Ben Murdoch8b112d22011-06-08 16:22:53 +01006283RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01006284 return ConvertCase<ToUpperTraits>(
6285 args, isolate, isolate->runtime_state()->to_upper_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00006286}
6287
Steve Block6ded16b2010-05-10 14:33:55 +01006288
Steve Block3ce2e202009-11-05 08:53:23 +00006289static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006290 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
Steve Block3ce2e202009-11-05 08:53:23 +00006291}
6292
Steve Block6ded16b2010-05-10 14:33:55 +01006293
Ben Murdoch8b112d22011-06-08 16:22:53 +01006294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
Steve Block3ce2e202009-11-05 08:53:23 +00006295 NoHandleAllocation ha;
6296 ASSERT(args.length() == 3);
6297
6298 CONVERT_CHECKED(String, s, args[0]);
6299 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6300 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6301
Steve Block6ded16b2010-05-10 14:33:55 +01006302 s->TryFlatten();
Steve Block3ce2e202009-11-05 08:53:23 +00006303 int length = s->length();
6304
6305 int left = 0;
6306 if (trimLeft) {
6307 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6308 left++;
6309 }
6310 }
6311
6312 int right = length;
6313 if (trimRight) {
6314 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6315 right--;
6316 }
6317 }
Steve Blockd0582a62009-12-15 09:54:21 +00006318 return s->SubString(left, right);
Steve Block3ce2e202009-11-05 08:53:23 +00006319}
Steve Blocka7e24c12009-10-30 11:49:00 +00006320
Steve Block6ded16b2010-05-10 14:33:55 +01006321
Ben Murdoch8b112d22011-06-08 16:22:53 +01006322RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
Steve Block6ded16b2010-05-10 14:33:55 +01006323 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +01006324 HandleScope handle_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01006325 CONVERT_ARG_CHECKED(String, subject, 0);
6326 CONVERT_ARG_CHECKED(String, pattern, 1);
6327 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6328
6329 int subject_length = subject->length();
6330 int pattern_length = pattern->length();
6331 RUNTIME_ASSERT(pattern_length > 0);
6332
Ben Murdoch589d6972011-11-30 16:04:58 +00006333 if (limit == 0xffffffffu) {
6334 Handle<Object> cached_answer(StringSplitCache::Lookup(
6335 isolate->heap()->string_split_cache(),
6336 *subject,
6337 *pattern));
6338 if (*cached_answer != Smi::FromInt(0)) {
6339 Handle<JSArray> result =
6340 isolate->factory()->NewJSArrayWithElements(
6341 Handle<FixedArray>::cast(cached_answer));
6342 return *result;
6343 }
6344 }
6345
Steve Block6ded16b2010-05-10 14:33:55 +01006346 // The limit can be very large (0xffffffffu), but since the pattern
6347 // isn't empty, we can never create more parts than ~half the length
6348 // of the subject.
6349
6350 if (!subject->IsFlat()) FlattenString(subject);
6351
6352 static const int kMaxInitialListCapacity = 16;
6353
Ben Murdoch257744e2011-11-30 15:57:28 +00006354 ZoneScope scope(isolate, DELETE_ON_EXIT);
Steve Block6ded16b2010-05-10 14:33:55 +01006355
6356 // Find (up to limit) indices of separator and end-of-string in subject
6357 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6358 ZoneList<int> indices(initial_capacity);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006359 if (!pattern->IsFlat()) FlattenString(pattern);
6360
Ben Murdoch589d6972011-11-30 16:04:58 +00006361 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006362
Steve Block6ded16b2010-05-10 14:33:55 +01006363 if (static_cast<uint32_t>(indices.length()) < limit) {
6364 indices.Add(subject_length);
6365 }
Steve Block6ded16b2010-05-10 14:33:55 +01006366
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006367 // The list indices now contains the end of each part to create.
Steve Block6ded16b2010-05-10 14:33:55 +01006368
6369 // Create JSArray of substrings separated by separator.
6370 int part_count = indices.length();
6371
Steve Block44f0eee2011-05-26 01:26:41 +01006372 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006373 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006374 if (maybe_result->IsFailure()) return maybe_result;
Steve Block6ded16b2010-05-10 14:33:55 +01006375 result->set_length(Smi::FromInt(part_count));
6376
6377 ASSERT(result->HasFastElements());
6378
6379 if (part_count == 1 && indices.at(0) == subject_length) {
6380 FixedArray::cast(result->elements())->set(0, *subject);
6381 return *result;
6382 }
6383
6384 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6385 int part_start = 0;
6386 for (int i = 0; i < part_count; i++) {
6387 HandleScope local_loop_handle;
6388 int part_end = indices.at(i);
6389 Handle<String> substring =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006390 isolate->factory()->NewProperSubString(subject, part_start, part_end);
Steve Block6ded16b2010-05-10 14:33:55 +01006391 elements->set(i, *substring);
6392 part_start = part_end + pattern_length;
6393 }
6394
Ben Murdoch589d6972011-11-30 16:04:58 +00006395 if (limit == 0xffffffffu) {
6396 if (result->HasFastElements()) {
6397 StringSplitCache::Enter(isolate->heap(),
6398 isolate->heap()->string_split_cache(),
6399 *subject,
6400 *pattern,
6401 *elements);
6402 }
6403 }
6404
Steve Block6ded16b2010-05-10 14:33:55 +01006405 return *result;
6406}
6407
6408
Ben Murdochc7cc0282012-03-05 14:35:55 +00006409// Copies ASCII characters to the given fixed array looking up
Steve Block6ded16b2010-05-10 14:33:55 +01006410// one-char strings in the cache. Gives up on the first char that is
6411// not in the cache and fills the remainder with smi zeros. Returns
6412// the length of the successfully copied prefix.
Steve Block44f0eee2011-05-26 01:26:41 +01006413static int CopyCachedAsciiCharsToArray(Heap* heap,
6414 const char* chars,
Steve Block6ded16b2010-05-10 14:33:55 +01006415 FixedArray* elements,
6416 int length) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006417 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +01006418 FixedArray* ascii_cache = heap->single_character_string_cache();
6419 Object* undefined = heap->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01006420 int i;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006421 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Block6ded16b2010-05-10 14:33:55 +01006422 for (i = 0; i < length; ++i) {
6423 Object* value = ascii_cache->get(chars[i]);
6424 if (value == undefined) break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006425 elements->set(i, value, mode);
Steve Block6ded16b2010-05-10 14:33:55 +01006426 }
6427 if (i < length) {
6428 ASSERT(Smi::FromInt(0) == 0);
6429 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6430 }
6431#ifdef DEBUG
6432 for (int j = 0; j < length; ++j) {
6433 Object* element = elements->get(j);
6434 ASSERT(element == Smi::FromInt(0) ||
6435 (element->IsString() && String::cast(element)->LooksValid()));
6436 }
6437#endif
6438 return i;
6439}
6440
6441
6442// Converts a String to JSArray.
6443// For example, "foo" => ["f", "o", "o"].
Ben Murdoch8b112d22011-06-08 16:22:53 +01006444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
Steve Block44f0eee2011-05-26 01:26:41 +01006445 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006446 ASSERT(args.length() == 2);
Steve Block6ded16b2010-05-10 14:33:55 +01006447 CONVERT_ARG_CHECKED(String, s, 0);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006448 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Steve Block6ded16b2010-05-10 14:33:55 +01006449
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006450 s = FlattenGetString(s);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006451 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
Steve Block6ded16b2010-05-10 14:33:55 +01006452
6453 Handle<FixedArray> elements;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006454 int position = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01006455 if (s->IsFlat() && s->IsAsciiRepresentation()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006456 // Try using cached chars where possible.
John Reck59135872010-11-02 12:39:01 -07006457 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006458 { MaybeObject* maybe_obj =
6459 isolate->heap()->AllocateUninitializedFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07006460 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6461 }
Steve Block44f0eee2011-05-26 01:26:41 +01006462 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006463 String::FlatContent content = s->GetFlatContent();
6464 if (content.IsAscii()) {
6465 Vector<const char> chars = content.ToAsciiVector();
6466 // Note, this will initialize all elements (not only the prefix)
6467 // to prevent GC from seeing partially initialized array.
6468 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6469 chars.start(),
6470 *elements,
6471 length);
6472 } else {
6473 MemsetPointer(elements->data_start(),
6474 isolate->heap()->undefined_value(),
6475 length);
Steve Block6ded16b2010-05-10 14:33:55 +01006476 }
6477 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006478 elements = isolate->factory()->NewFixedArray(length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006479 }
6480 for (int i = position; i < length; ++i) {
6481 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6482 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01006483 }
6484
6485#ifdef DEBUG
6486 for (int i = 0; i < length; ++i) {
6487 ASSERT(String::cast(elements->get(i))->length() == 1);
6488 }
6489#endif
6490
Steve Block44f0eee2011-05-26 01:26:41 +01006491 return *isolate->factory()->NewJSArrayWithElements(elements);
Steve Block6ded16b2010-05-10 14:33:55 +01006492}
6493
6494
Ben Murdoch8b112d22011-06-08 16:22:53 +01006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498 CONVERT_CHECKED(String, value, args[0]);
6499 return value->ToObject();
6500}
6501
6502
Steve Block44f0eee2011-05-26 01:26:41 +01006503bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006504 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
Steve Block44f0eee2011-05-26 01:26:41 +01006505 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006506 return char_length == 0;
6507}
6508
6509
Ben Murdoch8b112d22011-06-08 16:22:53 +01006510RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006511 NoHandleAllocation ha;
6512 ASSERT(args.length() == 1);
6513
6514 Object* number = args[0];
6515 RUNTIME_ASSERT(number->IsNumber());
6516
Steve Block44f0eee2011-05-26 01:26:41 +01006517 return isolate->heap()->NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00006518}
6519
6520
Ben Murdoch8b112d22011-06-08 16:22:53 +01006521RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
Steve Block6ded16b2010-05-10 14:33:55 +01006522 NoHandleAllocation ha;
6523 ASSERT(args.length() == 1);
6524
6525 Object* number = args[0];
6526 RUNTIME_ASSERT(number->IsNumber());
6527
Steve Block44f0eee2011-05-26 01:26:41 +01006528 return isolate->heap()->NumberToString(number, false);
Steve Block6ded16b2010-05-10 14:33:55 +01006529}
6530
6531
Ben Murdoch8b112d22011-06-08 16:22:53 +01006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006536 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01006537
6538 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6539 if (number > 0 && number <= Smi::kMaxValue) {
6540 return Smi::FromInt(static_cast<int>(number));
6541 }
Steve Block44f0eee2011-05-26 01:26:41 +01006542 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00006543}
6544
6545
Ben Murdoch8b112d22011-06-08 16:22:53 +01006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 1);
6549
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006550 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006551
6552 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6553 if (number > 0 && number <= Smi::kMaxValue) {
6554 return Smi::FromInt(static_cast<int>(number));
6555 }
6556
6557 double double_value = DoubleToInteger(number);
6558 // Map both -0 and +0 to +0.
6559 if (double_value == 0) double_value = 0;
6560
Steve Block44f0eee2011-05-26 01:26:41 +01006561 return isolate->heap()->NumberFromDouble(double_value);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006562}
6563
6564
Ben Murdoch8b112d22011-06-08 16:22:53 +01006565RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006566 NoHandleAllocation ha;
6567 ASSERT(args.length() == 1);
6568
Steve Block6ded16b2010-05-10 14:33:55 +01006569 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006570 return isolate->heap()->NumberFromUint32(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00006571}
6572
6573
Ben Murdoch8b112d22011-06-08 16:22:53 +01006574RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006575 NoHandleAllocation ha;
6576 ASSERT(args.length() == 1);
6577
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006578 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01006579
6580 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6581 if (number > 0 && number <= Smi::kMaxValue) {
6582 return Smi::FromInt(static_cast<int>(number));
6583 }
Steve Block44f0eee2011-05-26 01:26:41 +01006584 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00006585}
6586
6587
6588// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6589// a small integer.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006590RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 1);
6593
6594 Object* obj = args[0];
6595 if (obj->IsSmi()) {
6596 return obj;
6597 }
6598 if (obj->IsHeapNumber()) {
6599 double value = HeapNumber::cast(obj)->value();
6600 int int_value = FastD2I(value);
6601 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6602 return Smi::FromInt(int_value);
6603 }
6604 }
Steve Block44f0eee2011-05-26 01:26:41 +01006605 return isolate->heap()->nan_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006606}
6607
6608
Ben Murdoch8b112d22011-06-08 16:22:53 +01006609RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01006612 return isolate->heap()->AllocateHeapNumber(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006613}
6614
6615
Ben Murdoch8b112d22011-06-08 16:22:53 +01006616RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
6619
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6621 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006622 return isolate->heap()->NumberFromDouble(x + y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006623}
6624
6625
Ben Murdoch8b112d22011-06-08 16:22:53 +01006626RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 2);
6629
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006630 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6631 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006632 return isolate->heap()->NumberFromDouble(x - y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006633}
6634
6635
Ben Murdoch8b112d22011-06-08 16:22:53 +01006636RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 2);
6639
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6641 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006642 return isolate->heap()->NumberFromDouble(x * y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006643}
6644
6645
Ben Murdoch8b112d22011-06-08 16:22:53 +01006646RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006647 NoHandleAllocation ha;
6648 ASSERT(args.length() == 1);
6649
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006650 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01006651 return isolate->heap()->NumberFromDouble(-x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006652}
6653
6654
Ben Murdoch8b112d22011-06-08 16:22:53 +01006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 0);
6658
Steve Block44f0eee2011-05-26 01:26:41 +01006659 return isolate->heap()->NumberFromDouble(9876543210.0);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006660}
6661
6662
Ben Murdoch8b112d22011-06-08 16:22:53 +01006663RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006664 NoHandleAllocation ha;
6665 ASSERT(args.length() == 2);
6666
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006667 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6668 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006669 return isolate->heap()->NumberFromDouble(x / y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006670}
6671
6672
Ben Murdoch8b112d22011-06-08 16:22:53 +01006673RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006674 NoHandleAllocation ha;
6675 ASSERT(args.length() == 2);
6676
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006677 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6678 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00006679
Steve Block3ce2e202009-11-05 08:53:23 +00006680 x = modulo(x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01006681 // NumberFromDouble may return a Smi instead of a Number object
Steve Block44f0eee2011-05-26 01:26:41 +01006682 return isolate->heap()->NumberFromDouble(x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006683}
6684
6685
Ben Murdoch8b112d22011-06-08 16:22:53 +01006686RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006687 NoHandleAllocation ha;
6688 ASSERT(args.length() == 2);
6689 CONVERT_CHECKED(String, str1, args[0]);
6690 CONVERT_CHECKED(String, str2, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006691 isolate->counters()->string_add_runtime()->Increment();
6692 return isolate->heap()->AllocateConsString(str1, str2);
Steve Blocka7e24c12009-10-30 11:49:00 +00006693}
6694
6695
Steve Block6ded16b2010-05-10 14:33:55 +01006696template <typename sinkchar>
Steve Blocka7e24c12009-10-30 11:49:00 +00006697static inline void StringBuilderConcatHelper(String* special,
6698 sinkchar* sink,
6699 FixedArray* fixed_array,
6700 int array_length) {
6701 int position = 0;
6702 for (int i = 0; i < array_length; i++) {
6703 Object* element = fixed_array->get(i);
6704 if (element->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006705 // Smi encoding of position and length.
Steve Blocka7e24c12009-10-30 11:49:00 +00006706 int encoded_slice = Smi::cast(element)->value();
Steve Blockd0582a62009-12-15 09:54:21 +00006707 int pos;
6708 int len;
6709 if (encoded_slice > 0) {
6710 // Position and length encoded in one smi.
6711 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6712 len = StringBuilderSubstringLength::decode(encoded_slice);
6713 } else {
6714 // Position and length encoded in two smis.
6715 Object* obj = fixed_array->get(++i);
6716 ASSERT(obj->IsSmi());
6717 pos = Smi::cast(obj)->value();
6718 len = -encoded_slice;
6719 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006720 String::WriteToFlat(special,
6721 sink + position,
6722 pos,
6723 pos + len);
6724 position += len;
6725 } else {
6726 String* string = String::cast(element);
6727 int element_length = string->length();
6728 String::WriteToFlat(string, sink + position, 0, element_length);
6729 position += element_length;
6730 }
6731 }
6732}
6733
6734
Ben Murdoch8b112d22011-06-08 16:22:53 +01006735RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006736 NoHandleAllocation ha;
Leon Clarkee46be812010-01-19 14:06:41 +00006737 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00006738 CONVERT_CHECKED(JSArray, array, args[0]);
Leon Clarkee46be812010-01-19 14:06:41 +00006739 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006740 isolate->context()->mark_out_of_memory();
Leon Clarkee46be812010-01-19 14:06:41 +00006741 return Failure::OutOfMemoryException();
6742 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006743 int array_length = args.smi_at(1);
Leon Clarkee46be812010-01-19 14:06:41 +00006744 CONVERT_CHECKED(String, special, args[2]);
Steve Blockd0582a62009-12-15 09:54:21 +00006745
6746 // This assumption is used by the slice encoding in one or two smis.
6747 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6748
Ben Murdochc7cc0282012-03-05 14:35:55 +00006749 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006750 if (maybe_result->IsFailure()) return maybe_result;
6751
Steve Blocka7e24c12009-10-30 11:49:00 +00006752 int special_length = special->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00006753 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006754 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00006755 }
6756 FixedArray* fixed_array = FixedArray::cast(array->elements());
6757 if (fixed_array->length() < array_length) {
6758 array_length = fixed_array->length();
6759 }
6760
6761 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006762 return isolate->heap()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00006763 } else if (array_length == 1) {
6764 Object* first = fixed_array->get(0);
6765 if (first->IsString()) return first;
6766 }
6767
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006768 bool ascii = special->HasOnlyAsciiChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006769 int position = 0;
6770 for (int i = 0; i < array_length; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01006771 int increment = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006772 Object* elt = fixed_array->get(i);
6773 if (elt->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006774 // Smi encoding of position and length.
Steve Block6ded16b2010-05-10 14:33:55 +01006775 int smi_value = Smi::cast(elt)->value();
6776 int pos;
6777 int len;
6778 if (smi_value > 0) {
Steve Blockd0582a62009-12-15 09:54:21 +00006779 // Position and length encoded in one smi.
Steve Block6ded16b2010-05-10 14:33:55 +01006780 pos = StringBuilderSubstringPosition::decode(smi_value);
6781 len = StringBuilderSubstringLength::decode(smi_value);
Steve Blockd0582a62009-12-15 09:54:21 +00006782 } else {
6783 // Position and length encoded in two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01006784 len = -smi_value;
6785 // Get the position and check that it is a positive smi.
Steve Blockd0582a62009-12-15 09:54:21 +00006786 i++;
6787 if (i >= array_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006788 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006789 }
Steve Block6ded16b2010-05-10 14:33:55 +01006790 Object* next_smi = fixed_array->get(i);
6791 if (!next_smi->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006792 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006793 }
6794 pos = Smi::cast(next_smi)->value();
6795 if (pos < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006796 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006797 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006798 }
Steve Block6ded16b2010-05-10 14:33:55 +01006799 ASSERT(pos >= 0);
6800 ASSERT(len >= 0);
6801 if (pos > special_length || len > special_length - pos) {
Steve Block44f0eee2011-05-26 01:26:41 +01006802 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006803 }
6804 increment = len;
Steve Blocka7e24c12009-10-30 11:49:00 +00006805 } else if (elt->IsString()) {
6806 String* element = String::cast(elt);
6807 int element_length = element->length();
Leon Clarkee46be812010-01-19 14:06:41 +00006808 increment = element_length;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006809 if (ascii && !element->HasOnlyAsciiChars()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006810 ascii = false;
6811 }
6812 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006813 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00006814 }
Leon Clarkee46be812010-01-19 14:06:41 +00006815 if (increment > String::kMaxLength - position) {
Steve Block44f0eee2011-05-26 01:26:41 +01006816 isolate->context()->mark_out_of_memory();
Steve Block3ce2e202009-11-05 08:53:23 +00006817 return Failure::OutOfMemoryException();
6818 }
Leon Clarkee46be812010-01-19 14:06:41 +00006819 position += increment;
Steve Blocka7e24c12009-10-30 11:49:00 +00006820 }
6821
6822 int length = position;
6823 Object* object;
6824
6825 if (ascii) {
Steve Block44f0eee2011-05-26 01:26:41 +01006826 { MaybeObject* maybe_object =
6827 isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07006828 if (!maybe_object->ToObject(&object)) return maybe_object;
6829 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006830 SeqAsciiString* answer = SeqAsciiString::cast(object);
6831 StringBuilderConcatHelper(special,
6832 answer->GetChars(),
6833 fixed_array,
6834 array_length);
6835 return answer;
6836 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006837 { MaybeObject* maybe_object =
6838 isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07006839 if (!maybe_object->ToObject(&object)) return maybe_object;
6840 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006841 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6842 StringBuilderConcatHelper(special,
6843 answer->GetChars(),
6844 fixed_array,
6845 array_length);
6846 return answer;
6847 }
6848}
6849
6850
Ben Murdoch8b112d22011-06-08 16:22:53 +01006851RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006852 NoHandleAllocation ha;
6853 ASSERT(args.length() == 3);
6854 CONVERT_CHECKED(JSArray, array, args[0]);
6855 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006856 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006857 return Failure::OutOfMemoryException();
6858 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006859 int array_length = args.smi_at(1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006860 CONVERT_CHECKED(String, separator, args[2]);
6861
6862 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006863 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006864 }
6865 FixedArray* fixed_array = FixedArray::cast(array->elements());
6866 if (fixed_array->length() < array_length) {
6867 array_length = fixed_array->length();
6868 }
6869
6870 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006871 return isolate->heap()->empty_string();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006872 } else if (array_length == 1) {
6873 Object* first = fixed_array->get(0);
6874 if (first->IsString()) return first;
6875 }
6876
6877 int separator_length = separator->length();
6878 int max_nof_separators =
6879 (String::kMaxLength + separator_length - 1) / separator_length;
6880 if (max_nof_separators < (array_length - 1)) {
Steve Block44f0eee2011-05-26 01:26:41 +01006881 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006882 return Failure::OutOfMemoryException();
6883 }
6884 int length = (array_length - 1) * separator_length;
6885 for (int i = 0; i < array_length; i++) {
6886 Object* element_obj = fixed_array->get(i);
6887 if (!element_obj->IsString()) {
6888 // TODO(1161): handle this case.
Steve Block44f0eee2011-05-26 01:26:41 +01006889 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006890 }
6891 String* element = String::cast(element_obj);
6892 int increment = element->length();
6893 if (increment > String::kMaxLength - length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006894 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006895 return Failure::OutOfMemoryException();
6896 }
6897 length += increment;
6898 }
6899
6900 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +01006901 { MaybeObject* maybe_object =
6902 isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006903 if (!maybe_object->ToObject(&object)) return maybe_object;
6904 }
6905 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6906
6907 uc16* sink = answer->GetChars();
6908#ifdef DEBUG
6909 uc16* end = sink + length;
6910#endif
6911
6912 String* first = String::cast(fixed_array->get(0));
6913 int first_length = first->length();
6914 String::WriteToFlat(first, sink, 0, first_length);
6915 sink += first_length;
6916
6917 for (int i = 1; i < array_length; i++) {
6918 ASSERT(sink + separator_length <= end);
6919 String::WriteToFlat(separator, sink, 0, separator_length);
6920 sink += separator_length;
6921
6922 String* element = String::cast(fixed_array->get(i));
6923 int element_length = element->length();
6924 ASSERT(sink + element_length <= end);
6925 String::WriteToFlat(element, sink, 0, element_length);
6926 sink += element_length;
6927 }
6928 ASSERT(sink == end);
6929
6930 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6931 return answer;
6932}
6933
Ben Murdoch257744e2011-11-30 15:57:28 +00006934template <typename Char>
6935static void JoinSparseArrayWithSeparator(FixedArray* elements,
6936 int elements_length,
6937 uint32_t array_length,
6938 String* separator,
6939 Vector<Char> buffer) {
6940 int previous_separator_position = 0;
6941 int separator_length = separator->length();
6942 int cursor = 0;
6943 for (int i = 0; i < elements_length; i += 2) {
6944 int position = NumberToInt32(elements->get(i));
6945 String* string = String::cast(elements->get(i + 1));
6946 int string_length = string->length();
6947 if (string->length() > 0) {
6948 while (previous_separator_position < position) {
6949 String::WriteToFlat<Char>(separator, &buffer[cursor],
6950 0, separator_length);
6951 cursor += separator_length;
6952 previous_separator_position++;
6953 }
6954 String::WriteToFlat<Char>(string, &buffer[cursor],
6955 0, string_length);
6956 cursor += string->length();
6957 }
6958 }
6959 if (separator_length > 0) {
6960 // Array length must be representable as a signed 32-bit number,
6961 // otherwise the total string length would have been too large.
6962 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6963 int last_array_index = static_cast<int>(array_length - 1);
6964 while (previous_separator_position < last_array_index) {
6965 String::WriteToFlat<Char>(separator, &buffer[cursor],
6966 0, separator_length);
6967 cursor += separator_length;
6968 previous_separator_position++;
6969 }
6970 }
6971 ASSERT(cursor <= buffer.length());
6972}
6973
6974
6975RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 3);
6978 CONVERT_CHECKED(JSArray, elements_array, args[0]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006979 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6980 elements_array->HasFastSmiOnlyElements());
Ben Murdoch257744e2011-11-30 15:57:28 +00006981 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6982 CONVERT_CHECKED(String, separator, args[2]);
6983 // elements_array is fast-mode JSarray of alternating positions
6984 // (increasing order) and strings.
6985 // array_length is length of original array (used to add separators);
6986 // separator is string to put between elements. Assumed to be non-empty.
6987
6988 // Find total length of join result.
6989 int string_length = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006990 bool is_ascii = separator->IsAsciiRepresentation();
Ben Murdoch589d6972011-11-30 16:04:58 +00006991 int max_string_length;
6992 if (is_ascii) {
6993 max_string_length = SeqAsciiString::kMaxLength;
6994 } else {
6995 max_string_length = SeqTwoByteString::kMaxLength;
6996 }
Ben Murdoch257744e2011-11-30 15:57:28 +00006997 bool overflow = false;
6998 CONVERT_NUMBER_CHECKED(int, elements_length,
6999 Int32, elements_array->length());
7000 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7001 FixedArray* elements = FixedArray::cast(elements_array->elements());
7002 for (int i = 0; i < elements_length; i += 2) {
7003 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7004 CONVERT_CHECKED(String, string, elements->get(i + 1));
7005 int length = string->length();
7006 if (is_ascii && !string->IsAsciiRepresentation()) {
7007 is_ascii = false;
7008 max_string_length = SeqTwoByteString::kMaxLength;
7009 }
7010 if (length > max_string_length ||
7011 max_string_length - length < string_length) {
7012 overflow = true;
7013 break;
7014 }
7015 string_length += length;
7016 }
7017 int separator_length = separator->length();
7018 if (!overflow && separator_length > 0) {
7019 if (array_length <= 0x7fffffffu) {
7020 int separator_count = static_cast<int>(array_length) - 1;
7021 int remaining_length = max_string_length - string_length;
7022 if ((remaining_length / separator_length) >= separator_count) {
7023 string_length += separator_length * (array_length - 1);
7024 } else {
7025 // Not room for the separators within the maximal string length.
7026 overflow = true;
7027 }
7028 } else {
7029 // Nonempty separator and at least 2^31-1 separators necessary
7030 // means that the string is too large to create.
7031 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7032 overflow = true;
7033 }
7034 }
7035 if (overflow) {
7036 // Throw OutOfMemory exception for creating too large a string.
7037 V8::FatalProcessOutOfMemory("Array join result too large.");
7038 }
7039
7040 if (is_ascii) {
7041 MaybeObject* result_allocation =
7042 isolate->heap()->AllocateRawAsciiString(string_length);
7043 if (result_allocation->IsFailure()) return result_allocation;
7044 SeqAsciiString* result_string =
7045 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7046 JoinSparseArrayWithSeparator<char>(elements,
7047 elements_length,
7048 array_length,
7049 separator,
7050 Vector<char>(result_string->GetChars(),
7051 string_length));
7052 return result_string;
7053 } else {
7054 MaybeObject* result_allocation =
7055 isolate->heap()->AllocateRawTwoByteString(string_length);
7056 if (result_allocation->IsFailure()) return result_allocation;
7057 SeqTwoByteString* result_string =
7058 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7059 JoinSparseArrayWithSeparator<uc16>(elements,
7060 elements_length,
7061 array_length,
7062 separator,
7063 Vector<uc16>(result_string->GetChars(),
7064 string_length));
7065 return result_string;
7066 }
7067}
7068
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007069
Ben Murdoch8b112d22011-06-08 16:22:53 +01007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007076 return isolate->heap()->NumberFromInt32(x | y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007077}
7078
7079
Ben Murdoch8b112d22011-06-08 16:22:53 +01007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007086 return isolate->heap()->NumberFromInt32(x & y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007087}
7088
7089
Ben Murdoch8b112d22011-06-08 16:22:53 +01007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7095 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007096 return isolate->heap()->NumberFromInt32(x ^ y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007097}
7098
7099
Ben Murdoch8b112d22011-06-08 16:22:53 +01007100RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 1);
7103
7104 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01007105 return isolate->heap()->NumberFromInt32(~x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007106}
7107
7108
Ben Murdoch8b112d22011-06-08 16:22:53 +01007109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
7113 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7114 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007115 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007116}
7117
7118
Ben Murdoch8b112d22011-06-08 16:22:53 +01007119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007120 NoHandleAllocation ha;
7121 ASSERT(args.length() == 2);
7122
7123 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7124 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007125 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007126}
7127
7128
Ben Murdoch8b112d22011-06-08 16:22:53 +01007129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 2);
7132
7133 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7134 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01007135 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00007136}
7137
7138
Ben Murdoch8b112d22011-06-08 16:22:53 +01007139RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007140 NoHandleAllocation ha;
7141 ASSERT(args.length() == 2);
7142
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007143 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7144 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007145 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7146 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7147 if (x == y) return Smi::FromInt(EQUAL);
7148 Object* result;
7149 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7150 result = Smi::FromInt(EQUAL);
7151 } else {
7152 result = Smi::FromInt(NOT_EQUAL);
7153 }
7154 return result;
7155}
7156
7157
Ben Murdoch8b112d22011-06-08 16:22:53 +01007158RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007159 NoHandleAllocation ha;
7160 ASSERT(args.length() == 2);
7161
7162 CONVERT_CHECKED(String, x, args[0]);
7163 CONVERT_CHECKED(String, y, args[1]);
7164
7165 bool not_equal = !x->Equals(y);
7166 // This is slightly convoluted because the value that signifies
7167 // equality is 0 and inequality is 1 so we have to negate the result
7168 // from String::Equals.
7169 ASSERT(not_equal == 0 || not_equal == 1);
7170 STATIC_CHECK(EQUAL == 0);
7171 STATIC_CHECK(NOT_EQUAL == 1);
7172 return Smi::FromInt(not_equal);
7173}
7174
7175
Ben Murdoch8b112d22011-06-08 16:22:53 +01007176RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007177 NoHandleAllocation ha;
7178 ASSERT(args.length() == 3);
7179
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007180 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7181 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007182 if (isnan(x) || isnan(y)) return args[2];
7183 if (x == y) return Smi::FromInt(EQUAL);
7184 if (isless(x, y)) return Smi::FromInt(LESS);
7185 return Smi::FromInt(GREATER);
7186}
7187
7188
7189// Compare two Smis as if they were converted to strings and then
7190// compared lexicographically.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007191RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007192 NoHandleAllocation ha;
7193 ASSERT(args.length() == 2);
7194
Steve Blocka7e24c12009-10-30 11:49:00 +00007195 // Extract the integer values from the Smis.
7196 CONVERT_CHECKED(Smi, x, args[0]);
7197 CONVERT_CHECKED(Smi, y, args[1]);
7198 int x_value = x->value();
7199 int y_value = y->value();
7200
7201 // If the integers are equal so are the string representations.
7202 if (x_value == y_value) return Smi::FromInt(EQUAL);
7203
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007204 // If one of the integers is zero the normal integer order is the
Steve Blocka7e24c12009-10-30 11:49:00 +00007205 // same as the lexicographic order of the string representations.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007206 if (x_value == 0 || y_value == 0)
7207 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
Steve Blocka7e24c12009-10-30 11:49:00 +00007208
7209 // If only one of the integers is negative the negative number is
7210 // smallest because the char code of '-' is less than the char code
7211 // of any digit. Otherwise, we make both values positive.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007212
7213 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7214 // architectures using 32-bit Smis.
7215 uint32_t x_scaled = x_value;
7216 uint32_t y_scaled = y_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007217 if (x_value < 0 || y_value < 0) {
7218 if (y_value >= 0) return Smi::FromInt(LESS);
7219 if (x_value >= 0) return Smi::FromInt(GREATER);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007220 x_scaled = -x_value;
7221 y_scaled = -y_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007222 }
7223
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007224 static const uint32_t kPowersOf10[] = {
7225 1, 10, 100, 1000, 10*1000, 100*1000,
7226 1000*1000, 10*1000*1000, 100*1000*1000,
7227 1000*1000*1000
7228 };
Steve Block44f0eee2011-05-26 01:26:41 +01007229
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007230 // If the integers have the same number of decimal digits they can be
7231 // compared directly as the numeric order is the same as the
7232 // lexicographic order. If one integer has fewer digits, it is scaled
7233 // by some power of 10 to have the same number of digits as the longer
7234 // integer. If the scaled integers are equal it means the shorter
7235 // integer comes first in the lexicographic order.
Steve Block44f0eee2011-05-26 01:26:41 +01007236
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007237 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7238 int x_log2 = IntegerLog2(x_scaled);
7239 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7240 x_log10 -= x_scaled < kPowersOf10[x_log10];
7241
7242 int y_log2 = IntegerLog2(y_scaled);
7243 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7244 y_log10 -= y_scaled < kPowersOf10[y_log10];
7245
7246 int tie = EQUAL;
7247
7248 if (x_log10 < y_log10) {
7249 // X has fewer digits. We would like to simply scale up X but that
7250 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7251 // be scaled up to 9_000_000_000. So we scale up by the next
7252 // smallest power and scale down Y to drop one digit. It is OK to
7253 // drop one digit from the longer integer since the final digit is
7254 // past the length of the shorter integer.
7255 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7256 y_scaled /= 10;
7257 tie = LESS;
7258 } else if (y_log10 < x_log10) {
7259 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7260 x_scaled /= 10;
7261 tie = GREATER;
Steve Blocka7e24c12009-10-30 11:49:00 +00007262 }
7263
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007264 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7265 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7266 return Smi::FromInt(tie);
Steve Blocka7e24c12009-10-30 11:49:00 +00007267}
7268
7269
Steve Block44f0eee2011-05-26 01:26:41 +01007270static Object* StringInputBufferCompare(RuntimeState* state,
7271 String* x,
7272 String* y) {
7273 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7274 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
Steve Block6ded16b2010-05-10 14:33:55 +01007275 bufx.Reset(x);
7276 bufy.Reset(y);
7277 while (bufx.has_more() && bufy.has_more()) {
7278 int d = bufx.GetNext() - bufy.GetNext();
7279 if (d < 0) return Smi::FromInt(LESS);
7280 else if (d > 0) return Smi::FromInt(GREATER);
7281 }
7282
7283 // x is (non-trivial) prefix of y:
7284 if (bufy.has_more()) return Smi::FromInt(LESS);
7285 // y is prefix of x:
7286 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7287}
7288
7289
7290static Object* FlatStringCompare(String* x, String* y) {
7291 ASSERT(x->IsFlat());
7292 ASSERT(y->IsFlat());
7293 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7294 int prefix_length = x->length();
7295 if (y->length() < prefix_length) {
7296 prefix_length = y->length();
7297 equal_prefix_result = Smi::FromInt(GREATER);
7298 } else if (y->length() > prefix_length) {
7299 equal_prefix_result = Smi::FromInt(LESS);
7300 }
7301 int r;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007302 String::FlatContent x_content = x->GetFlatContent();
7303 String::FlatContent y_content = y->GetFlatContent();
7304 if (x_content.IsAscii()) {
7305 Vector<const char> x_chars = x_content.ToAsciiVector();
7306 if (y_content.IsAscii()) {
7307 Vector<const char> y_chars = y_content.ToAsciiVector();
Steve Block6ded16b2010-05-10 14:33:55 +01007308 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7309 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007310 Vector<const uc16> y_chars = y_content.ToUC16Vector();
Steve Block6ded16b2010-05-10 14:33:55 +01007311 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7312 }
7313 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007314 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7315 if (y_content.IsAscii()) {
7316 Vector<const char> y_chars = y_content.ToAsciiVector();
Steve Block6ded16b2010-05-10 14:33:55 +01007317 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7318 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007319 Vector<const uc16> y_chars = y_content.ToUC16Vector();
Steve Block6ded16b2010-05-10 14:33:55 +01007320 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7321 }
7322 }
7323 Object* result;
7324 if (r == 0) {
7325 result = equal_prefix_result;
7326 } else {
7327 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7328 }
Steve Block44f0eee2011-05-26 01:26:41 +01007329 ASSERT(result ==
7330 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
Steve Block6ded16b2010-05-10 14:33:55 +01007331 return result;
7332}
7333
7334
Ben Murdoch8b112d22011-06-08 16:22:53 +01007335RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007336 NoHandleAllocation ha;
7337 ASSERT(args.length() == 2);
7338
7339 CONVERT_CHECKED(String, x, args[0]);
7340 CONVERT_CHECKED(String, y, args[1]);
7341
Steve Block44f0eee2011-05-26 01:26:41 +01007342 isolate->counters()->string_compare_runtime()->Increment();
Leon Clarkee46be812010-01-19 14:06:41 +00007343
Steve Blocka7e24c12009-10-30 11:49:00 +00007344 // A few fast case tests before we flatten.
7345 if (x == y) return Smi::FromInt(EQUAL);
7346 if (y->length() == 0) {
7347 if (x->length() == 0) return Smi::FromInt(EQUAL);
7348 return Smi::FromInt(GREATER);
7349 } else if (x->length() == 0) {
7350 return Smi::FromInt(LESS);
7351 }
7352
7353 int d = x->Get(0) - y->Get(0);
7354 if (d < 0) return Smi::FromInt(LESS);
7355 else if (d > 0) return Smi::FromInt(GREATER);
7356
John Reck59135872010-11-02 12:39:01 -07007357 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007358 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
John Reck59135872010-11-02 12:39:01 -07007359 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7360 }
Steve Block44f0eee2011-05-26 01:26:41 +01007361 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
John Reck59135872010-11-02 12:39:01 -07007362 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7363 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007364
Steve Block6ded16b2010-05-10 14:33:55 +01007365 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
Steve Block44f0eee2011-05-26 01:26:41 +01007366 : StringInputBufferCompare(isolate->runtime_state(), x, y);
Steve Blocka7e24c12009-10-30 11:49:00 +00007367}
7368
7369
Ben Murdoch8b112d22011-06-08 16:22:53 +01007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007373 isolate->counters()->math_acos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007374
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007376 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007377}
7378
7379
Ben Murdoch8b112d22011-06-08 16:22:53 +01007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007383 isolate->counters()->math_asin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007384
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007386 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007387}
7388
7389
Ben Murdoch8b112d22011-06-08 16:22:53 +01007390RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007391 NoHandleAllocation ha;
7392 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007393 isolate->counters()->math_atan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007394
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007395 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007396 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007397}
7398
7399
Steve Block44f0eee2011-05-26 01:26:41 +01007400static const double kPiDividedBy4 = 0.78539816339744830962;
7401
7402
Ben Murdoch8b112d22011-06-08 16:22:53 +01007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01007406 isolate->counters()->math_atan2()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007407
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7409 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00007410 double result;
7411 if (isinf(x) && isinf(y)) {
7412 // Make sure that the result in case of two infinite arguments
7413 // is a multiple of Pi / 4. The sign of the result is determined
7414 // by the first argument (x) and the sign of the second argument
7415 // determines the multiplier: one or three.
Steve Blocka7e24c12009-10-30 11:49:00 +00007416 int multiplier = (x < 0) ? -1 : 1;
7417 if (y < 0) multiplier *= 3;
7418 result = multiplier * kPiDividedBy4;
7419 } else {
7420 result = atan2(x, y);
7421 }
Steve Block44f0eee2011-05-26 01:26:41 +01007422 return isolate->heap()->AllocateHeapNumber(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007423}
7424
7425
Ben Murdoch8b112d22011-06-08 16:22:53 +01007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007429 isolate->counters()->math_ceil()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007430
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007432 return isolate->heap()->NumberFromDouble(ceiling(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007433}
7434
7435
Ben Murdoch8b112d22011-06-08 16:22:53 +01007436RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007437 NoHandleAllocation ha;
7438 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007439 isolate->counters()->math_cos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007440
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007442 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007443}
7444
7445
Ben Murdoch8b112d22011-06-08 16:22:53 +01007446RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007447 NoHandleAllocation ha;
7448 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007449 isolate->counters()->math_exp()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007450
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007451 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007452 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007453}
7454
7455
Ben Murdoch8b112d22011-06-08 16:22:53 +01007456RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007459 isolate->counters()->math_floor()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007460
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007461 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007462 return isolate->heap()->NumberFromDouble(floor(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007463}
7464
7465
Ben Murdoch8b112d22011-06-08 16:22:53 +01007466RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007467 NoHandleAllocation ha;
7468 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007469 isolate->counters()->math_log()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007470
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007471 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007472 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007473}
7474
Ben Murdochc7cc0282012-03-05 14:35:55 +00007475// Slow version of Math.pow. We check for fast paths for special cases.
7476// Used if SSE2/VFP3 is not available.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007477RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01007480 isolate->counters()->math_pow()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007481
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00007483
7484 // If the second argument is a smi, it is much faster to call the
7485 // custom powi() function than the generic pow().
7486 if (args[1]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007487 int y = args.smi_at(1);
Steve Block44f0eee2011-05-26 01:26:41 +01007488 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00007489 }
7490
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007491 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007492 int y_int = static_cast<int>(y);
7493 double result;
7494 if (y == y_int) {
7495 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7496 } else if (y == 0.5) {
7497 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7498 } else if (y == -0.5) {
7499 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7500 } else {
7501 result = power_double_double(x, y);
7502 }
7503 if (isnan(result)) return isolate->heap()->nan_value();
7504 return isolate->heap()->AllocateHeapNumber(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007505}
7506
Ben Murdochc7cc0282012-03-05 14:35:55 +00007507// Fast version of Math.pow if we know that y is not an integer and y is not
7508// -0.5 or 0.5. Used as slow case from full codegen.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
Steve Block6ded16b2010-05-10 14:33:55 +01007510 NoHandleAllocation ha;
7511 ASSERT(args.length() == 2);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007512 isolate->counters()->math_pow()->Increment();
7513
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007514 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7515 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
Steve Block6ded16b2010-05-10 14:33:55 +01007516 if (y == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007517 return Smi::FromInt(1);
Steve Block6ded16b2010-05-10 14:33:55 +01007518 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007519 double result = power_double_double(x, y);
7520 if (isnan(result)) return isolate->heap()->nan_value();
7521 return isolate->heap()->AllocateHeapNumber(result);
Steve Block6ded16b2010-05-10 14:33:55 +01007522 }
7523}
Steve Blocka7e24c12009-10-30 11:49:00 +00007524
Steve Block6ded16b2010-05-10 14:33:55 +01007525
Ben Murdoch8b112d22011-06-08 16:22:53 +01007526RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007527 NoHandleAllocation ha;
7528 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007529 isolate->counters()->math_round()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007530
Steve Block6ded16b2010-05-10 14:33:55 +01007531 if (!args[0]->IsHeapNumber()) {
7532 // Must be smi. Return the argument unchanged for all the other types
7533 // to make fuzz-natives test happy.
7534 return args[0];
7535 }
7536
7537 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7538
7539 double value = number->value();
7540 int exponent = number->get_exponent();
7541 int sign = number->get_sign();
7542
Ben Murdoch257744e2011-11-30 15:57:28 +00007543 if (exponent < -1) {
7544 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7545 if (sign) return isolate->heap()->minus_zero_value();
7546 return Smi::FromInt(0);
7547 }
7548
7549 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7550 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
Ben Murdochc7cc0282012-03-05 14:35:55 +00007551 // argument holds for 32-bit smis).
Ben Murdoch257744e2011-11-30 15:57:28 +00007552 if (!sign && exponent < kSmiValueSize - 2) {
Steve Block6ded16b2010-05-10 14:33:55 +01007553 return Smi::FromInt(static_cast<int>(value + 0.5));
7554 }
7555
7556 // If the magnitude is big enough, there's no place for fraction part. If we
7557 // try to add 0.5 to this number, 1.0 will be added instead.
7558 if (exponent >= 52) {
7559 return number;
7560 }
7561
Steve Block44f0eee2011-05-26 01:26:41 +01007562 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007563
7564 // Do not call NumberFromDouble() to avoid extra checks.
Steve Block44f0eee2011-05-26 01:26:41 +01007565 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
Steve Blocka7e24c12009-10-30 11:49:00 +00007566}
7567
7568
Ben Murdoch8b112d22011-06-08 16:22:53 +01007569RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007570 NoHandleAllocation ha;
7571 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007572 isolate->counters()->math_sin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007573
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007574 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007575 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007576}
7577
7578
Ben Murdoch8b112d22011-06-08 16:22:53 +01007579RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007580 NoHandleAllocation ha;
7581 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007582 isolate->counters()->math_sqrt()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007583
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007585 return isolate->heap()->AllocateHeapNumber(sqrt(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00007586}
7587
7588
Ben Murdoch8b112d22011-06-08 16:22:53 +01007589RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007590 NoHandleAllocation ha;
7591 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007592 isolate->counters()->math_tan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007593
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007595 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00007596}
7597
7598
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007599static int MakeDay(int year, int month) {
Steve Block6ded16b2010-05-10 14:33:55 +01007600 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7601 181, 212, 243, 273, 304, 334};
7602 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7603 182, 213, 244, 274, 305, 335};
7604
7605 year += month / 12;
7606 month %= 12;
7607 if (month < 0) {
7608 year--;
7609 month += 12;
7610 }
7611
7612 ASSERT(month >= 0);
7613 ASSERT(month < 12);
7614
7615 // year_delta is an arbitrary number such that:
7616 // a) year_delta = -1 (mod 400)
7617 // b) year + year_delta > 0 for years in the range defined by
7618 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7619 // Jan 1 1970. This is required so that we don't run into integer
7620 // division of negative numbers.
7621 // c) there shouldn't be an overflow for 32-bit integers in the following
7622 // operations.
7623 static const int year_delta = 399999;
7624 static const int base_day = 365 * (1970 + year_delta) +
7625 (1970 + year_delta) / 4 -
7626 (1970 + year_delta) / 100 +
7627 (1970 + year_delta) / 400;
7628
7629 int year1 = year + year_delta;
7630 int day_from_year = 365 * year1 +
7631 year1 / 4 -
7632 year1 / 100 +
7633 year1 / 400 -
7634 base_day;
7635
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007636 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7637 return day_from_year + day_from_month[month];
Steve Block6ded16b2010-05-10 14:33:55 +01007638 }
7639
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007640 return day_from_year + day_from_month_leap[month];
Steve Block6ded16b2010-05-10 14:33:55 +01007641}
7642
7643
Ben Murdoch8b112d22011-06-08 16:22:53 +01007644RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
Steve Block6ded16b2010-05-10 14:33:55 +01007645 NoHandleAllocation ha;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007646 ASSERT(args.length() == 2);
Steve Block6ded16b2010-05-10 14:33:55 +01007647
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007648 CONVERT_SMI_ARG_CHECKED(year, 0);
7649 CONVERT_SMI_ARG_CHECKED(month, 1);
Steve Block6ded16b2010-05-10 14:33:55 +01007650
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007651 return Smi::FromInt(MakeDay(year, month));
Steve Block6ded16b2010-05-10 14:33:55 +01007652}
7653
7654
7655static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7656static const int kDaysIn4Years = 4 * 365 + 1;
7657static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7658static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7659static const int kDays1970to2000 = 30 * 365 + 7;
7660static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7661 kDays1970to2000;
7662static const int kYearsOffset = 400000;
7663
7664static const char kDayInYear[] = {
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30,
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7689
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30,
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7714
7715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7716 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7718 22, 23, 24, 25, 26, 27, 28, 29,
7719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7720 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7722 22, 23, 24, 25, 26, 27, 28, 29, 30,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7732 22, 23, 24, 25, 26, 27, 28, 29, 30,
7733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7734 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7736 22, 23, 24, 25, 26, 27, 28, 29, 30,
7737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7739
7740 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7741 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7743 22, 23, 24, 25, 26, 27, 28,
7744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7745 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7747 22, 23, 24, 25, 26, 27, 28, 29, 30,
7748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7749 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7751 22, 23, 24, 25, 26, 27, 28, 29, 30,
7752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7755 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7757 22, 23, 24, 25, 26, 27, 28, 29, 30,
7758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7759 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7761 22, 23, 24, 25, 26, 27, 28, 29, 30,
7762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7763 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7764
7765static const char kMonthInYear[] = {
7766 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7767 0, 0, 0, 0, 0, 0,
7768 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7769 1, 1, 1,
7770 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7771 2, 2, 2, 2, 2, 2,
7772 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7773 3, 3, 3, 3, 3,
7774 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7775 4, 4, 4, 4, 4, 4,
7776 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7777 5, 5, 5, 5, 5,
7778 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7779 6, 6, 6, 6, 6, 6,
7780 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7781 7, 7, 7, 7, 7, 7,
7782 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7783 8, 8, 8, 8, 8,
7784 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7785 9, 9, 9, 9, 9, 9,
7786 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7787 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7788 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7789 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7790
7791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7792 0, 0, 0, 0, 0, 0,
7793 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7794 1, 1, 1,
7795 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7796 2, 2, 2, 2, 2, 2,
7797 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7798 3, 3, 3, 3, 3,
7799 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7800 4, 4, 4, 4, 4, 4,
7801 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7802 5, 5, 5, 5, 5,
7803 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7804 6, 6, 6, 6, 6, 6,
7805 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7806 7, 7, 7, 7, 7, 7,
7807 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7808 8, 8, 8, 8, 8,
7809 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7810 9, 9, 9, 9, 9, 9,
7811 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7812 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7813 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7814 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7815
7816 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7817 0, 0, 0, 0, 0, 0,
7818 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7819 1, 1, 1, 1,
7820 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7821 2, 2, 2, 2, 2, 2,
7822 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7823 3, 3, 3, 3, 3,
7824 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7825 4, 4, 4, 4, 4, 4,
7826 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7827 5, 5, 5, 5, 5,
7828 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7829 6, 6, 6, 6, 6, 6,
7830 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7831 7, 7, 7, 7, 7, 7,
7832 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7833 8, 8, 8, 8, 8,
7834 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7835 9, 9, 9, 9, 9, 9,
7836 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7837 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7838 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7839 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7840
7841 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7842 0, 0, 0, 0, 0, 0,
7843 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7844 1, 1, 1,
7845 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7846 2, 2, 2, 2, 2, 2,
7847 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7848 3, 3, 3, 3, 3,
7849 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7850 4, 4, 4, 4, 4, 4,
7851 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7852 5, 5, 5, 5, 5,
7853 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7854 6, 6, 6, 6, 6, 6,
7855 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7856 7, 7, 7, 7, 7, 7,
7857 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7858 8, 8, 8, 8, 8,
7859 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7860 9, 9, 9, 9, 9, 9,
7861 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7862 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7863 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7864 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7865
7866
7867// This function works for dates from 1970 to 2099.
7868static inline void DateYMDFromTimeAfter1970(int date,
7869 int& year, int& month, int& day) {
7870#ifdef DEBUG
7871 int save_date = date; // Need this for ASSERT in the end.
7872#endif
7873
7874 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7875 date %= kDaysIn4Years;
7876
7877 month = kMonthInYear[date];
7878 day = kDayInYear[date];
7879
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007880 ASSERT(MakeDay(year, month) + day - 1 == save_date);
Steve Block6ded16b2010-05-10 14:33:55 +01007881}
7882
7883
7884static inline void DateYMDFromTimeSlow(int date,
7885 int& year, int& month, int& day) {
7886#ifdef DEBUG
7887 int save_date = date; // Need this for ASSERT in the end.
7888#endif
7889
7890 date += kDaysOffset;
7891 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7892 date %= kDaysIn400Years;
7893
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007894 ASSERT(MakeDay(year, 0) + date == save_date);
Steve Block6ded16b2010-05-10 14:33:55 +01007895
7896 date--;
7897 int yd1 = date / kDaysIn100Years;
7898 date %= kDaysIn100Years;
7899 year += 100 * yd1;
7900
7901 date++;
7902 int yd2 = date / kDaysIn4Years;
7903 date %= kDaysIn4Years;
7904 year += 4 * yd2;
7905
7906 date--;
7907 int yd3 = date / 365;
7908 date %= 365;
7909 year += yd3;
7910
7911 bool is_leap = (!yd1 || yd2) && !yd3;
7912
7913 ASSERT(date >= -1);
7914 ASSERT(is_leap || (date >= 0));
7915 ASSERT((date < 365) || (is_leap && (date < 366)));
7916 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007917 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7918 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
Steve Block6ded16b2010-05-10 14:33:55 +01007919
7920 if (is_leap) {
7921 day = kDayInYear[2*365 + 1 + date];
7922 month = kMonthInYear[2*365 + 1 + date];
7923 } else {
7924 day = kDayInYear[date];
7925 month = kMonthInYear[date];
7926 }
7927
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007928 ASSERT(MakeDay(year, month) + day - 1 == save_date);
Steve Block6ded16b2010-05-10 14:33:55 +01007929}
7930
7931
7932static inline void DateYMDFromTime(int date,
7933 int& year, int& month, int& day) {
7934 if (date >= 0 && date < 32 * kDaysIn4Years) {
7935 DateYMDFromTimeAfter1970(date, year, month, day);
7936 } else {
7937 DateYMDFromTimeSlow(date, year, month, day);
7938 }
7939}
7940
7941
Ben Murdoch8b112d22011-06-08 16:22:53 +01007942RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
Steve Block6ded16b2010-05-10 14:33:55 +01007943 NoHandleAllocation ha;
7944 ASSERT(args.length() == 2);
7945
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007946 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01007947 CONVERT_CHECKED(JSArray, res_array, args[1]);
7948
7949 int year, month, day;
7950 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7951
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007952 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7953 RUNTIME_ASSERT(elms_base->length() == 3);
7954 RUNTIME_ASSERT(res_array->HasFastTypeElements());
Iain Merrick75681382010-08-19 15:07:18 +01007955
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007956 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7957 if (maybe->IsFailure()) return maybe;
7958 FixedArray* elms = FixedArray::cast(res_array->elements());
Iain Merrick75681382010-08-19 15:07:18 +01007959 elms->set(0, Smi::FromInt(year));
7960 elms->set(1, Smi::FromInt(month));
7961 elms->set(2, Smi::FromInt(day));
Steve Block6ded16b2010-05-10 14:33:55 +01007962
Steve Block44f0eee2011-05-26 01:26:41 +01007963 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007964}
7965
7966
Ben Murdoch8b112d22011-06-08 16:22:53 +01007967RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007968 HandleScope scope(isolate);
7969 ASSERT(args.length() == 3);
7970
7971 Handle<JSFunction> callee = args.at<JSFunction>(0);
7972 Object** parameters = reinterpret_cast<Object**>(args[1]);
7973 const int argument_count = Smi::cast(args[2])->value();
7974
7975 Handle<JSObject> result =
7976 isolate->factory()->NewArgumentsObject(callee, argument_count);
7977 // Allocate the elements if needed.
7978 int parameter_count = callee->shared()->formal_parameter_count();
7979 if (argument_count > 0) {
7980 if (parameter_count > 0) {
7981 int mapped_count = Min(argument_count, parameter_count);
7982 Handle<FixedArray> parameter_map =
7983 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7984 parameter_map->set_map(
7985 isolate->heap()->non_strict_arguments_elements_map());
7986
7987 Handle<Map> old_map(result->map());
7988 Handle<Map> new_map =
7989 isolate->factory()->CopyMapDropTransitions(old_map);
Ben Murdoch589d6972011-11-30 16:04:58 +00007990 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007991
7992 result->set_map(*new_map);
7993 result->set_elements(*parameter_map);
7994
7995 // Store the context and the arguments array at the beginning of the
7996 // parameter map.
7997 Handle<Context> context(isolate->context());
7998 Handle<FixedArray> arguments =
7999 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8000 parameter_map->set(0, *context);
8001 parameter_map->set(1, *arguments);
8002
8003 // Loop over the actual parameters backwards.
8004 int index = argument_count - 1;
8005 while (index >= mapped_count) {
8006 // These go directly in the arguments array and have no
8007 // corresponding slot in the parameter map.
8008 arguments->set(index, *(parameters - index - 1));
8009 --index;
8010 }
8011
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008012 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008013 while (index >= 0) {
8014 // Detect duplicate names to the right in the parameter list.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008015 Handle<String> name(scope_info->ParameterName(index));
8016 int context_local_count = scope_info->ContextLocalCount();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008017 bool duplicate = false;
8018 for (int j = index + 1; j < parameter_count; ++j) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008019 if (scope_info->ParameterName(j) == *name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008020 duplicate = true;
8021 break;
8022 }
8023 }
8024
8025 if (duplicate) {
8026 // This goes directly in the arguments array with a hole in the
8027 // parameter map.
8028 arguments->set(index, *(parameters - index - 1));
8029 parameter_map->set_the_hole(index + 2);
8030 } else {
8031 // The context index goes in the parameter map with a hole in the
8032 // arguments array.
8033 int context_index = -1;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008034 for (int j = 0; j < context_local_count; ++j) {
8035 if (scope_info->ContextLocalName(j) == *name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008036 context_index = j;
8037 break;
8038 }
8039 }
8040 ASSERT(context_index >= 0);
8041 arguments->set_the_hole(index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008042 parameter_map->set(index + 2, Smi::FromInt(
8043 Context::MIN_CONTEXT_SLOTS + context_index));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008044 }
8045
8046 --index;
8047 }
8048 } else {
8049 // If there is no aliasing, the arguments object elements are not
8050 // special in any way.
8051 Handle<FixedArray> elements =
8052 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8053 result->set_elements(*elements);
8054 for (int i = 0; i < argument_count; ++i) {
8055 elements->set(i, *(parameters - i - 1));
8056 }
8057 }
8058 }
8059 return *result;
8060}
8061
8062
8063RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008064 NoHandleAllocation ha;
8065 ASSERT(args.length() == 3);
8066
8067 JSFunction* callee = JSFunction::cast(args[0]);
8068 Object** parameters = reinterpret_cast<Object**>(args[1]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008069 const int length = args.smi_at(2);
Steve Blocka7e24c12009-10-30 11:49:00 +00008070
John Reck59135872010-11-02 12:39:01 -07008071 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01008072 { MaybeObject* maybe_result =
8073 isolate->heap()->AllocateArgumentsObject(callee, length);
John Reck59135872010-11-02 12:39:01 -07008074 if (!maybe_result->ToObject(&result)) return maybe_result;
8075 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008076 // Allocate the elements if needed.
8077 if (length > 0) {
8078 // Allocate the fixed array.
John Reck59135872010-11-02 12:39:01 -07008079 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008080 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07008081 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8082 }
Leon Clarke4515c472010-02-03 11:58:03 +00008083
8084 AssertNoAllocation no_gc;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008085 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008086 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008087 array->set_length(length);
Leon Clarke4515c472010-02-03 11:58:03 +00008088
8089 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008090 for (int i = 0; i < length; i++) {
8091 array->set(i, *--parameters, mode);
8092 }
Steve Blockd0582a62009-12-15 09:54:21 +00008093 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00008094 }
8095 return result;
8096}
8097
8098
Ben Murdoch8b112d22011-06-08 16:22:53 +01008099RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
Steve Block44f0eee2011-05-26 01:26:41 +01008100 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008101 ASSERT(args.length() == 3);
Steve Block3ce2e202009-11-05 08:53:23 +00008102 CONVERT_ARG_CHECKED(Context, context, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01008103 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008104 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
Steve Blocka7e24c12009-10-30 11:49:00 +00008105
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008106 // The caller ensures that we pretenure closures that are assigned
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008107 // directly to properties.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08008108 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +00008109 Handle<JSFunction> result =
Steve Block44f0eee2011-05-26 01:26:41 +01008110 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8111 context,
8112 pretenure_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00008113 return *result;
8114}
8115
Ben Murdoch8b112d22011-06-08 16:22:53 +01008116
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008117// Find the arguments of the JavaScript function invocation that called
8118// into C++ code. Collect these in a newly allocated array of handles (possibly
8119// prefixed by a number of empty handles).
8120static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8121 int prefix_argc,
8122 int* total_argc) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008123 // Find frame containing arguments passed to the caller.
8124 JavaScriptFrameIterator it;
8125 JavaScriptFrame* frame = it.frame();
8126 List<JSFunction*> functions(2);
8127 frame->GetFunctions(&functions);
8128 if (functions.length() > 1) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008129 int inlined_jsframe_index = functions.length() - 1;
8130 JSFunction* inlined_function = functions[inlined_jsframe_index];
8131 Vector<SlotRef> args_slots =
8132 SlotRef::ComputeSlotMappingForArguments(
8133 frame,
8134 inlined_jsframe_index,
8135 inlined_function->shared()->formal_parameter_count());
8136
8137 int args_count = args_slots.length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008138
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008139 *total_argc = prefix_argc + args_count;
8140 SmartArrayPointer<Handle<Object> > param_data(
8141 NewArray<Handle<Object> >(*total_argc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01008142 for (int i = 0; i < args_count; i++) {
8143 Handle<Object> val = args_slots[i].GetValue();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008144 param_data[prefix_argc + i] = val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008145 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00008146
8147 args_slots.Dispose();
8148
Ben Murdoch8b112d22011-06-08 16:22:53 +01008149 return param_data;
8150 } else {
8151 it.AdvanceToArgumentsFrame();
8152 frame = it.frame();
8153 int args_count = frame->ComputeParametersCount();
8154
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008155 *total_argc = prefix_argc + args_count;
8156 SmartArrayPointer<Handle<Object> > param_data(
8157 NewArray<Handle<Object> >(*total_argc));
Ben Murdoch8b112d22011-06-08 16:22:53 +01008158 for (int i = 0; i < args_count; i++) {
8159 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008160 param_data[prefix_argc + i] = val;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008161 }
8162 return param_data;
8163 }
8164}
8165
8166
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008167RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8168 HandleScope scope(isolate);
8169 ASSERT(args.length() == 4);
8170 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8171 RUNTIME_ASSERT(args[3]->IsNumber());
8172 Handle<Object> bindee = args.at<Object>(1);
8173
8174 // TODO(lrn): Create bound function in C++ code from premade shared info.
8175 bound_function->shared()->set_bound(true);
8176 // Get all arguments of calling function (Function.prototype.bind).
8177 int argc = 0;
8178 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8179 // Don't count the this-arg.
8180 if (argc > 0) {
8181 ASSERT(*arguments[0] == args[2]);
8182 argc--;
8183 } else {
8184 ASSERT(args[2]->IsUndefined());
8185 }
8186 // Initialize array of bindings (function, this, and any existing arguments
8187 // if the function was already bound).
8188 Handle<FixedArray> new_bindings;
8189 int i;
8190 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8191 Handle<FixedArray> old_bindings(
8192 JSFunction::cast(*bindee)->function_bindings());
8193 new_bindings =
8194 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8195 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8196 i = 0;
8197 for (int n = old_bindings->length(); i < n; i++) {
8198 new_bindings->set(i, old_bindings->get(i));
8199 }
8200 } else {
8201 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8202 new_bindings = isolate->factory()->NewFixedArray(array_size);
8203 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8204 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8205 i = 2;
8206 }
8207 // Copy arguments, skipping the first which is "this_arg".
8208 for (int j = 0; j < argc; j++, i++) {
8209 new_bindings->set(i, *arguments[j + 1]);
8210 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00008211 new_bindings->set_map_no_write_barrier(
8212 isolate->heap()->fixed_cow_array_map());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008213 bound_function->set_function_bindings(*new_bindings);
8214
8215 // Update length.
8216 Handle<String> length_symbol = isolate->factory()->length_symbol();
8217 Handle<Object> new_length(args.at<Object>(3));
8218 PropertyAttributes attr =
8219 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8220 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8221 return *bound_function;
8222}
8223
8224
8225RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8226 HandleScope handles(isolate);
8227 ASSERT(args.length() == 1);
8228 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
8229 if (callable->IsJSFunction()) {
8230 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8231 if (function->shared()->bound()) {
8232 Handle<FixedArray> bindings(function->function_bindings());
8233 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8234 return *isolate->factory()->NewJSArrayWithElements(bindings);
8235 }
8236 }
8237 return isolate->heap()->undefined_value();
8238}
8239
8240
Ben Murdoch8b112d22011-06-08 16:22:53 +01008241RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
Steve Block44f0eee2011-05-26 01:26:41 +01008242 HandleScope scope(isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008243 ASSERT(args.length() == 1);
Steve Block1e0659c2011-05-24 12:43:12 +01008244 // First argument is a function to use as a constructor.
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008245 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008246 RUNTIME_ASSERT(function->shared()->bound());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008247
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008248 // The argument is a bound function. Extract its bound arguments
8249 // and callable.
8250 Handle<FixedArray> bound_args =
8251 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8252 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8253 Handle<Object> bound_function(
8254 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8255 ASSERT(!bound_function->IsJSFunction() ||
8256 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008257
Ben Murdoch8b112d22011-06-08 16:22:53 +01008258 int total_argc = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008259 SmartArrayPointer<Handle<Object> > param_data =
8260 GetCallerArguments(bound_argc, &total_argc);
Steve Block1e0659c2011-05-24 12:43:12 +01008261 for (int i = 0; i < bound_argc; i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008262 param_data[i] = Handle<Object>(bound_args->get(
8263 JSFunction::kBoundArgumentsStartIndex + i));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008264 }
8265
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008266 if (!bound_function->IsJSFunction()) {
8267 bool exception_thrown;
8268 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8269 &exception_thrown);
8270 if (exception_thrown) return Failure::Exception();
8271 }
8272 ASSERT(bound_function->IsJSFunction());
8273
Ben Murdochbb769b22010-08-11 14:56:33 +01008274 bool exception = false;
Steve Block1e0659c2011-05-24 12:43:12 +01008275 Handle<Object> result =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008276 Execution::New(Handle<JSFunction>::cast(bound_function),
8277 total_argc, *param_data, &exception);
Ben Murdochbb769b22010-08-11 14:56:33 +01008278 if (exception) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008279 return Failure::Exception();
Ben Murdochbb769b22010-08-11 14:56:33 +01008280 }
8281 ASSERT(!result.is_null());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01008282 return *result;
8283}
8284
Steve Blocka7e24c12009-10-30 11:49:00 +00008285
Steve Block44f0eee2011-05-26 01:26:41 +01008286static void TrySettingInlineConstructStub(Isolate* isolate,
8287 Handle<JSFunction> function) {
8288 Handle<Object> prototype = isolate->factory()->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00008289 if (function->has_instance_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008290 prototype = Handle<Object>(function->instance_prototype(), isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00008291 }
8292 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008293 ConstructStubCompiler compiler(isolate);
8294 Handle<Code> code = compiler.CompileConstructStub(function);
8295 function->shared()->set_construct_stub(*code);
Steve Blocka7e24c12009-10-30 11:49:00 +00008296 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008297}
8298
8299
Ben Murdoch8b112d22011-06-08 16:22:53 +01008300RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
Steve Block44f0eee2011-05-26 01:26:41 +01008301 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008302 ASSERT(args.length() == 1);
8303
8304 Handle<Object> constructor = args.at<Object>(0);
8305
8306 // If the constructor isn't a proper function we throw a type error.
8307 if (!constructor->IsJSFunction()) {
8308 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8309 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01008310 isolate->factory()->NewTypeError("not_constructor", arguments);
8311 return isolate->Throw(*type_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00008312 }
8313
8314 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
Steve Block6ded16b2010-05-10 14:33:55 +01008315
8316 // If function should not have prototype, construction is not allowed. In this
8317 // case generated code bailouts here, since function has no initial_map.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008318 if (!function->should_have_prototype() && !function->shared()->bound()) {
Steve Block6ded16b2010-05-10 14:33:55 +01008319 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8320 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01008321 isolate->factory()->NewTypeError("not_constructor", arguments);
8322 return isolate->Throw(*type_error);
Steve Block6ded16b2010-05-10 14:33:55 +01008323 }
8324
Steve Blocka7e24c12009-10-30 11:49:00 +00008325#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01008326 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00008327 // Handle stepping into constructors if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01008328 if (debug->StepInActive()) {
8329 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00008330 }
8331#endif
8332
8333 if (function->has_initial_map()) {
8334 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
8335 // The 'Function' function ignores the receiver object when
8336 // called using 'new' and creates a new JSFunction object that
8337 // is returned. The receiver object is only used for error
8338 // reporting if an error occurs when constructing the new
Steve Block44f0eee2011-05-26 01:26:41 +01008339 // JSFunction. FACTORY->NewJSObject() should not be used to
Steve Blocka7e24c12009-10-30 11:49:00 +00008340 // allocate JSFunctions since it does not properly initialize
8341 // the shared part of the function. Since the receiver is
8342 // ignored anyway, we use the global object as the receiver
8343 // instead of a new JSFunction object. This way, errors are
8344 // reported the same way whether or not 'Function' is called
8345 // using 'new'.
Steve Block44f0eee2011-05-26 01:26:41 +01008346 return isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00008347 }
8348 }
8349
Ben Murdochb0fe1622011-05-05 13:52:32 +01008350 // The function should be compiled for the optimization hints to be
8351 // available. We cannot use EnsureCompiled because that forces a
8352 // compilation through the shared function info which makes it
8353 // impossible for us to optimize.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008354 if (!function->is_compiled()) {
8355 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8356 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008357
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008358 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008359 if (!function->has_initial_map() &&
8360 shared->IsInobjectSlackTrackingInProgress()) {
8361 // The tracking is already in progress for another function. We can only
8362 // track one initial_map at a time, so we force the completion before the
8363 // function is called as a constructor for the first time.
8364 shared->CompleteInobjectSlackTracking();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008365 }
8366
8367 bool first_allocation = !shared->live_objects_may_exist();
Steve Block44f0eee2011-05-26 01:26:41 +01008368 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8369 RETURN_IF_EMPTY_HANDLE(isolate, result);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008370 // Delay setting the stub if inobject slack tracking is in progress.
8371 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008372 TrySettingInlineConstructStub(isolate, function);
Steve Blocka7e24c12009-10-30 11:49:00 +00008373 }
8374
Steve Block44f0eee2011-05-26 01:26:41 +01008375 isolate->counters()->constructed_objects()->Increment();
8376 isolate->counters()->constructed_objects_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00008377
8378 return *result;
8379}
8380
8381
Ben Murdoch8b112d22011-06-08 16:22:53 +01008382RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
Steve Block44f0eee2011-05-26 01:26:41 +01008383 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008384 ASSERT(args.length() == 1);
8385
8386 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8387 function->shared()->CompleteInobjectSlackTracking();
Steve Block44f0eee2011-05-26 01:26:41 +01008388 TrySettingInlineConstructStub(isolate, function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008389
Steve Block44f0eee2011-05-26 01:26:41 +01008390 return isolate->heap()->undefined_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008391}
8392
8393
Ben Murdoch8b112d22011-06-08 16:22:53 +01008394RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01008395 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008396 ASSERT(args.length() == 1);
8397
8398 Handle<JSFunction> function = args.at<JSFunction>(0);
8399#ifdef DEBUG
Iain Merrick75681382010-08-19 15:07:18 +01008400 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008401 PrintF("[lazy: ");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008402 function->PrintName();
Steve Blocka7e24c12009-10-30 11:49:00 +00008403 PrintF("]\n");
8404 }
8405#endif
8406
Ben Murdoch589d6972011-11-30 16:04:58 +00008407 // Compile the target function.
Steve Blocka7e24c12009-10-30 11:49:00 +00008408 ASSERT(!function->is_compiled());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008409 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008410 return Failure::Exception();
8411 }
8412
Ben Murdochb0fe1622011-05-05 13:52:32 +01008413 // All done. Return the compiled code.
8414 ASSERT(function->is_compiled());
Steve Blocka7e24c12009-10-30 11:49:00 +00008415 return function->code();
8416}
8417
8418
Ben Murdoch8b112d22011-06-08 16:22:53 +01008419RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01008420 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008421 ASSERT(args.length() == 1);
8422 Handle<JSFunction> function = args.at<JSFunction>(0);
Ben Murdoch589d6972011-11-30 16:04:58 +00008423
8424 // If the function is not compiled ignore the lazy
8425 // recompilation. This can happen if the debugger is activated and
8426 // the function is returned to the not compiled state.
8427 if (!function->shared()->is_compiled()) {
8428 function->ReplaceCode(function->shared()->code());
8429 return function->code();
8430 }
8431
Ben Murdochb0fe1622011-05-05 13:52:32 +01008432 // If the function is not optimizable or debugger is active continue using the
8433 // code from the full compiler.
8434 if (!function->shared()->code()->optimizable() ||
Ben Murdoch257744e2011-11-30 15:57:28 +00008435 isolate->DebuggerHasBreakPoints()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01008436 if (FLAG_trace_opt) {
8437 PrintF("[failed to optimize ");
8438 function->PrintName();
8439 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8440 function->shared()->code()->optimizable() ? "T" : "F",
Ben Murdoch257744e2011-11-30 15:57:28 +00008441 isolate->DebuggerHasBreakPoints() ? "T" : "F");
Ben Murdochb8e0da22011-05-16 14:20:40 +01008442 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008443 function->ReplaceCode(function->shared()->code());
8444 return function->code();
8445 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008446 if (JSFunction::CompileOptimized(function,
8447 AstNode::kNoNumber,
8448 CLEAR_EXCEPTION)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008449 return function->code();
8450 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01008451 if (FLAG_trace_opt) {
8452 PrintF("[failed to optimize ");
8453 function->PrintName();
8454 PrintF(": optimized compilation failed]\n");
8455 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008456 function->ReplaceCode(function->shared()->code());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008457 return function->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008458}
8459
8460
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008461class ActivationsFinder : public ThreadVisitor {
8462 public:
8463 explicit ActivationsFinder(JSFunction* function)
8464 : function_(function), has_activations_(false) {}
8465
8466 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8467 if (has_activations_) return;
8468
8469 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8470 JavaScriptFrame* frame = it.frame();
8471 if (frame->is_optimized() && frame->function() == function_) {
8472 has_activations_ = true;
8473 return;
8474 }
8475 }
8476 }
8477
8478 bool has_activations() { return has_activations_; }
8479
8480 private:
8481 JSFunction* function_;
8482 bool has_activations_;
8483};
8484
8485
Ben Murdoch8b112d22011-06-08 16:22:53 +01008486RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
Steve Block44f0eee2011-05-26 01:26:41 +01008487 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008488 ASSERT(args.length() == 1);
8489 RUNTIME_ASSERT(args[0]->IsSmi());
8490 Deoptimizer::BailoutType type =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008491 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
Steve Block44f0eee2011-05-26 01:26:41 +01008492 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8493 ASSERT(isolate->heap()->IsAllocationAllowed());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008494 int jsframes = deoptimizer->jsframe_count();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008495
Ben Murdoch8b112d22011-06-08 16:22:53 +01008496 deoptimizer->MaterializeHeapNumbers();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008497 delete deoptimizer;
8498
Ben Murdoch8b112d22011-06-08 16:22:53 +01008499 JavaScriptFrameIterator it(isolate);
8500 JavaScriptFrame* frame = NULL;
Ben Murdochc7cc0282012-03-05 14:35:55 +00008501 for (int i = 0; i < jsframes - 1; i++) it.Advance();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008502 frame = it.frame();
8503
Ben Murdochb0fe1622011-05-05 13:52:32 +01008504 RUNTIME_ASSERT(frame->function()->IsJSFunction());
Steve Block44f0eee2011-05-26 01:26:41 +01008505 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008506 Handle<Object> arguments;
8507 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
Steve Block44f0eee2011-05-26 01:26:41 +01008508 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008509 if (arguments.is_null()) {
8510 // FunctionGetArguments can't throw an exception, so cast away the
8511 // doubt with an assert.
8512 arguments = Handle<Object>(
8513 Accessors::FunctionGetArguments(*function,
8514 NULL)->ToObjectUnchecked());
Steve Block44f0eee2011-05-26 01:26:41 +01008515 ASSERT(*arguments != isolate->heap()->null_value());
8516 ASSERT(*arguments != isolate->heap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008517 }
8518 frame->SetExpression(i, *arguments);
8519 }
8520 }
8521
Ben Murdochb0fe1622011-05-05 13:52:32 +01008522 if (type == Deoptimizer::EAGER) {
8523 RUNTIME_ASSERT(function->IsOptimized());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008524 }
8525
8526 // Avoid doing too much work when running with --always-opt and keep
8527 // the optimized code around.
8528 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
Steve Block44f0eee2011-05-26 01:26:41 +01008529 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008530 }
8531
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008532 // Find other optimized activations of the function.
8533 bool has_other_activations = false;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008534 while (!it.done()) {
8535 JavaScriptFrame* frame = it.frame();
8536 if (frame->is_optimized() && frame->function() == *function) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008537 has_other_activations = true;
8538 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008539 }
8540 it.Advance();
8541 }
8542
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008543 if (!has_other_activations) {
8544 ActivationsFinder activations_finder(*function);
8545 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8546 has_other_activations = activations_finder.has_activations();
8547 }
8548
8549 if (!has_other_activations) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008550 if (FLAG_trace_deopt) {
8551 PrintF("[removing optimized code for: ");
8552 function->PrintName();
8553 PrintF("]\n");
8554 }
8555 function->ReplaceCode(function->shared()->code());
Ben Murdoch589d6972011-11-30 16:04:58 +00008556 } else {
8557 Deoptimizer::DeoptimizeFunction(*function);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008558 }
Steve Block44f0eee2011-05-26 01:26:41 +01008559 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008560}
8561
8562
Ben Murdoch8b112d22011-06-08 16:22:53 +01008563RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
Steve Block44f0eee2011-05-26 01:26:41 +01008564 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008565 delete deoptimizer;
Steve Block44f0eee2011-05-26 01:26:41 +01008566 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008567}
8568
8569
Ben Murdoch8b112d22011-06-08 16:22:53 +01008570RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01008571 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008572 ASSERT(args.length() == 1);
8573 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01008574 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008575
8576 Deoptimizer::DeoptimizeFunction(*function);
8577
Steve Block44f0eee2011-05-26 01:26:41 +01008578 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008579}
8580
8581
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8583#if defined(USE_SIMULATOR)
8584 return isolate->heap()->true_value();
8585#else
8586 return isolate->heap()->false_value();
8587#endif
8588}
8589
8590
Ben Murdoch8b112d22011-06-08 16:22:53 +01008591RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8592 HandleScope scope(isolate);
8593 ASSERT(args.length() == 1);
8594 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8595 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8596 function->MarkForLazyRecompilation();
8597 return isolate->heap()->undefined_value();
8598}
8599
8600
Ben Murdoch257744e2011-11-30 15:57:28 +00008601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8602 HandleScope scope(isolate);
8603 ASSERT(args.length() == 1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008604 // The least significant bit (after untagging) indicates whether the
8605 // function is currently optimized, regardless of reason.
Ben Murdoch257744e2011-11-30 15:57:28 +00008606 if (!V8::UseCrankshaft()) {
8607 return Smi::FromInt(4); // 4 == "never".
8608 }
8609 if (FLAG_always_opt) {
8610 return Smi::FromInt(3); // 3 == "always".
8611 }
8612 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8613 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8614 : Smi::FromInt(2); // 2 == "no".
8615}
8616
8617
8618RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8619 HandleScope scope(isolate);
8620 ASSERT(args.length() == 1);
8621 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8622 return Smi::FromInt(function->shared()->opt_count());
8623}
8624
8625
Ben Murdoch8b112d22011-06-08 16:22:53 +01008626RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
Steve Block44f0eee2011-05-26 01:26:41 +01008627 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008628 ASSERT(args.length() == 1);
8629 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8630
8631 // We're not prepared to handle a function with arguments object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008632 ASSERT(!function->shared()->uses_arguments());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008633
8634 // We have hit a back edge in an unoptimized frame for a function that was
8635 // selected for on-stack replacement. Find the unoptimized code object.
Steve Block44f0eee2011-05-26 01:26:41 +01008636 Handle<Code> unoptimized(function->shared()->code(), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008637 // Keep track of whether we've succeeded in optimizing.
8638 bool succeeded = unoptimized->optimizable();
8639 if (succeeded) {
8640 // If we are trying to do OSR when there are already optimized
8641 // activations of the function, it means (a) the function is directly or
8642 // indirectly recursive and (b) an optimized invocation has been
8643 // deoptimized so that we are currently in an unoptimized activation.
8644 // Check for optimized activations of this function.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008645 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008646 while (succeeded && !it.done()) {
8647 JavaScriptFrame* frame = it.frame();
8648 succeeded = !frame->is_optimized() || frame->function() != *function;
8649 it.Advance();
8650 }
8651 }
8652
8653 int ast_id = AstNode::kNoNumber;
8654 if (succeeded) {
8655 // The top JS function is this one, the PC is somewhere in the
8656 // unoptimized code.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008657 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008658 JavaScriptFrame* frame = it.frame();
8659 ASSERT(frame->function() == *function);
Ben Murdoch8b112d22011-06-08 16:22:53 +01008660 ASSERT(frame->LookupCode() == *unoptimized);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008661 ASSERT(unoptimized->contains(frame->pc()));
8662
8663 // Use linear search of the unoptimized code's stack check table to find
8664 // the AST id matching the PC.
8665 Address start = unoptimized->instruction_start();
8666 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
Steve Block1e0659c2011-05-24 12:43:12 +01008667 Address table_cursor = start + unoptimized->stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008668 uint32_t table_length = Memory::uint32_at(table_cursor);
8669 table_cursor += kIntSize;
8670 for (unsigned i = 0; i < table_length; ++i) {
8671 // Table entries are (AST id, pc offset) pairs.
8672 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8673 if (pc_offset == target_pc_offset) {
8674 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8675 break;
8676 }
8677 table_cursor += 2 * kIntSize;
8678 }
8679 ASSERT(ast_id != AstNode::kNoNumber);
8680 if (FLAG_trace_osr) {
8681 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8682 function->PrintName();
8683 PrintF("]\n");
8684 }
8685
8686 // Try to compile the optimized code. A true return value from
8687 // CompileOptimized means that compilation succeeded, not necessarily
8688 // that optimization succeeded.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008689 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008690 function->IsOptimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008691 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8692 function->code()->deoptimization_data());
8693 if (data->OsrPcOffset()->value() >= 0) {
8694 if (FLAG_trace_osr) {
8695 PrintF("[on-stack replacement offset %d in optimized code]\n",
8696 data->OsrPcOffset()->value());
8697 }
8698 ASSERT(data->OsrAstId()->value() == ast_id);
8699 } else {
8700 // We may never generate the desired OSR entry if we emit an
8701 // early deoptimize.
8702 succeeded = false;
8703 }
8704 } else {
8705 succeeded = false;
8706 }
8707 }
8708
8709 // Revert to the original stack checks in the original unoptimized code.
8710 if (FLAG_trace_osr) {
8711 PrintF("[restoring original stack checks in ");
8712 function->PrintName();
8713 PrintF("]\n");
8714 }
8715 StackCheckStub check_stub;
8716 Handle<Code> check_code = check_stub.GetCode();
Steve Block44f0eee2011-05-26 01:26:41 +01008717 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
Steve Block1e0659c2011-05-24 12:43:12 +01008718 Deoptimizer::RevertStackCheckCode(*unoptimized,
8719 *check_code,
8720 *replacement_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008721
8722 // Allow OSR only at nesting level zero again.
8723 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8724
8725 // If the optimization attempt succeeded, return the AST id tagged as a
8726 // smi. This tells the builtin that we need to translate the unoptimized
8727 // frame to an optimized one.
8728 if (succeeded) {
8729 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8730 return Smi::FromInt(ast_id);
8731 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008732 if (function->IsMarkedForLazyRecompilation()) {
8733 function->ReplaceCode(function->shared()->code());
8734 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008735 return Smi::FromInt(-1);
8736 }
8737}
8738
8739
Ben Murdoch589d6972011-11-30 16:04:58 +00008740RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8741 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8742 return isolate->heap()->undefined_value();
8743}
8744
8745
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008746RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8747 HandleScope scope(isolate);
8748 ASSERT(args.length() >= 2);
8749 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8750 Object* receiver = args[0];
8751 int argc = args.length() - 2;
8752
8753 // If there are too many arguments, allocate argv via malloc.
8754 const int argv_small_size = 10;
8755 Handle<Object> argv_small_buffer[argv_small_size];
8756 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8757 Handle<Object>* argv = argv_small_buffer;
8758 if (argc > argv_small_size) {
8759 argv = new Handle<Object>[argc];
8760 if (argv == NULL) return isolate->StackOverflow();
8761 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8762 }
8763
8764 for (int i = 0; i < argc; ++i) {
8765 MaybeObject* maybe = args[1 + i];
8766 Object* object;
8767 if (!maybe->To<Object>(&object)) return maybe;
8768 argv[i] = Handle<Object>(object);
8769 }
8770
8771 bool threw;
8772 Handle<JSReceiver> hfun(fun);
8773 Handle<Object> hreceiver(receiver);
8774 Handle<Object> result =
8775 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8776
8777 if (threw) return Failure::Exception();
8778 return *result;
8779}
8780
8781
Ben Murdoch589d6972011-11-30 16:04:58 +00008782RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8783 HandleScope scope(isolate);
8784 ASSERT(args.length() == 5);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008785 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8786 Handle<Object> receiver = args.at<Object>(1);
8787 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8788 CONVERT_SMI_ARG_CHECKED(offset, 3);
8789 CONVERT_SMI_ARG_CHECKED(argc, 4);
Ben Murdoch589d6972011-11-30 16:04:58 +00008790 ASSERT(offset >= 0);
8791 ASSERT(argc >= 0);
8792
8793 // If there are too many arguments, allocate argv via malloc.
8794 const int argv_small_size = 10;
8795 Handle<Object> argv_small_buffer[argv_small_size];
8796 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8797 Handle<Object>* argv = argv_small_buffer;
8798 if (argc > argv_small_size) {
8799 argv = new Handle<Object>[argc];
8800 if (argv == NULL) return isolate->StackOverflow();
8801 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8802 }
8803
8804 for (int i = 0; i < argc; ++i) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008805 argv[i] = Object::GetElement(arguments, offset + i);
Ben Murdoch589d6972011-11-30 16:04:58 +00008806 }
8807
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008808 bool threw;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008809 Handle<Object> result =
Ben Murdochc7cc0282012-03-05 14:35:55 +00008810 Execution::Call(fun, receiver, argc, argv, &threw, true);
Ben Murdoch589d6972011-11-30 16:04:58 +00008811
8812 if (threw) return Failure::Exception();
8813 return *result;
8814}
8815
8816
Ben Murdoch8b112d22011-06-08 16:22:53 +01008817RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008818 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008819 ASSERT(args.length() == 1);
8820 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8821 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8822}
8823
8824
Ben Murdoch8b112d22011-06-08 16:22:53 +01008825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008826 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008827 ASSERT(args.length() == 1);
8828 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8829 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8830}
8831
8832
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008834 NoHandleAllocation ha;
8835 ASSERT(args.length() == 1);
8836
8837 CONVERT_CHECKED(JSFunction, function, args[0]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008838 int length = function->shared()->scope_info()->ContextLength();
John Reck59135872010-11-02 12:39:01 -07008839 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01008840 { MaybeObject* maybe_result =
8841 isolate->heap()->AllocateFunctionContext(length, function);
John Reck59135872010-11-02 12:39:01 -07008842 if (!maybe_result->ToObject(&result)) return maybe_result;
8843 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008844
Steve Block44f0eee2011-05-26 01:26:41 +01008845 isolate->set_context(Context::cast(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00008846
8847 return result; // non-failure
8848}
8849
John Reck59135872010-11-02 12:39:01 -07008850
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008851RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8852 NoHandleAllocation ha;
8853 ASSERT(args.length() == 2);
8854 JSObject* extension_object;
8855 if (args[0]->IsJSObject()) {
8856 extension_object = JSObject::cast(args[0]);
8857 } else {
8858 // Convert the object to a proper JavaScript object.
8859 MaybeObject* maybe_js_object = args[0]->ToObject();
8860 if (!maybe_js_object->To(&extension_object)) {
8861 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8862 HandleScope scope(isolate);
8863 Handle<Object> handle = args.at<Object>(0);
8864 Handle<Object> result =
8865 isolate->factory()->NewTypeError("with_expression",
8866 HandleVector(&handle, 1));
8867 return isolate->Throw(*result);
8868 } else {
John Reck59135872010-11-02 12:39:01 -07008869 return maybe_js_object;
8870 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008871 }
8872 }
8873
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008874 JSFunction* function;
8875 if (args[1]->IsSmi()) {
8876 // A smi sentinel indicates a context nested inside global code rather
8877 // than some function. There is a canonical empty function that can be
8878 // gotten from the global context.
8879 function = isolate->context()->global_context()->closure();
8880 } else {
8881 function = JSFunction::cast(args[1]);
John Reck59135872010-11-02 12:39:01 -07008882 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008883
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008884 Context* context;
8885 MaybeObject* maybe_context =
8886 isolate->heap()->AllocateWithContext(function,
8887 isolate->context(),
8888 extension_object);
8889 if (!maybe_context->To(&context)) return maybe_context;
Steve Block44f0eee2011-05-26 01:26:41 +01008890 isolate->set_context(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008891 return context;
Steve Blocka7e24c12009-10-30 11:49:00 +00008892}
8893
8894
Ben Murdoch8b112d22011-06-08 16:22:53 +01008895RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008896 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008897 ASSERT(args.length() == 3);
8898 String* name = String::cast(args[0]);
8899 Object* thrown_object = args[1];
8900 JSFunction* function;
8901 if (args[2]->IsSmi()) {
8902 // A smi sentinel indicates a context nested inside global code rather
8903 // than some function. There is a canonical empty function that can be
8904 // gotten from the global context.
8905 function = isolate->context()->global_context()->closure();
8906 } else {
8907 function = JSFunction::cast(args[2]);
8908 }
8909 Context* context;
8910 MaybeObject* maybe_context =
8911 isolate->heap()->AllocateCatchContext(function,
8912 isolate->context(),
8913 name,
8914 thrown_object);
8915 if (!maybe_context->To(&context)) return maybe_context;
8916 isolate->set_context(context);
8917 return context;
Steve Blocka7e24c12009-10-30 11:49:00 +00008918}
8919
8920
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008921RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8922 NoHandleAllocation ha;
8923 ASSERT(args.length() == 2);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008924 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008925 JSFunction* function;
8926 if (args[1]->IsSmi()) {
8927 // A smi sentinel indicates a context nested inside global code rather
8928 // than some function. There is a canonical empty function that can be
8929 // gotten from the global context.
8930 function = isolate->context()->global_context()->closure();
8931 } else {
8932 function = JSFunction::cast(args[1]);
8933 }
8934 Context* context;
8935 MaybeObject* maybe_context =
8936 isolate->heap()->AllocateBlockContext(function,
8937 isolate->context(),
8938 scope_info);
8939 if (!maybe_context->To(&context)) return maybe_context;
8940 isolate->set_context(context);
8941 return context;
8942}
8943
8944
Ben Murdoch8b112d22011-06-08 16:22:53 +01008945RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01008946 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008947 ASSERT(args.length() == 2);
8948
8949 CONVERT_ARG_CHECKED(Context, context, 0);
8950 CONVERT_ARG_CHECKED(String, name, 1);
8951
8952 int index;
8953 PropertyAttributes attributes;
8954 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008955 BindingFlags binding_flags;
8956 Handle<Object> holder = context->Lookup(name,
8957 flags,
8958 &index,
8959 &attributes,
8960 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00008961
Steve Block1e0659c2011-05-24 12:43:12 +01008962 // If the slot was not found the result is true.
8963 if (holder.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008964 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008965 }
8966
Steve Block1e0659c2011-05-24 12:43:12 +01008967 // If the slot was found in a context, it should be DONT_DELETE.
8968 if (holder->IsContext()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008969 return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +01008970 }
8971
8972 // The slot was found in a JSObject, either a context extension object,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008973 // the global object, or the subject of a with. Try to delete it
8974 // (respecting DONT_DELETE).
Steve Block1e0659c2011-05-24 12:43:12 +01008975 Handle<JSObject> object = Handle<JSObject>::cast(holder);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008976 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00008977}
8978
8979
8980// A mechanism to return a pair of Object pointers in registers (if possible).
8981// How this is achieved is calling convention-dependent.
8982// All currently supported x86 compiles uses calling conventions that are cdecl
8983// variants where a 64-bit value is returned in two 32-bit registers
8984// (edx:eax on ia32, r1:r0 on ARM).
8985// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8986// In Win64 calling convention, a struct of two pointers is returned in memory,
8987// allocated by the caller, and passed as a pointer in a hidden first parameter.
8988#ifdef V8_HOST_ARCH_64_BIT
8989struct ObjectPair {
John Reck59135872010-11-02 12:39:01 -07008990 MaybeObject* x;
8991 MaybeObject* y;
Steve Blocka7e24c12009-10-30 11:49:00 +00008992};
8993
John Reck59135872010-11-02 12:39:01 -07008994static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008995 ObjectPair result = {x, y};
8996 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8997 // In Win64 they are assigned to a hidden first argument.
8998 return result;
8999}
9000#else
9001typedef uint64_t ObjectPair;
John Reck59135872010-11-02 12:39:01 -07009002static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009003 return reinterpret_cast<uint32_t>(x) |
9004 (reinterpret_cast<ObjectPair>(y) << 32);
9005}
9006#endif
9007
9008
Steve Block44f0eee2011-05-26 01:26:41 +01009009static inline MaybeObject* Unhole(Heap* heap,
9010 MaybeObject* x,
John Reck59135872010-11-02 12:39:01 -07009011 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009012 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9013 USE(attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01009014 return x->IsTheHole() ? heap->undefined_value() : x;
Steve Blocka7e24c12009-10-30 11:49:00 +00009015}
9016
9017
Ben Murdoch257744e2011-11-30 15:57:28 +00009018static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9019 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009020 ASSERT(!holder->IsGlobalObject());
Steve Block44f0eee2011-05-26 01:26:41 +01009021 Context* top = isolate->context();
Steve Blocka7e24c12009-10-30 11:49:00 +00009022 // Get the context extension function.
9023 JSFunction* context_extension_function =
9024 top->global_context()->context_extension_function();
9025 // If the holder isn't a context extension object, we just return it
9026 // as the receiver. This allows arguments objects to be used as
9027 // receivers, but only if they are put in the context scope chain
9028 // explicitly via a with-statement.
9029 Object* constructor = holder->map()->constructor();
9030 if (constructor != context_extension_function) return holder;
Ben Murdoch257744e2011-11-30 15:57:28 +00009031 // Fall back to using the global object as the implicit receiver if
9032 // the property turns out to be a local variable allocated in a
9033 // context extension object - introduced via eval. Implicit global
9034 // receivers are indicated with the hole value.
9035 return isolate->heap()->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009036}
9037
9038
Steve Block44f0eee2011-05-26 01:26:41 +01009039static ObjectPair LoadContextSlotHelper(Arguments args,
9040 Isolate* isolate,
9041 bool throw_error) {
9042 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009043 ASSERT_EQ(2, args.length());
9044
9045 if (!args[0]->IsContext() || !args[1]->IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +01009046 return MakePair(isolate->ThrowIllegalOperation(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009047 }
9048 Handle<Context> context = args.at<Context>(0);
9049 Handle<String> name = args.at<String>(1);
9050
9051 int index;
9052 PropertyAttributes attributes;
9053 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009054 BindingFlags binding_flags;
9055 Handle<Object> holder = context->Lookup(name,
9056 flags,
9057 &index,
9058 &attributes,
9059 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00009060
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009061 // If the index is non-negative, the slot has been found in a context.
Steve Blocka7e24c12009-10-30 11:49:00 +00009062 if (index >= 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009063 ASSERT(holder->IsContext());
9064 // If the "property" we were looking for is a local variable, the
9065 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
Ben Murdoch257744e2011-11-30 15:57:28 +00009066 //
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009067 // Use the hole as the receiver to signal that the receiver is implicit
9068 // and that the global receiver should be used (as distinguished from an
9069 // explicit receiver that happens to be a global object).
Ben Murdoch257744e2011-11-30 15:57:28 +00009070 Handle<Object> receiver = isolate->factory()->the_hole_value();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009071 Object* value = Context::cast(*holder)->get(index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009072 // Check for uninitialized bindings.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009073 switch (binding_flags) {
9074 case MUTABLE_CHECK_INITIALIZED:
9075 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9076 if (value->IsTheHole()) {
9077 Handle<Object> reference_error =
9078 isolate->factory()->NewReferenceError("not_defined",
9079 HandleVector(&name, 1));
9080 return MakePair(isolate->Throw(*reference_error), NULL);
9081 }
9082 // FALLTHROUGH
9083 case MUTABLE_IS_INITIALIZED:
9084 case IMMUTABLE_IS_INITIALIZED:
9085 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9086 ASSERT(!value->IsTheHole());
9087 return MakePair(value, *receiver);
9088 case IMMUTABLE_CHECK_INITIALIZED:
9089 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9090 case MISSING_BINDING:
9091 UNREACHABLE();
9092 return MakePair(NULL, NULL);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009093 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009094 }
9095
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009096 // Otherwise, if the slot was found the holder is a context extension
9097 // object, subject of a with, or a global object. We read the named
9098 // property from it.
9099 if (!holder.is_null()) {
9100 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9101 ASSERT(object->HasProperty(*name));
Ben Murdoch257744e2011-11-30 15:57:28 +00009102 // GetProperty below can cause GC.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009103 Handle<Object> receiver_handle(object->IsGlobalObject()
9104 ? GlobalObject::cast(*object)->global_receiver()
9105 : ComputeReceiverForNonGlobal(isolate, *object));
Ben Murdoch257744e2011-11-30 15:57:28 +00009106
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009107 // No need to unhole the value here. This is taken care of by the
Steve Blocka7e24c12009-10-30 11:49:00 +00009108 // GetProperty function.
John Reck59135872010-11-02 12:39:01 -07009109 MaybeObject* value = object->GetProperty(*name);
Ben Murdoch257744e2011-11-30 15:57:28 +00009110 return MakePair(value, *receiver_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +00009111 }
9112
9113 if (throw_error) {
9114 // The property doesn't exist - throw exception.
9115 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01009116 isolate->factory()->NewReferenceError("not_defined",
9117 HandleVector(&name, 1));
9118 return MakePair(isolate->Throw(*reference_error), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009119 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00009120 // The property doesn't exist - return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +01009121 return MakePair(isolate->heap()->undefined_value(),
9122 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009123 }
9124}
9125
9126
Ben Murdoch8b112d22011-06-08 16:22:53 +01009127RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01009128 return LoadContextSlotHelper(args, isolate, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00009129}
9130
9131
Ben Murdoch8b112d22011-06-08 16:22:53 +01009132RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01009133 return LoadContextSlotHelper(args, isolate, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00009134}
9135
9136
Ben Murdoch8b112d22011-06-08 16:22:53 +01009137RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01009138 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009139 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00009140
Steve Block44f0eee2011-05-26 01:26:41 +01009141 Handle<Object> value(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009142 CONVERT_ARG_CHECKED(Context, context, 1);
9143 CONVERT_ARG_CHECKED(String, name, 2);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009144 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9145 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9146 ? kNonStrictMode : kStrictMode;
Steve Blocka7e24c12009-10-30 11:49:00 +00009147
9148 int index;
9149 PropertyAttributes attributes;
9150 ContextLookupFlags flags = FOLLOW_CHAINS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009151 BindingFlags binding_flags;
9152 Handle<Object> holder = context->Lookup(name,
9153 flags,
9154 &index,
9155 &attributes,
9156 &binding_flags);
Steve Blocka7e24c12009-10-30 11:49:00 +00009157
9158 if (index >= 0) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009159 // The property was found in a context slot.
9160 Handle<Context> context = Handle<Context>::cast(holder);
9161 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9162 context->get(index)->IsTheHole()) {
9163 Handle<Object> error =
9164 isolate->factory()->NewReferenceError("not_defined",
9165 HandleVector(&name, 1));
9166 return isolate->Throw(*error);
9167 }
9168 // Ignore if read_only variable.
9169 if ((attributes & READ_ONLY) == 0) {
9170 // Context is a fixed array and set cannot fail.
9171 context->set(index, *value);
9172 } else if (strict_mode == kStrictMode) {
9173 // Setting read only property in strict mode.
9174 Handle<Object> error =
9175 isolate->factory()->NewTypeError("strict_cannot_assign",
9176 HandleVector(&name, 1));
9177 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00009178 }
9179 return *value;
9180 }
9181
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009182 // Slow case: The property is not in a context slot. It is either in a
9183 // context extension object, a property of the subject of a with, or a
9184 // property of the global object.
9185 Handle<JSObject> object;
Steve Blocka7e24c12009-10-30 11:49:00 +00009186
9187 if (!holder.is_null()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009188 // The property exists on the holder.
9189 object = Handle<JSObject>::cast(holder);
Steve Blocka7e24c12009-10-30 11:49:00 +00009190 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009191 // The property was not found.
Steve Blocka7e24c12009-10-30 11:49:00 +00009192 ASSERT(attributes == ABSENT);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009193
9194 if (strict_mode == kStrictMode) {
9195 // Throw in strict mode (assignment to undefined variable).
9196 Handle<Object> error =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009197 isolate->factory()->NewReferenceError(
9198 "not_defined", HandleVector(&name, 1));
Ben Murdoch8b112d22011-06-08 16:22:53 +01009199 return isolate->Throw(*error);
9200 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009201 // In non-strict mode, the property is added to the global object.
Steve Blocka7e24c12009-10-30 11:49:00 +00009202 attributes = NONE;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009203 object = Handle<JSObject>(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00009204 }
9205
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009206 // Set the property if it's not read only or doesn't yet exist.
Steve Blocka7e24c12009-10-30 11:49:00 +00009207 if ((attributes & READ_ONLY) == 0 ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009208 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009209 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01009210 isolate,
Ben Murdochc7cc0282012-03-05 14:35:55 +00009211 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009212 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
9213 // Setting read only property in strict mode.
9214 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01009215 isolate->factory()->NewTypeError(
9216 "strict_cannot_assign", HandleVector(&name, 1));
9217 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00009218 }
9219 return *value;
9220}
9221
9222
Ben Murdoch8b112d22011-06-08 16:22:53 +01009223RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
Steve Block44f0eee2011-05-26 01:26:41 +01009224 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009225 ASSERT(args.length() == 1);
9226
Steve Block44f0eee2011-05-26 01:26:41 +01009227 return isolate->Throw(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00009228}
9229
9230
Ben Murdoch8b112d22011-06-08 16:22:53 +01009231RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
Steve Block44f0eee2011-05-26 01:26:41 +01009232 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009233 ASSERT(args.length() == 1);
9234
Steve Block44f0eee2011-05-26 01:26:41 +01009235 return isolate->ReThrow(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00009236}
9237
9238
Ben Murdoch8b112d22011-06-08 16:22:53 +01009239RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
Steve Blockd0582a62009-12-15 09:54:21 +00009240 ASSERT_EQ(0, args.length());
Steve Block44f0eee2011-05-26 01:26:41 +01009241 return isolate->PromoteScheduledException();
Steve Blockd0582a62009-12-15 09:54:21 +00009242}
9243
9244
Ben Murdoch8b112d22011-06-08 16:22:53 +01009245RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01009246 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009247 ASSERT(args.length() == 1);
9248
Steve Block44f0eee2011-05-26 01:26:41 +01009249 Handle<Object> name(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009250 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01009251 isolate->factory()->NewReferenceError("not_defined",
9252 HandleVector(&name, 1));
9253 return isolate->Throw(*reference_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00009254}
9255
9256
Ben Murdoch8b112d22011-06-08 16:22:53 +01009257RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
Ben Murdochf87a2032010-10-22 12:50:53 +01009258 ASSERT(args.length() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009259
9260 // First check if this is a real stack overflow.
Steve Block44f0eee2011-05-26 01:26:41 +01009261 if (isolate->stack_guard()->IsStackOverflow()) {
9262 NoHandleAllocation na;
9263 return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +00009264 }
9265
9266 return Execution::HandleStackGuardInterrupt();
9267}
9268
9269
Steve Blocka7e24c12009-10-30 11:49:00 +00009270static int StackSize() {
9271 int n = 0;
9272 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9273 return n;
9274}
9275
9276
9277static void PrintTransition(Object* result) {
9278 // indentation
9279 { const int nmax = 80;
9280 int n = StackSize();
9281 if (n <= nmax)
9282 PrintF("%4d:%*s", n, n, "");
9283 else
9284 PrintF("%4d:%*s", n, nmax, "...");
9285 }
9286
9287 if (result == NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009288 JavaScriptFrame::PrintTop(stdout, true, false);
9289 PrintF(" {\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00009290 } else {
9291 // function result
9292 PrintF("} -> ");
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009293 result->ShortPrint();
Steve Blocka7e24c12009-10-30 11:49:00 +00009294 PrintF("\n");
9295 }
9296}
9297
9298
Ben Murdoch8b112d22011-06-08 16:22:53 +01009299RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009300 ASSERT(args.length() == 0);
9301 NoHandleAllocation ha;
9302 PrintTransition(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01009303 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009304}
9305
9306
Ben Murdoch8b112d22011-06-08 16:22:53 +01009307RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009308 NoHandleAllocation ha;
9309 PrintTransition(args[0]);
9310 return args[0]; // return TOS
9311}
9312
9313
Ben Murdoch8b112d22011-06-08 16:22:53 +01009314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009315 NoHandleAllocation ha;
9316 ASSERT(args.length() == 1);
9317
9318#ifdef DEBUG
9319 if (args[0]->IsString()) {
9320 // If we have a string, assume it's a code "marker"
9321 // and print some interesting cpu debugging info.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009322 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009323 JavaScriptFrame* frame = it.frame();
9324 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9325 frame->fp(), frame->sp(), frame->caller_sp());
9326 } else {
9327 PrintF("DebugPrint: ");
9328 }
9329 args[0]->Print();
Steve Blockd0582a62009-12-15 09:54:21 +00009330 if (args[0]->IsHeapObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01009331 PrintF("\n");
Steve Blockd0582a62009-12-15 09:54:21 +00009332 HeapObject::cast(args[0])->map()->Print();
9333 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009334#else
9335 // ShortPrint is available in release mode. Print is not.
9336 args[0]->ShortPrint();
9337#endif
9338 PrintF("\n");
9339 Flush();
9340
9341 return args[0]; // return TOS
9342}
9343
9344
Ben Murdoch8b112d22011-06-08 16:22:53 +01009345RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009346 ASSERT(args.length() == 0);
9347 NoHandleAllocation ha;
Steve Block44f0eee2011-05-26 01:26:41 +01009348 isolate->PrintStack();
9349 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009350}
9351
9352
Ben Murdoch8b112d22011-06-08 16:22:53 +01009353RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009354 NoHandleAllocation ha;
9355 ASSERT(args.length() == 0);
9356
9357 // According to ECMA-262, section 15.9.1, page 117, the precision of
9358 // the number in a Date object representing a particular instant in
9359 // time is milliseconds. Therefore, we floor the result of getting
9360 // the OS time.
9361 double millis = floor(OS::TimeCurrentMillis());
Steve Block44f0eee2011-05-26 01:26:41 +01009362 return isolate->heap()->NumberFromDouble(millis);
Steve Blocka7e24c12009-10-30 11:49:00 +00009363}
9364
9365
Ben Murdoch8b112d22011-06-08 16:22:53 +01009366RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
Steve Block44f0eee2011-05-26 01:26:41 +01009367 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009368 ASSERT(args.length() == 2);
9369
9370 CONVERT_ARG_CHECKED(String, str, 0);
9371 FlattenString(str);
9372
9373 CONVERT_ARG_CHECKED(JSArray, output, 1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009374
9375 MaybeObject* maybe_result_array =
Ben Murdochc7cc0282012-03-05 14:35:55 +00009376 output->EnsureCanContainHeapObjectElements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009377 if (maybe_result_array->IsFailure()) return maybe_result_array;
Steve Blocka7e24c12009-10-30 11:49:00 +00009378 RUNTIME_ASSERT(output->HasFastElements());
9379
9380 AssertNoAllocation no_allocation;
9381
9382 FixedArray* output_array = FixedArray::cast(output->elements());
9383 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9384 bool result;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009385 String::FlatContent str_content = str->GetFlatContent();
9386 if (str_content.IsAscii()) {
9387 result = DateParser::Parse(str_content.ToAsciiVector(),
Ben Murdoch8b112d22011-06-08 16:22:53 +01009388 output_array,
9389 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00009390 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009391 ASSERT(str_content.IsTwoByte());
9392 result = DateParser::Parse(str_content.ToUC16Vector(),
Ben Murdoch8b112d22011-06-08 16:22:53 +01009393 output_array,
9394 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00009395 }
9396
9397 if (result) {
9398 return *output;
9399 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009400 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009401 }
9402}
9403
9404
Ben Murdoch8b112d22011-06-08 16:22:53 +01009405RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009406 NoHandleAllocation ha;
9407 ASSERT(args.length() == 1);
9408
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009409 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009410 const char* zone = OS::LocalTimezone(x);
Steve Block44f0eee2011-05-26 01:26:41 +01009411 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
Steve Blocka7e24c12009-10-30 11:49:00 +00009412}
9413
9414
Ben Murdoch8b112d22011-06-08 16:22:53 +01009415RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009416 NoHandleAllocation ha;
9417 ASSERT(args.length() == 0);
9418
Steve Block44f0eee2011-05-26 01:26:41 +01009419 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
Steve Blocka7e24c12009-10-30 11:49:00 +00009420}
9421
9422
Ben Murdoch8b112d22011-06-08 16:22:53 +01009423RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009424 NoHandleAllocation ha;
9425 ASSERT(args.length() == 1);
9426
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009427 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009428 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00009429}
9430
9431
Ben Murdoch8b112d22011-06-08 16:22:53 +01009432RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009433 ASSERT(args.length() == 1);
9434 Object* global = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01009435 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009436 return JSGlobalObject::cast(global)->global_receiver();
9437}
9438
9439
Ben Murdoch8b112d22011-06-08 16:22:53 +01009440RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
Steve Block44f0eee2011-05-26 01:26:41 +01009441 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009442 ASSERT_EQ(1, args.length());
9443 CONVERT_ARG_CHECKED(String, source, 0);
9444
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009445 source = Handle<String>(source->TryFlattenGetString());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009446 // Optimized fast case where we only have ASCII characters.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009447 Handle<Object> result;
9448 if (source->IsSeqAsciiString()) {
9449 result = JsonParser<true>::Parse(source);
9450 } else {
9451 result = JsonParser<false>::Parse(source);
9452 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009453 if (result.is_null()) {
9454 // Syntax error or stack overflow in scanner.
Steve Block44f0eee2011-05-26 01:26:41 +01009455 ASSERT(isolate->has_pending_exception());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009456 return Failure::Exception();
9457 }
9458 return *result;
9459}
9460
9461
Ben Murdoch257744e2011-11-30 15:57:28 +00009462bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9463 Handle<Context> context) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009464 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9465 // Check with callback if set.
9466 AllowCodeGenerationFromStringsCallback callback =
9467 isolate->allow_code_gen_callback();
9468 if (callback == NULL) {
9469 // No callback set and code generation disallowed.
9470 return false;
9471 } else {
9472 // Callback set. Let it decide if code generation is allowed.
9473 VMState state(isolate, EXTERNAL);
9474 return callback(v8::Utils::ToLocal(context));
Ben Murdoch257744e2011-11-30 15:57:28 +00009475 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009476}
9477
9478
Ben Murdoch8b112d22011-06-08 16:22:53 +01009479RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
Steve Block44f0eee2011-05-26 01:26:41 +01009480 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009481 ASSERT_EQ(1, args.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009482 CONVERT_ARG_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009483
Ben Murdoch257744e2011-11-30 15:57:28 +00009484 // Extract global context.
Steve Block44f0eee2011-05-26 01:26:41 +01009485 Handle<Context> context(isolate->context()->global_context());
Ben Murdoch257744e2011-11-30 15:57:28 +00009486
9487 // Check if global context allows code generation from
9488 // strings. Throw an exception if it doesn't.
Ben Murdochc7cc0282012-03-05 14:35:55 +00009489 if (context->allow_code_gen_from_strings()->IsFalse() &&
9490 !CodeGenerationFromStringsAllowed(isolate, context)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009491 return isolate->Throw(*isolate->factory()->NewError(
9492 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9493 }
9494
9495 // Compile source string in the global context.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009496 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9497 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +01009498 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00009499 Handle<JSFunction> fun =
Steve Block44f0eee2011-05-26 01:26:41 +01009500 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9501 context,
9502 NOT_TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009503 return *fun;
9504}
9505
9506
Steve Block44f0eee2011-05-26 01:26:41 +01009507static ObjectPair CompileGlobalEval(Isolate* isolate,
9508 Handle<String> source,
Steve Block1e0659c2011-05-24 12:43:12 +01009509 Handle<Object> receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009510 LanguageMode language_mode,
9511 int scope_position) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009512 Handle<Context> context = Handle<Context>(isolate->context());
9513 Handle<Context> global_context = Handle<Context>(context->global_context());
9514
9515 // Check if global context allows code generation from
9516 // strings. Throw an exception if it doesn't.
Ben Murdochc7cc0282012-03-05 14:35:55 +00009517 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9518 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009519 isolate->Throw(*isolate->factory()->NewError(
9520 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9521 return MakePair(Failure::Exception(), NULL);
9522 }
9523
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009524 // Deal with a normal eval call with a string argument. Compile it
9525 // and return the compiled function bound in the local context.
9526 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9527 source,
Steve Block44f0eee2011-05-26 01:26:41 +01009528 Handle<Context>(isolate->context()),
Ben Murdoch257744e2011-11-30 15:57:28 +00009529 context->IsGlobalContext(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009530 language_mode,
9531 scope_position);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009532 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01009533 Handle<JSFunction> compiled =
9534 isolate->factory()->NewFunctionFromSharedFunctionInfo(
Ben Murdoch257744e2011-11-30 15:57:28 +00009535 shared, context, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009536 return MakePair(*compiled, *receiver);
9537}
9538
9539
Ben Murdoch8b112d22011-06-08 16:22:53 +01009540RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009541 ASSERT(args.length() == 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00009542
Steve Block44f0eee2011-05-26 01:26:41 +01009543 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009544 Handle<Object> callee = args.at<Object>(0);
Leon Clarkee46be812010-01-19 14:06:41 +00009545
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009546 // If "eval" didn't refer to the original GlobalEval, it's not a
9547 // direct call to eval.
9548 // (And even if it is, but the first argument isn't a string, just let
9549 // execution default to an indirect call to eval, which will also return
9550 // the first argument without doing anything).
Steve Block44f0eee2011-05-26 01:26:41 +01009551 if (*callee != isolate->global_context()->global_eval_fun() ||
Leon Clarkee46be812010-01-19 14:06:41 +00009552 !args[1]->IsString()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009553 return MakePair(*callee, isolate->heap()->the_hole_value());
Leon Clarkee46be812010-01-19 14:06:41 +00009554 }
9555
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009556 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9557 ASSERT(args[4]->IsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +01009558 return CompileGlobalEval(isolate,
9559 args.at<String>(1),
Steve Block1e0659c2011-05-24 12:43:12 +01009560 args.at<Object>(2),
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009561 language_mode,
9562 args.smi_at(4));
Steve Blocka7e24c12009-10-30 11:49:00 +00009563}
9564
9565
Ben Murdoch8b112d22011-06-08 16:22:53 +01009566RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009567 // This utility adjusts the property attributes for newly created Function
9568 // object ("new Function(...)") by changing the map.
9569 // All it does is changing the prototype property to enumerable
9570 // as specified in ECMA262, 15.3.5.2.
Steve Block44f0eee2011-05-26 01:26:41 +01009571 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009572 ASSERT(args.length() == 1);
9573 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009574
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009575 Handle<Map> map = func->shared()->is_classic_mode()
9576 ? isolate->function_instance_map()
9577 : isolate->strict_mode_function_instance_map();
Steve Block44f0eee2011-05-26 01:26:41 +01009578
9579 ASSERT(func->map()->instance_type() == map->instance_type());
9580 ASSERT(func->map()->instance_size() == map->instance_size());
9581 func->set_map(*map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009582 return *func;
9583}
9584
9585
Ben Murdoch8b112d22011-06-08 16:22:53 +01009586RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
Ben Murdochbb769b22010-08-11 14:56:33 +01009587 // Allocate a block of memory in NewSpace (filled with a filler).
9588 // Use as fallback for allocation in generated code when NewSpace
9589 // is full.
9590 ASSERT(args.length() == 1);
9591 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9592 int size = size_smi->value();
9593 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9594 RUNTIME_ASSERT(size > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009595 Heap* heap = isolate->heap();
9596 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
Ben Murdochbb769b22010-08-11 14:56:33 +01009597 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
John Reck59135872010-11-02 12:39:01 -07009598 Object* allocation;
Steve Block44f0eee2011-05-26 01:26:41 +01009599 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
John Reck59135872010-11-02 12:39:01 -07009600 if (maybe_allocation->ToObject(&allocation)) {
Steve Block44f0eee2011-05-26 01:26:41 +01009601 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
John Reck59135872010-11-02 12:39:01 -07009602 }
9603 return maybe_allocation;
Ben Murdochbb769b22010-08-11 14:56:33 +01009604 }
Ben Murdochbb769b22010-08-11 14:56:33 +01009605}
9606
9607
Ben Murdochb0fe1622011-05-05 13:52:32 +01009608// Push an object unto an array of objects if it is not already in the
Steve Blocka7e24c12009-10-30 11:49:00 +00009609// array. Returns true if the element was pushed on the stack and
9610// false otherwise.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009611RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009612 ASSERT(args.length() == 2);
9613 CONVERT_CHECKED(JSArray, array, args[0]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009614 CONVERT_CHECKED(JSObject, element, args[1]);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009615 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009616 int length = Smi::cast(array->length())->value();
9617 FixedArray* elements = FixedArray::cast(array->elements());
9618 for (int i = 0; i < length; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009619 if (elements->get(i) == element) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009620 }
John Reck59135872010-11-02 12:39:01 -07009621 Object* obj;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009622 // Strict not needed. Used for cycle detection in Array join implementation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009623 { MaybeObject* maybe_obj =
9624 array->SetFastElement(length, element, kNonStrictMode, true);
John Reck59135872010-11-02 12:39:01 -07009625 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9626 }
Steve Block44f0eee2011-05-26 01:26:41 +01009627 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009628}
9629
9630
9631/**
9632 * A simple visitor visits every element of Array's.
9633 * The backend storage can be a fixed array for fast elements case,
9634 * or a dictionary for sparse array. Since Dictionary is a subtype
9635 * of FixedArray, the class can be used by both fast and slow cases.
9636 * The second parameter of the constructor, fast_elements, specifies
9637 * whether the storage is a FixedArray or Dictionary.
9638 *
9639 * An index limit is used to deal with the situation that a result array
9640 * length overflows 32-bit non-negative integer.
9641 */
9642class ArrayConcatVisitor {
9643 public:
Steve Block44f0eee2011-05-26 01:26:41 +01009644 ArrayConcatVisitor(Isolate* isolate,
9645 Handle<FixedArray> storage,
Steve Blocka7e24c12009-10-30 11:49:00 +00009646 bool fast_elements) :
Steve Block44f0eee2011-05-26 01:26:41 +01009647 isolate_(isolate),
9648 storage_(Handle<FixedArray>::cast(
9649 isolate->global_handles()->Create(*storage))),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009650 index_offset_(0u),
9651 fast_elements_(fast_elements) { }
9652
9653 ~ArrayConcatVisitor() {
9654 clear_storage();
9655 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009656
9657 void visit(uint32_t i, Handle<Object> elm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009658 if (i >= JSObject::kMaxElementCount - index_offset_) return;
Leon Clarkee46be812010-01-19 14:06:41 +00009659 uint32_t index = index_offset_ + i;
Steve Blocka7e24c12009-10-30 11:49:00 +00009660
9661 if (fast_elements_) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009662 if (index < static_cast<uint32_t>(storage_->length())) {
9663 storage_->set(index, *elm);
9664 return;
9665 }
9666 // Our initial estimate of length was foiled, possibly by
9667 // getters on the arrays increasing the length of later arrays
9668 // during iteration.
9669 // This shouldn't happen in anything but pathological cases.
9670 SetDictionaryMode(index);
9671 // Fall-through to dictionary mode.
Steve Blocka7e24c12009-10-30 11:49:00 +00009672 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009673 ASSERT(!fast_elements_);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009674 Handle<SeededNumberDictionary> dict(
9675 SeededNumberDictionary::cast(*storage_));
9676 Handle<SeededNumberDictionary> result =
Steve Block44f0eee2011-05-26 01:26:41 +01009677 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009678 if (!result.is_identical_to(dict)) {
9679 // Dictionary needed to grow.
9680 clear_storage();
9681 set_storage(*result);
9682 }
9683}
Steve Blocka7e24c12009-10-30 11:49:00 +00009684
9685 void increase_index_offset(uint32_t delta) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009686 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9687 index_offset_ = JSObject::kMaxElementCount;
Leon Clarkee46be812010-01-19 14:06:41 +00009688 } else {
9689 index_offset_ += delta;
9690 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009691 }
9692
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009693 Handle<JSArray> ToArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01009694 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009695 Handle<Object> length =
Steve Block44f0eee2011-05-26 01:26:41 +01009696 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009697 Handle<Map> map;
9698 if (fast_elements_) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009699 map = isolate_->factory()->GetElementsTransitionMap(array,
9700 FAST_ELEMENTS);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009701 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009702 map = isolate_->factory()->GetElementsTransitionMap(array,
9703 DICTIONARY_ELEMENTS);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009704 }
9705 array->set_map(*map);
9706 array->set_length(*length);
9707 array->set_elements(*storage_);
9708 return array;
9709 }
Leon Clarkee46be812010-01-19 14:06:41 +00009710
Steve Blocka7e24c12009-10-30 11:49:00 +00009711 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009712 // Convert storage to dictionary mode.
9713 void SetDictionaryMode(uint32_t index) {
9714 ASSERT(fast_elements_);
9715 Handle<FixedArray> current_storage(*storage_);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009716 Handle<SeededNumberDictionary> slow_storage(
9717 isolate_->factory()->NewSeededNumberDictionary(
9718 current_storage->length()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009719 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9720 for (uint32_t i = 0; i < current_length; i++) {
9721 HandleScope loop_scope;
9722 Handle<Object> element(current_storage->get(i));
9723 if (!element->IsTheHole()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009724 Handle<SeededNumberDictionary> new_storage =
Steve Block44f0eee2011-05-26 01:26:41 +01009725 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009726 if (!new_storage.is_identical_to(slow_storage)) {
9727 slow_storage = loop_scope.CloseAndEscape(new_storage);
9728 }
9729 }
9730 }
9731 clear_storage();
9732 set_storage(*slow_storage);
9733 fast_elements_ = false;
9734 }
9735
9736 inline void clear_storage() {
Steve Block44f0eee2011-05-26 01:26:41 +01009737 isolate_->global_handles()->Destroy(
9738 Handle<Object>::cast(storage_).location());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009739 }
9740
9741 inline void set_storage(FixedArray* storage) {
Steve Block44f0eee2011-05-26 01:26:41 +01009742 storage_ = Handle<FixedArray>::cast(
9743 isolate_->global_handles()->Create(storage));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009744 }
9745
Steve Block44f0eee2011-05-26 01:26:41 +01009746 Isolate* isolate_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009747 Handle<FixedArray> storage_; // Always a global handle.
9748 // Index after last seen index. Always less than or equal to
9749 // JSObject::kMaxElementCount.
Steve Blocka7e24c12009-10-30 11:49:00 +00009750 uint32_t index_offset_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009751 bool fast_elements_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009752};
9753
9754
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009755static uint32_t EstimateElementCount(Handle<JSArray> array) {
9756 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9757 int element_count = 0;
9758 switch (array->GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009759 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009760 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009761 // Fast elements can't have lengths that are not representable by
9762 // a 32-bit signed integer.
9763 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9764 int fast_length = static_cast<int>(length);
9765 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9766 for (int i = 0; i < fast_length; i++) {
9767 if (!elements->get(i)->IsTheHole()) element_count++;
Steve Blocka7e24c12009-10-30 11:49:00 +00009768 }
Steve Block3ce2e202009-11-05 08:53:23 +00009769 break;
9770 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009771 case FAST_DOUBLE_ELEMENTS:
9772 // TODO(1810): Decide if it's worthwhile to implement this.
9773 UNREACHABLE();
9774 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00009775 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009776 Handle<SeededNumberDictionary> dictionary(
9777 SeededNumberDictionary::cast(array->elements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009778 int capacity = dictionary->Capacity();
9779 for (int i = 0; i < capacity; i++) {
9780 Handle<Object> key(dictionary->KeyAt(i));
9781 if (dictionary->IsKey(*key)) {
9782 element_count++;
9783 }
9784 }
9785 break;
9786 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009787 case NON_STRICT_ARGUMENTS_ELEMENTS:
9788 case EXTERNAL_BYTE_ELEMENTS:
9789 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9790 case EXTERNAL_SHORT_ELEMENTS:
9791 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9792 case EXTERNAL_INT_ELEMENTS:
9793 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9794 case EXTERNAL_FLOAT_ELEMENTS:
9795 case EXTERNAL_DOUBLE_ELEMENTS:
9796 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009797 // External arrays are always dense.
9798 return length;
9799 }
9800 // As an estimate, we assume that the prototype doesn't contain any
9801 // inherited elements.
9802 return element_count;
9803}
9804
9805
9806
9807template<class ExternalArrayClass, class ElementType>
Steve Block44f0eee2011-05-26 01:26:41 +01009808static void IterateExternalArrayElements(Isolate* isolate,
9809 Handle<JSObject> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009810 bool elements_are_ints,
9811 bool elements_are_guaranteed_smis,
9812 ArrayConcatVisitor* visitor) {
9813 Handle<ExternalArrayClass> array(
9814 ExternalArrayClass::cast(receiver->elements()));
9815 uint32_t len = static_cast<uint32_t>(array->length());
9816
9817 ASSERT(visitor != NULL);
9818 if (elements_are_ints) {
9819 if (elements_are_guaranteed_smis) {
9820 for (uint32_t j = 0; j < len; j++) {
9821 HandleScope loop_scope;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009822 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009823 visitor->visit(j, e);
9824 }
9825 } else {
9826 for (uint32_t j = 0; j < len; j++) {
9827 HandleScope loop_scope;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009828 int64_t val = static_cast<int64_t>(array->get_scalar(j));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009829 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9830 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9831 visitor->visit(j, e);
9832 } else {
9833 Handle<Object> e =
Steve Block44f0eee2011-05-26 01:26:41 +01009834 isolate->factory()->NewNumber(static_cast<ElementType>(val));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009835 visitor->visit(j, e);
9836 }
9837 }
9838 }
9839 } else {
9840 for (uint32_t j = 0; j < len; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009841 HandleScope loop_scope(isolate);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009842 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009843 visitor->visit(j, e);
9844 }
9845 }
9846}
9847
9848
9849// Used for sorting indices in a List<uint32_t>.
9850static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9851 uint32_t a = *ap;
9852 uint32_t b = *bp;
9853 return (a == b) ? 0 : (a < b) ? -1 : 1;
9854}
9855
9856
9857static void CollectElementIndices(Handle<JSObject> object,
9858 uint32_t range,
9859 List<uint32_t>* indices) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009860 ElementsKind kind = object->GetElementsKind();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009861 switch (kind) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009862 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009863 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009864 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9865 uint32_t length = static_cast<uint32_t>(elements->length());
9866 if (range < length) length = range;
9867 for (uint32_t i = 0; i < length; i++) {
9868 if (!elements->get(i)->IsTheHole()) {
9869 indices->Add(i);
9870 }
9871 }
9872 break;
9873 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009874 case FAST_DOUBLE_ELEMENTS: {
9875 // TODO(1810): Decide if it's worthwhile to implement this.
9876 UNREACHABLE();
9877 break;
9878 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009879 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009880 Handle<SeededNumberDictionary> dict(
9881 SeededNumberDictionary::cast(object->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009882 uint32_t capacity = dict->Capacity();
9883 for (uint32_t j = 0; j < capacity; j++) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009884 HandleScope loop_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +00009885 Handle<Object> k(dict->KeyAt(j));
9886 if (dict->IsKey(*k)) {
9887 ASSERT(k->IsNumber());
9888 uint32_t index = static_cast<uint32_t>(k->Number());
9889 if (index < range) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009890 indices->Add(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009891 }
9892 }
9893 }
9894 break;
9895 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009896 default: {
9897 int dense_elements_length;
9898 switch (kind) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009899 case EXTERNAL_PIXEL_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009900 dense_elements_length =
9901 ExternalPixelArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009902 break;
9903 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009904 case EXTERNAL_BYTE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009905 dense_elements_length =
9906 ExternalByteArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009907 break;
9908 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009909 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009910 dense_elements_length =
9911 ExternalUnsignedByteArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009912 break;
9913 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009914 case EXTERNAL_SHORT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009915 dense_elements_length =
9916 ExternalShortArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009917 break;
9918 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009919 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009920 dense_elements_length =
9921 ExternalUnsignedShortArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009922 break;
9923 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009924 case EXTERNAL_INT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009925 dense_elements_length =
9926 ExternalIntArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009927 break;
9928 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009929 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009930 dense_elements_length =
9931 ExternalUnsignedIntArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009932 break;
9933 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009934 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009935 dense_elements_length =
9936 ExternalFloatArray::cast(object->elements())->length();
9937 break;
9938 }
Ben Murdoch589d6972011-11-30 16:04:58 +00009939 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +00009940 dense_elements_length =
9941 ExternalDoubleArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009942 break;
9943 }
9944 default:
9945 UNREACHABLE();
9946 dense_elements_length = 0;
9947 break;
9948 }
9949 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9950 if (range <= length) {
9951 length = range;
9952 // We will add all indices, so we might as well clear it first
9953 // and avoid duplicates.
9954 indices->Clear();
9955 }
9956 for (uint32_t i = 0; i < length; i++) {
9957 indices->Add(i);
9958 }
9959 if (length == range) return; // All indices accounted for already.
9960 break;
9961 }
9962 }
9963
9964 Handle<Object> prototype(object->GetPrototype());
9965 if (prototype->IsJSObject()) {
9966 // The prototype will usually have no inherited element indices,
9967 // but we have to check.
9968 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9969 }
9970}
9971
9972
9973/**
9974 * A helper function that visits elements of a JSArray in numerical
9975 * order.
9976 *
9977 * The visitor argument called for each existing element in the array
9978 * with the element index and the element's value.
9979 * Afterwards it increments the base-index of the visitor by the array
9980 * length.
9981 * Returns false if any access threw an exception, otherwise true.
9982 */
Steve Block44f0eee2011-05-26 01:26:41 +01009983static bool IterateElements(Isolate* isolate,
9984 Handle<JSArray> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009985 ArrayConcatVisitor* visitor) {
9986 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9987 switch (receiver->GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009988 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch589d6972011-11-30 16:04:58 +00009989 case FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009990 // Run through the elements FixedArray and use HasElement and GetElement
9991 // to check the prototype for missing elements.
9992 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9993 int fast_length = static_cast<int>(length);
9994 ASSERT(fast_length <= elements->length());
9995 for (int j = 0; j < fast_length; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01009996 HandleScope loop_scope(isolate);
9997 Handle<Object> element_value(elements->get(j), isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009998 if (!element_value->IsTheHole()) {
9999 visitor->visit(j, element_value);
10000 } else if (receiver->HasElement(j)) {
10001 // Call GetElement on receiver, not its prototype, or getters won't
10002 // have the correct receiver.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010003 element_value = Object::GetElement(receiver, j);
10004 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010005 visitor->visit(j, element_value);
10006 }
10007 }
10008 break;
10009 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010010 case FAST_DOUBLE_ELEMENTS: {
10011 // TODO(1810): Decide if it's worthwhile to implement this.
10012 UNREACHABLE();
10013 break;
10014 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010015 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010016 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010017 List<uint32_t> indices(dict->Capacity() / 2);
10018 // Collect all indices in the object and the prototypes less
10019 // than length. This might introduce duplicates in the indices list.
10020 CollectElementIndices(receiver, length, &indices);
10021 indices.Sort(&compareUInt32);
10022 int j = 0;
10023 int n = indices.length();
10024 while (j < n) {
10025 HandleScope loop_scope;
10026 uint32_t index = indices[j];
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010027 Handle<Object> element = Object::GetElement(receiver, index);
10028 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010029 visitor->visit(index, element);
10030 // Skip to next different index (i.e., omit duplicates).
10031 do {
10032 j++;
10033 } while (j < n && indices[j] == index);
10034 }
10035 break;
10036 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010037 case EXTERNAL_PIXEL_ELEMENTS: {
Steve Block44f0eee2011-05-26 01:26:41 +010010038 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10039 receiver->elements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010040 for (uint32_t j = 0; j < length; j++) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010041 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010042 visitor->visit(j, e);
10043 }
10044 break;
10045 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010046 case EXTERNAL_BYTE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010047 IterateExternalArrayElements<ExternalByteArray, int8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010048 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010049 break;
10050 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010051 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010052 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010053 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010054 break;
10055 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010056 case EXTERNAL_SHORT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010057 IterateExternalArrayElements<ExternalShortArray, int16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010058 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010059 break;
10060 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010061 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010062 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010063 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010064 break;
10065 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010066 case EXTERNAL_INT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010067 IterateExternalArrayElements<ExternalIntArray, int32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010068 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010069 break;
10070 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010071 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010072 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +010010073 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010074 break;
10075 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010076 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010077 IterateExternalArrayElements<ExternalFloatArray, float>(
Steve Block44f0eee2011-05-26 01:26:41 +010010078 isolate, receiver, false, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010079 break;
10080 }
Ben Murdoch589d6972011-11-30 16:04:58 +000010081 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoch257744e2011-11-30 15:57:28 +000010082 IterateExternalArrayElements<ExternalDoubleArray, double>(
10083 isolate, receiver, false, false, visitor);
10084 break;
10085 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010086 default:
10087 UNREACHABLE();
10088 break;
10089 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010090 visitor->increase_index_offset(length);
10091 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000010092}
10093
10094
10095/**
10096 * Array::concat implementation.
10097 * See ECMAScript 262, 15.4.4.4.
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010098 * TODO(581): Fix non-compliance for very large concatenations and update to
Leon Clarkee46be812010-01-19 14:06:41 +000010099 * following the ECMAScript 5 specification.
Steve Blocka7e24c12009-10-30 11:49:00 +000010100 */
Ben Murdoch8b112d22011-06-08 16:22:53 +010010101RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010102 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010010103 HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010104
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010105 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10106 int argument_count = static_cast<int>(arguments->length()->Number());
10107 RUNTIME_ASSERT(arguments->HasFastElements());
10108 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010109
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010110 // Pass 1: estimate the length and number of elements of the result.
10111 // The actual length can be larger if any of the arguments have getters
10112 // that mutate other arguments (but will otherwise be precise).
10113 // The number of elements is precise if there are no inherited elements.
Steve Blocka7e24c12009-10-30 11:49:00 +000010114
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010115 uint32_t estimate_result_length = 0;
10116 uint32_t estimate_nof_elements = 0;
10117 {
10118 for (int i = 0; i < argument_count; i++) {
10119 HandleScope loop_scope;
10120 Handle<Object> obj(elements->get(i));
10121 uint32_t length_estimate;
10122 uint32_t element_estimate;
10123 if (obj->IsJSArray()) {
10124 Handle<JSArray> array(Handle<JSArray>::cast(obj));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010125 // TODO(1810): Find out if it's worthwhile to properly support
10126 // arbitrary ElementsKinds. For now, pessimistically transition to
10127 // FAST_ELEMENTS.
10128 if (array->HasFastDoubleElements()) {
10129 array = Handle<JSArray>::cast(
Ben Murdochc7cc0282012-03-05 14:35:55 +000010130 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010131 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010132 length_estimate =
10133 static_cast<uint32_t>(array->length()->Number());
10134 element_estimate =
10135 EstimateElementCount(array);
10136 } else {
10137 length_estimate = 1;
10138 element_estimate = 1;
10139 }
10140 // Avoid overflows by capping at kMaxElementCount.
10141 if (JSObject::kMaxElementCount - estimate_result_length <
10142 length_estimate) {
10143 estimate_result_length = JSObject::kMaxElementCount;
10144 } else {
10145 estimate_result_length += length_estimate;
10146 }
10147 if (JSObject::kMaxElementCount - estimate_nof_elements <
10148 element_estimate) {
10149 estimate_nof_elements = JSObject::kMaxElementCount;
10150 } else {
10151 estimate_nof_elements += element_estimate;
Steve Blocka7e24c12009-10-30 11:49:00 +000010152 }
10153 }
10154 }
10155
Steve Blocka7e24c12009-10-30 11:49:00 +000010156 // If estimated number of elements is more than half of length, a
10157 // fixed array (fast case) is more time and space-efficient than a
10158 // dictionary.
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010159 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
Steve Blocka7e24c12009-10-30 11:49:00 +000010160
10161 Handle<FixedArray> storage;
10162 if (fast_case) {
10163 // The backing storage array must have non-existing elements to
10164 // preserve holes across concat operations.
Steve Block44f0eee2011-05-26 01:26:41 +010010165 storage = isolate->factory()->NewFixedArrayWithHoles(
10166 estimate_result_length);
Steve Blocka7e24c12009-10-30 11:49:00 +000010167 } else {
10168 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10169 uint32_t at_least_space_for = estimate_nof_elements +
10170 (estimate_nof_elements >> 2);
10171 storage = Handle<FixedArray>::cast(
Ben Murdochc7cc0282012-03-05 14:35:55 +000010172 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
Steve Blocka7e24c12009-10-30 11:49:00 +000010173 }
10174
Steve Block44f0eee2011-05-26 01:26:41 +010010175 ArrayConcatVisitor visitor(isolate, storage, fast_case);
Steve Blocka7e24c12009-10-30 11:49:00 +000010176
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010177 for (int i = 0; i < argument_count; i++) {
10178 Handle<Object> obj(elements->get(i));
10179 if (obj->IsJSArray()) {
10180 Handle<JSArray> array = Handle<JSArray>::cast(obj);
Steve Block44f0eee2011-05-26 01:26:41 +010010181 if (!IterateElements(isolate, array, &visitor)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010182 return Failure::Exception();
10183 }
10184 } else {
10185 visitor.visit(0, obj);
10186 visitor.increase_index_offset(1);
10187 }
10188 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010189
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010190 return *visitor.ToArray();
Steve Blocka7e24c12009-10-30 11:49:00 +000010191}
10192
10193
10194// This will not allocate (flatten the string), but it may run
10195// very slowly for very deeply nested ConsStrings. For debugging use only.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010196RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010197 NoHandleAllocation ha;
10198 ASSERT(args.length() == 1);
10199
10200 CONVERT_CHECKED(String, string, args[0]);
10201 StringInputBuffer buffer(string);
10202 while (buffer.has_more()) {
10203 uint16_t character = buffer.GetNext();
10204 PrintF("%c", character);
10205 }
10206 return string;
10207}
10208
10209// Moves all own elements of an object, that are below a limit, to positions
10210// starting at zero. All undefined values are placed after non-undefined values,
10211// and are followed by non-existing element. Does not change the length
10212// property.
10213// Returns the number of non-undefined elements collected.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010214RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010215 ASSERT(args.length() == 2);
10216 CONVERT_CHECKED(JSObject, object, args[0]);
10217 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10218 return object->PrepareElementsForSort(limit);
10219}
10220
10221
10222// Move contents of argument 0 (an array) to argument 1 (an array)
Ben Murdoch8b112d22011-06-08 16:22:53 +010010223RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010224 ASSERT(args.length() == 2);
10225 CONVERT_CHECKED(JSArray, from, args[0]);
10226 CONVERT_CHECKED(JSArray, to, args[1]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010227 FixedArrayBase* new_elements = from->elements();
John Reck59135872010-11-02 12:39:01 -070010228 MaybeObject* maybe_new_map;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010229 ElementsKind elements_kind;
Steve Block44f0eee2011-05-26 01:26:41 +010010230 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10231 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010232 elements_kind = FAST_ELEMENTS;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010233 } else if (new_elements->map() ==
10234 isolate->heap()->fixed_double_array_map()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010235 elements_kind = FAST_DOUBLE_ELEMENTS;
Steve Block8defd9f2010-07-08 12:39:36 +010010236 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010237 elements_kind = DICTIONARY_ELEMENTS;
Steve Block8defd9f2010-07-08 12:39:36 +010010238 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010239 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
John Reck59135872010-11-02 12:39:01 -070010240 Object* new_map;
10241 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
Steve Block8defd9f2010-07-08 12:39:36 +010010242 to->set_map(Map::cast(new_map));
10243 to->set_elements(new_elements);
Steve Blocka7e24c12009-10-30 11:49:00 +000010244 to->set_length(from->length());
John Reck59135872010-11-02 12:39:01 -070010245 Object* obj;
10246 { MaybeObject* maybe_obj = from->ResetElements();
10247 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10248 }
Leon Clarke4515c472010-02-03 11:58:03 +000010249 from->set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000010250 return to;
10251}
10252
10253
Steve Block59151502010-09-22 15:07:15 +010010254// How many elements does this object/array have?
Ben Murdoch8b112d22011-06-08 16:22:53 +010010255RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010256 ASSERT(args.length() == 1);
Steve Block59151502010-09-22 15:07:15 +010010257 CONVERT_CHECKED(JSObject, object, args[0]);
10258 HeapObject* elements = object->elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000010259 if (elements->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010260 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10261 return Smi::FromInt(result);
Steve Block59151502010-09-22 15:07:15 +010010262 } else if (object->IsJSArray()) {
10263 return JSArray::cast(object)->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000010264 } else {
Steve Block59151502010-09-22 15:07:15 +010010265 return Smi::FromInt(FixedArray::cast(elements)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010266 }
10267}
10268
10269
Ben Murdoch8b112d22011-06-08 16:22:53 +010010270RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
Steve Block44f0eee2011-05-26 01:26:41 +010010271 HandleScope handle_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010010272
10273 ASSERT_EQ(3, args.length());
10274
10275 CONVERT_ARG_CHECKED(JSObject, object, 0);
10276 Handle<Object> key1 = args.at<Object>(1);
10277 Handle<Object> key2 = args.at<Object>(2);
10278
10279 uint32_t index1, index2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010280 if (!key1->ToArrayIndex(&index1)
10281 || !key2->ToArrayIndex(&index2)) {
Steve Block44f0eee2011-05-26 01:26:41 +010010282 return isolate->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +010010283 }
10284
10285 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010286 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
Steve Block44f0eee2011-05-26 01:26:41 +010010287 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010288 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
Steve Block44f0eee2011-05-26 01:26:41 +010010289 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
Steve Block6ded16b2010-05-10 14:33:55 +010010290
Ben Murdochc7cc0282012-03-05 14:35:55 +000010291 RETURN_IF_EMPTY_HANDLE(
10292 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10293 RETURN_IF_EMPTY_HANDLE(
10294 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
Steve Block6ded16b2010-05-10 14:33:55 +010010295
Steve Block44f0eee2011-05-26 01:26:41 +010010296 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010010297}
10298
10299
Steve Blocka7e24c12009-10-30 11:49:00 +000010300// Returns an array that tells you where in the [0, length) interval an array
Steve Block59151502010-09-22 15:07:15 +010010301// might have elements. Can either return keys (positive integers) or
10302// intervals (pair of a negative integer (-start-1) followed by a
10303// positive (length)) or undefined values.
10304// Intervals can span over some keys that are not in the object.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010305RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010306 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010010307 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010308 CONVERT_ARG_CHECKED(JSObject, array, 0);
10309 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
10310 if (array->elements()->IsDictionary()) {
10311 // Create an array and get all the keys into it, then remove all the
10312 // keys that are not integers in the range 0 to length-1.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010313 bool threw = false;
10314 Handle<FixedArray> keys =
10315 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10316 if (threw) return Failure::Exception();
10317
Steve Blocka7e24c12009-10-30 11:49:00 +000010318 int keys_length = keys->length();
10319 for (int i = 0; i < keys_length; i++) {
10320 Object* key = keys->get(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010321 uint32_t index = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010322 if (!key->ToArrayIndex(&index) || index >= length) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010323 // Zap invalid keys.
10324 keys->set_undefined(i);
10325 }
10326 }
Steve Block44f0eee2011-05-26 01:26:41 +010010327 return *isolate->factory()->NewJSArrayWithElements(keys);
Steve Blocka7e24c12009-10-30 11:49:00 +000010328 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010329 ASSERT(array->HasFastElements() ||
10330 array->HasFastSmiOnlyElements() ||
10331 array->HasFastDoubleElements());
Steve Block44f0eee2011-05-26 01:26:41 +010010332 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010333 // -1 means start of array.
Leon Clarke4515c472010-02-03 11:58:03 +000010334 single_interval->set(0, Smi::FromInt(-1));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010335 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010336 uint32_t actual_length =
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010337 static_cast<uint32_t>(elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010338 uint32_t min_length = actual_length < length ? actual_length : length;
10339 Handle<Object> length_object =
Steve Block44f0eee2011-05-26 01:26:41 +010010340 isolate->factory()->NewNumber(static_cast<double>(min_length));
Steve Blocka7e24c12009-10-30 11:49:00 +000010341 single_interval->set(1, *length_object);
Steve Block44f0eee2011-05-26 01:26:41 +010010342 return *isolate->factory()->NewJSArrayWithElements(single_interval);
Steve Blocka7e24c12009-10-30 11:49:00 +000010343 }
10344}
10345
10346
10347// DefineAccessor takes an optional final argument which is the
Ben Murdochc7cc0282012-03-05 14:35:55 +000010348// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
Steve Blocka7e24c12009-10-30 11:49:00 +000010349// to the way accessors are implemented, it is set for both the getter
10350// and setter on the first call to DefineAccessor and ignored on
10351// subsequent calls.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010352RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010353 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10354 // Compute attributes.
10355 PropertyAttributes attributes = NONE;
10356 if (args.length() == 5) {
10357 CONVERT_CHECKED(Smi, attrs, args[4]);
10358 int value = attrs->value();
10359 // Only attribute bits should be set.
10360 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10361 attributes = static_cast<PropertyAttributes>(value);
10362 }
10363
10364 CONVERT_CHECKED(JSObject, obj, args[0]);
10365 CONVERT_CHECKED(String, name, args[1]);
10366 CONVERT_CHECKED(Smi, flag, args[2]);
10367 CONVERT_CHECKED(JSFunction, fun, args[3]);
10368 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10369}
10370
10371
Ben Murdoch8b112d22011-06-08 16:22:53 +010010372RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010373 ASSERT(args.length() == 3);
10374 CONVERT_CHECKED(JSObject, obj, args[0]);
10375 CONVERT_CHECKED(String, name, args[1]);
10376 CONVERT_CHECKED(Smi, flag, args[2]);
10377 return obj->LookupAccessor(name, flag->value() == 0);
10378}
10379
10380
10381#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +010010382RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010383 ASSERT(args.length() == 0);
10384 return Execution::DebugBreakHelper();
10385}
10386
10387
10388// Helper functions for wrapping and unwrapping stack frame ids.
10389static Smi* WrapFrameId(StackFrame::Id id) {
10390 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
10391 return Smi::FromInt(id >> 2);
10392}
10393
10394
10395static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10396 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10397}
10398
10399
10400// Adds a JavaScript function as a debug event listener.
10401// args[0]: debug event listener function to set or null or undefined for
10402// clearing the event listener function
10403// args[1]: object supplied during callback
Ben Murdoch8b112d22011-06-08 16:22:53 +010010404RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010405 ASSERT(args.length() == 2);
10406 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10407 args[0]->IsUndefined() ||
10408 args[0]->IsNull());
10409 Handle<Object> callback = args.at<Object>(0);
10410 Handle<Object> data = args.at<Object>(1);
Steve Block44f0eee2011-05-26 01:26:41 +010010411 isolate->debugger()->SetEventListener(callback, data);
Steve Blocka7e24c12009-10-30 11:49:00 +000010412
Steve Block44f0eee2011-05-26 01:26:41 +010010413 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010414}
10415
10416
Ben Murdoch8b112d22011-06-08 16:22:53 +010010417RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010418 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010419 isolate->stack_guard()->DebugBreak();
10420 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010421}
10422
10423
Steve Block44f0eee2011-05-26 01:26:41 +010010424static MaybeObject* DebugLookupResultValue(Heap* heap,
10425 Object* receiver,
10426 String* name,
John Reck59135872010-11-02 12:39:01 -070010427 LookupResult* result,
10428 bool* caught_exception) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010429 Object* value;
10430 switch (result->type()) {
10431 case NORMAL:
10432 value = result->holder()->GetNormalizedProperty(result);
10433 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010434 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010435 }
10436 return value;
10437 case FIELD:
10438 value =
10439 JSObject::cast(
10440 result->holder())->FastPropertyAt(result->GetFieldIndex());
10441 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010442 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010443 }
10444 return value;
10445 case CONSTANT_FUNCTION:
10446 return result->GetConstantFunction();
10447 case CALLBACKS: {
10448 Object* structure = result->GetCallbackObject();
Ben Murdoch257744e2011-11-30 15:57:28 +000010449 if (structure->IsForeign() || structure->IsAccessorInfo()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010450 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10451 receiver, structure, name);
John Reck59135872010-11-02 12:39:01 -070010452 if (!maybe_value->ToObject(&value)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010453 if (maybe_value->IsRetryAfterGC()) return maybe_value;
John Reck59135872010-11-02 12:39:01 -070010454 ASSERT(maybe_value->IsException());
Steve Block44f0eee2011-05-26 01:26:41 +010010455 maybe_value = heap->isolate()->pending_exception();
10456 heap->isolate()->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000010457 if (caught_exception != NULL) {
10458 *caught_exception = true;
10459 }
John Reck59135872010-11-02 12:39:01 -070010460 return maybe_value;
Steve Blocka7e24c12009-10-30 11:49:00 +000010461 }
10462 return value;
10463 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010464 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010465 }
10466 }
10467 case INTERCEPTOR:
10468 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +000010469 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +000010470 case CONSTANT_TRANSITION:
10471 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +010010472 return heap->undefined_value();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010473 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +000010474 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010475 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010476 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010477 UNREACHABLE(); // keep the compiler happy
Steve Block44f0eee2011-05-26 01:26:41 +010010478 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010479}
10480
10481
10482// Get debugger related details for an object property.
10483// args[0]: object holding property
10484// args[1]: name of the property
10485//
10486// The array returned contains the following information:
10487// 0: Property value
10488// 1: Property details
10489// 2: Property value is exception
10490// 3: Getter function if defined
10491// 4: Setter function if defined
10492// Items 2-4 are only filled if the property has either a getter or a setter
10493// defined through __defineGetter__ and/or __defineSetter__.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010494RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010495 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010496
10497 ASSERT(args.length() == 2);
10498
10499 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10500 CONVERT_ARG_CHECKED(String, name, 1);
10501
10502 // Make sure to set the current context to the context before the debugger was
10503 // entered (if the debugger is entered). The reason for switching context here
10504 // is that for some property lookups (accessors and interceptors) callbacks
10505 // into the embedding application can occour, and the embedding application
10506 // could have the assumption that its own global context is the current
10507 // context and not some internal debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +010010508 SaveContext save(isolate);
10509 if (isolate->debug()->InDebugger()) {
10510 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000010511 }
10512
10513 // Skip the global proxy as it has no properties and always delegates to the
10514 // real global object.
10515 if (obj->IsJSGlobalProxy()) {
10516 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10517 }
10518
10519
10520 // Check if the name is trivially convertible to an index and get the element
10521 // if so.
10522 uint32_t index;
10523 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +010010524 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
John Reck59135872010-11-02 12:39:01 -070010525 Object* element_or_char;
10526 { MaybeObject* maybe_element_or_char =
Steve Block44f0eee2011-05-26 01:26:41 +010010527 Runtime::GetElementOrCharAt(isolate, obj, index);
John Reck59135872010-11-02 12:39:01 -070010528 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10529 return maybe_element_or_char;
10530 }
10531 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010532 details->set(0, element_or_char);
Steve Blocka7e24c12009-10-30 11:49:00 +000010533 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +010010534 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010535 }
10536
10537 // Find the number of objects making up this.
10538 int length = LocalPrototypeChainLength(*obj);
10539
10540 // Try local lookup on each of the objects.
10541 Handle<JSObject> jsproto = obj;
10542 for (int i = 0; i < length; i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010543 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010544 jsproto->LocalLookup(*name, &result);
10545 if (result.IsProperty()) {
10546 // LookupResult is not GC safe as it holds raw object pointers.
10547 // GC can happen later in this code so put the required fields into
10548 // local variables using handles when required for later use.
10549 PropertyType result_type = result.type();
10550 Handle<Object> result_callback_obj;
10551 if (result_type == CALLBACKS) {
Steve Block44f0eee2011-05-26 01:26:41 +010010552 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10553 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010554 }
10555 Smi* property_details = result.GetPropertyDetails().AsSmi();
10556 // DebugLookupResultValue can cause GC so details from LookupResult needs
10557 // to be copied to handles before this.
10558 bool caught_exception = false;
John Reck59135872010-11-02 12:39:01 -070010559 Object* raw_value;
10560 { MaybeObject* maybe_raw_value =
Steve Block44f0eee2011-05-26 01:26:41 +010010561 DebugLookupResultValue(isolate->heap(), *obj, *name,
10562 &result, &caught_exception);
John Reck59135872010-11-02 12:39:01 -070010563 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10564 }
Steve Block44f0eee2011-05-26 01:26:41 +010010565 Handle<Object> value(raw_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010566
10567 // If the callback object is a fixed array then it contains JavaScript
10568 // getter and/or setter.
10569 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
Ben Murdochc7cc0282012-03-05 14:35:55 +000010570 result_callback_obj->IsAccessorPair();
Steve Blocka7e24c12009-10-30 11:49:00 +000010571 Handle<FixedArray> details =
Steve Block44f0eee2011-05-26 01:26:41 +010010572 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010573 details->set(0, *value);
10574 details->set(1, property_details);
10575 if (hasJavaScriptAccessors) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010576 details->set(2, isolate->heap()->ToBoolean(caught_exception));
Ben Murdochc7cc0282012-03-05 14:35:55 +000010577 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10578 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
Steve Blocka7e24c12009-10-30 11:49:00 +000010579 }
10580
Steve Block44f0eee2011-05-26 01:26:41 +010010581 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010582 }
10583 if (i < length - 1) {
10584 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10585 }
10586 }
10587
Steve Block44f0eee2011-05-26 01:26:41 +010010588 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010589}
10590
10591
Ben Murdoch8b112d22011-06-08 16:22:53 +010010592RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
Steve Block44f0eee2011-05-26 01:26:41 +010010593 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010594
10595 ASSERT(args.length() == 2);
10596
10597 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10598 CONVERT_ARG_CHECKED(String, name, 1);
10599
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010600 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010601 obj->Lookup(*name, &result);
10602 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010603 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010604 }
Steve Block44f0eee2011-05-26 01:26:41 +010010605 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010606}
10607
10608
Steve Blocka7e24c12009-10-30 11:49:00 +000010609// Return the property type calculated from the property details.
10610// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010612 ASSERT(args.length() == 1);
10613 CONVERT_CHECKED(Smi, details, args[0]);
10614 PropertyType type = PropertyDetails(details).type();
10615 return Smi::FromInt(static_cast<int>(type));
10616}
10617
10618
10619// Return the property attribute calculated from the property details.
10620// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010621RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010622 ASSERT(args.length() == 1);
10623 CONVERT_CHECKED(Smi, details, args[0]);
10624 PropertyAttributes attributes = PropertyDetails(details).attributes();
10625 return Smi::FromInt(static_cast<int>(attributes));
10626}
10627
10628
10629// Return the property insertion index calculated from the property details.
10630// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010631RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010632 ASSERT(args.length() == 1);
10633 CONVERT_CHECKED(Smi, details, args[0]);
10634 int index = PropertyDetails(details).index();
10635 return Smi::FromInt(index);
10636}
10637
10638
Steve Blocka7e24c12009-10-30 11:49:00 +000010639// Return property value from named interceptor.
10640// args[0]: object
10641// args[1]: property name
Ben Murdoch8b112d22011-06-08 16:22:53 +010010642RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
Steve Block44f0eee2011-05-26 01:26:41 +010010643 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010644 ASSERT(args.length() == 2);
10645 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10646 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10647 CONVERT_ARG_CHECKED(String, name, 1);
10648
10649 PropertyAttributes attributes;
10650 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
10651}
10652
10653
10654// Return element value from indexed interceptor.
10655// args[0]: object
10656// args[1]: index
Ben Murdoch8b112d22011-06-08 16:22:53 +010010657RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
Steve Block44f0eee2011-05-26 01:26:41 +010010658 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010659 ASSERT(args.length() == 2);
10660 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10661 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10662 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10663
10664 return obj->GetElementWithInterceptor(*obj, index);
10665}
10666
10667
Ben Murdoch8b112d22011-06-08 16:22:53 +010010668RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010669 ASSERT(args.length() >= 1);
10670 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
10671 // Check that the break id is valid.
Steve Block44f0eee2011-05-26 01:26:41 +010010672 if (isolate->debug()->break_id() == 0 ||
10673 break_id != isolate->debug()->break_id()) {
10674 return isolate->Throw(
10675 isolate->heap()->illegal_execution_state_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010676 }
10677
Steve Block44f0eee2011-05-26 01:26:41 +010010678 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010679}
10680
10681
Ben Murdoch8b112d22011-06-08 16:22:53 +010010682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010010683 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010684 ASSERT(args.length() == 1);
10685
10686 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010687 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010688 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10689 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010690 if (!maybe_result->ToObject(&result)) return maybe_result;
10691 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010692
10693 // Count all frames which are relevant to debugging stack trace.
10694 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010695 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +000010696 if (id == StackFrame::NO_ID) {
10697 // If there is no JavaScript stack frame count is 0.
10698 return Smi::FromInt(0);
10699 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010700
10701 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10702 n += it.frame()->GetInlineCount();
10703 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010704 return Smi::FromInt(n);
10705}
10706
10707
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010708class FrameInspector {
10709 public:
10710 FrameInspector(JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010711 int inlined_jsframe_index,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010712 Isolate* isolate)
10713 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10714 // Calculate the deoptimized frame.
10715 if (frame->is_optimized()) {
10716 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
Ben Murdochc7cc0282012-03-05 14:35:55 +000010717 frame, inlined_jsframe_index, isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010718 }
10719 has_adapted_arguments_ = frame_->has_adapted_arguments();
10720 is_optimized_ = frame_->is_optimized();
10721 }
10722
10723 ~FrameInspector() {
10724 // Get rid of the calculated deoptimized frame if any.
10725 if (deoptimized_frame_ != NULL) {
10726 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10727 isolate_);
10728 }
10729 }
10730
10731 int GetParametersCount() {
10732 return is_optimized_
10733 ? deoptimized_frame_->parameters_count()
10734 : frame_->ComputeParametersCount();
10735 }
10736 int expression_count() { return deoptimized_frame_->expression_count(); }
10737 Object* GetFunction() {
10738 return is_optimized_
10739 ? deoptimized_frame_->GetFunction()
10740 : frame_->function();
10741 }
10742 Object* GetParameter(int index) {
10743 return is_optimized_
10744 ? deoptimized_frame_->GetParameter(index)
10745 : frame_->GetParameter(index);
10746 }
10747 Object* GetExpression(int index) {
10748 return is_optimized_
10749 ? deoptimized_frame_->GetExpression(index)
10750 : frame_->GetExpression(index);
10751 }
10752
10753 // To inspect all the provided arguments the frame might need to be
10754 // replaced with the arguments frame.
10755 void SetArgumentsFrame(JavaScriptFrame* frame) {
10756 ASSERT(has_adapted_arguments_);
10757 frame_ = frame;
10758 is_optimized_ = frame_->is_optimized();
10759 ASSERT(!is_optimized_);
10760 }
10761
10762 private:
10763 JavaScriptFrame* frame_;
10764 DeoptimizedFrameInfo* deoptimized_frame_;
10765 Isolate* isolate_;
10766 bool is_optimized_;
10767 bool has_adapted_arguments_;
10768
10769 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10770};
10771
10772
Steve Blocka7e24c12009-10-30 11:49:00 +000010773static const int kFrameDetailsFrameIdIndex = 0;
10774static const int kFrameDetailsReceiverIndex = 1;
10775static const int kFrameDetailsFunctionIndex = 2;
10776static const int kFrameDetailsArgumentCountIndex = 3;
10777static const int kFrameDetailsLocalCountIndex = 4;
10778static const int kFrameDetailsSourcePositionIndex = 5;
10779static const int kFrameDetailsConstructCallIndex = 6;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010780static const int kFrameDetailsAtReturnIndex = 7;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010781static const int kFrameDetailsFlagsIndex = 8;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010782static const int kFrameDetailsFirstDynamicIndex = 9;
Steve Blocka7e24c12009-10-30 11:49:00 +000010783
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010784
10785static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10786 JavaScriptFrame* frame) {
10787 SaveContext* save = isolate->save_context();
10788 while (save != NULL && !save->IsBelowFrame(frame)) {
10789 save = save->prev();
10790 }
10791 ASSERT(save != NULL);
10792 return save;
10793}
10794
10795
Steve Blocka7e24c12009-10-30 11:49:00 +000010796// Return an array with frame details
10797// args[0]: number: break id
10798// args[1]: number: frame index
10799//
10800// The array returned contains the following information:
10801// 0: Frame id
10802// 1: Receiver
10803// 2: Function
10804// 3: Argument count
10805// 4: Local count
10806// 5: Source position
10807// 6: Constructor call
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010808// 7: Is at return
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010809// 8: Flags
Steve Blocka7e24c12009-10-30 11:49:00 +000010810// Arguments name, value
10811// Locals name, value
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010812// Return value if any
Ben Murdoch8b112d22011-06-08 16:22:53 +010010813RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010814 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010815 ASSERT(args.length() == 2);
10816
10817 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010818 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010819 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10820 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010821 if (!maybe_check->ToObject(&check)) return maybe_check;
10822 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010823 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +010010824 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010825
10826 // Find the relevant frame with the requested index.
Steve Block44f0eee2011-05-26 01:26:41 +010010827 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +000010828 if (id == StackFrame::NO_ID) {
10829 // If there are no JavaScript stack frames return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +010010830 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010831 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010832
Steve Blocka7e24c12009-10-30 11:49:00 +000010833 int count = 0;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010834 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000010835 for (; !it.done(); it.Advance()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010836 if (index < count + it.frame()->GetInlineCount()) break;
10837 count += it.frame()->GetInlineCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010838 }
Steve Block44f0eee2011-05-26 01:26:41 +010010839 if (it.done()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010840
Ben Murdochc7cc0282012-03-05 14:35:55 +000010841 bool is_optimized = it.frame()->is_optimized();
10842
10843 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10844 if (is_optimized) {
10845 inlined_jsframe_index =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010846 it.frame()->GetInlineCount() - (index - count) - 1;
10847 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000010848 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010849
Steve Blocka7e24c12009-10-30 11:49:00 +000010850 // Traverse the saved contexts chain to find the active context for the
10851 // selected frame.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010852 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
Steve Blocka7e24c12009-10-30 11:49:00 +000010853
10854 // Get the frame id.
Steve Block44f0eee2011-05-26 01:26:41 +010010855 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010856
10857 // Find source position.
Steve Block44f0eee2011-05-26 01:26:41 +010010858 int position =
Ben Murdoch8b112d22011-06-08 16:22:53 +010010859 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
Steve Blocka7e24c12009-10-30 11:49:00 +000010860
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010861 // Check for constructor frame. Inlined frames cannot be construct calls.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010862 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010863 bool constructor = !inlined_frame && it.frame()->IsConstructor();
Steve Blocka7e24c12009-10-30 11:49:00 +000010864
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010865 // Get scope info and read from it for local variable information.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010866 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010867 Handle<SharedFunctionInfo> shared(function->shared());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010868 Handle<ScopeInfo> scope_info(shared->scope_info());
10869 ASSERT(*scope_info != ScopeInfo::Empty());
Steve Blocka7e24c12009-10-30 11:49:00 +000010870
Steve Blocka7e24c12009-10-30 11:49:00 +000010871 // Get the locals names and values into a temporary array.
10872 //
10873 // TODO(1240907): Hide compiler-introduced stack variables
10874 // (e.g. .result)? For users of the debugger, they will probably be
10875 // confusing.
Steve Block44f0eee2011-05-26 01:26:41 +010010876 Handle<FixedArray> locals =
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010877 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010878
Ben Murdochb0fe1622011-05-05 13:52:32 +010010879 // Fill in the values of the locals.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010880 int i = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010881 for (; i < scope_info->StackLocalCount(); ++i) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010882 // Use the value from the stack.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010883 locals->set(i * 2, scope_info->LocalName(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010884 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
10885 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010886 if (i < scope_info->LocalCount()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010887 // Get the context containing declarations.
10888 Handle<Context> context(
10889 Context::cast(it.frame()->context())->declaration_context());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010890 for (; i < scope_info->LocalCount(); ++i) {
10891 Handle<String> name(scope_info->LocalName(i));
10892 VariableMode mode;
10893 InitializationFlag init_flag;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010894 locals->set(i * 2, *name);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010895 locals->set(i * 2 + 1, context->get(
10896 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
Steve Blocka7e24c12009-10-30 11:49:00 +000010897 }
10898 }
10899
Ben Murdochb0fe1622011-05-05 13:52:32 +010010900 // Check whether this frame is positioned at return. If not top
10901 // frame or if the frame is optimized it cannot be at a return.
10902 bool at_return = false;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010903 if (!is_optimized && index == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +010010904 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010905 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010906
10907 // If positioned just before return find the value to be returned and add it
10908 // to the frame information.
Steve Block44f0eee2011-05-26 01:26:41 +010010909 Handle<Object> return_value = isolate->factory()->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010910 if (at_return) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010911 StackFrameIterator it2(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010912 Address internal_frame_sp = NULL;
10913 while (!it2.done()) {
10914 if (it2.frame()->is_internal()) {
10915 internal_frame_sp = it2.frame()->sp();
10916 } else {
10917 if (it2.frame()->is_java_script()) {
10918 if (it2.frame()->id() == it.frame()->id()) {
10919 // The internal frame just before the JavaScript frame contains the
10920 // value to return on top. A debug break at return will create an
10921 // internal frame to store the return value (eax/rax/r0) before
10922 // entering the debug break exit frame.
10923 if (internal_frame_sp != NULL) {
10924 return_value =
Steve Block44f0eee2011-05-26 01:26:41 +010010925 Handle<Object>(Memory::Object_at(internal_frame_sp),
10926 isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010927 break;
10928 }
10929 }
10930 }
10931
10932 // Indicate that the previous frame was not an internal frame.
10933 internal_frame_sp = NULL;
10934 }
10935 it2.Advance();
10936 }
10937 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010938
10939 // Now advance to the arguments adapter frame (if any). It contains all
10940 // the provided parameters whereas the function frame always have the number
10941 // of arguments matching the functions parameters. The rest of the
10942 // information (except for what is collected above) is the same.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010943 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010944 it.AdvanceToArgumentsFrame();
10945 frame_inspector.SetArgumentsFrame(it.frame());
10946 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010947
10948 // Find the number of arguments to fill. At least fill the number of
10949 // parameters for the function and fill more if more parameters are provided.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010950 int argument_count = scope_info->ParameterCount();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010951 if (argument_count < frame_inspector.GetParametersCount()) {
10952 argument_count = frame_inspector.GetParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +000010953 }
10954
10955 // Calculate the size of the result.
10956 int details_size = kFrameDetailsFirstDynamicIndex +
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010957 2 * (argument_count + scope_info->LocalCount()) +
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010958 (at_return ? 1 : 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010959 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +000010960
10961 // Add the frame id.
10962 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10963
10964 // Add the function (same as in function frame).
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010965 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000010966
10967 // Add the arguments count.
10968 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10969
10970 // Add the locals count
10971 details->set(kFrameDetailsLocalCountIndex,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010972 Smi::FromInt(scope_info->LocalCount()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010973
10974 // Add the source position.
10975 if (position != RelocInfo::kNoPosition) {
10976 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10977 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010010978 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010979 }
10980
10981 // Add the constructor information.
Steve Block44f0eee2011-05-26 01:26:41 +010010982 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
Steve Blocka7e24c12009-10-30 11:49:00 +000010983
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010984 // Add the at return information.
Steve Block44f0eee2011-05-26 01:26:41 +010010985 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010986
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010987 // Add flags to indicate information on whether this frame is
10988 // bit 0: invoked in the debugger context.
10989 // bit 1: optimized frame.
10990 // bit 2: inlined in optimized frame
10991 int flags = 0;
10992 if (*save->context() == *isolate->debug()->debug_context()) {
10993 flags |= 1 << 0;
10994 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000010995 if (is_optimized) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010996 flags |= 1 << 1;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010997 flags |= inlined_jsframe_index << 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010998 }
10999 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
Steve Blocka7e24c12009-10-30 11:49:00 +000011000
11001 // Fill the dynamic part.
11002 int details_index = kFrameDetailsFirstDynamicIndex;
11003
11004 // Add arguments name and value.
11005 for (int i = 0; i < argument_count; i++) {
11006 // Name of the argument.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011007 if (i < scope_info->ParameterCount()) {
11008 details->set(details_index++, scope_info->ParameterName(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011009 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010011010 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011011 }
11012
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011013 // Parameter value.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011014 if (i < frame_inspector.GetParametersCount()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011015 // Get the value from the stack.
11016 details->set(details_index++, frame_inspector.GetParameter(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011017 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010011018 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011019 }
11020 }
11021
11022 // Add locals name and value from the temporary copy from the function frame.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011023 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011024 details->set(details_index++, locals->get(i));
11025 }
11026
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010011027 // Add the value being returned.
11028 if (at_return) {
11029 details->set(details_index++, *return_value);
11030 }
11031
Steve Blocka7e24c12009-10-30 11:49:00 +000011032 // Add the receiver (same as in function frame).
11033 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11034 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
Steve Block44f0eee2011-05-26 01:26:41 +010011035 Handle<Object> receiver(it.frame()->receiver(), isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011036 if (!receiver->IsJSObject() &&
11037 shared->is_classic_mode() &&
11038 !shared->native()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011039 // If the receiver is not a JSObject and the function is not a
11040 // builtin or strict-mode we have hit an optimization where a
11041 // value object is not converted into a wrapped JS objects. To
11042 // hide this optimization from the debugger, we wrap the receiver
Steve Blocka7e24c12009-10-30 11:49:00 +000011043 // by creating correct wrapper object based on the calling frame's
11044 // global context.
11045 it.Advance();
11046 Handle<Context> calling_frames_global_context(
11047 Context::cast(Context::cast(it.frame()->context())->global_context()));
Steve Block44f0eee2011-05-26 01:26:41 +010011048 receiver =
11049 isolate->factory()->ToObject(receiver, calling_frames_global_context);
Steve Blocka7e24c12009-10-30 11:49:00 +000011050 }
11051 details->set(kFrameDetailsReceiverIndex, *receiver);
11052
11053 ASSERT_EQ(details_size, details_index);
Steve Block44f0eee2011-05-26 01:26:41 +010011054 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011055}
11056
11057
11058// Copy all the context locals into an object used to materialize a scope.
Steve Block1e0659c2011-05-24 12:43:12 +010011059static bool CopyContextLocalsToScopeObject(
Steve Block44f0eee2011-05-26 01:26:41 +010011060 Isolate* isolate,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011061 Handle<ScopeInfo> scope_info,
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011062 Handle<Context> context,
11063 Handle<JSObject> scope_object) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011064 // Fill all context locals to the context extension.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011065 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11066 VariableMode mode;
11067 InitializationFlag init_flag;
11068 int context_index = scope_info->ContextSlotIndex(
11069 scope_info->ContextLocalName(i), &mode, &init_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +000011070
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011071 RETURN_IF_EMPTY_HANDLE_VALUE(
11072 isolate,
11073 SetProperty(scope_object,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011074 Handle<String>(scope_info->ContextLocalName(i)),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011075 Handle<Object>(context->get(context_index), isolate),
11076 NONE,
11077 kNonStrictMode),
11078 false);
Steve Blocka7e24c12009-10-30 11:49:00 +000011079 }
Steve Block1e0659c2011-05-24 12:43:12 +010011080
11081 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000011082}
11083
11084
11085// Create a plain JSObject which materializes the local scope for the specified
11086// frame.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011087static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011088 Isolate* isolate,
11089 JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000011090 FrameInspector* frame_inspector) {
11091 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011092 Handle<SharedFunctionInfo> shared(function->shared());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011093 Handle<ScopeInfo> scope_info(shared->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000011094
11095 // Allocate and initialize a JSObject with all the arguments, stack locals
11096 // heap locals and extension properties of the debugged function.
Steve Block44f0eee2011-05-26 01:26:41 +010011097 Handle<JSObject> local_scope =
11098 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +000011099
11100 // First fill all parameters.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011101 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011102 Handle<Object> value(
11103 i < frame_inspector->GetParametersCount() ?
11104 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11105
Steve Block1e0659c2011-05-24 12:43:12 +010011106 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +010011107 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +010011108 SetProperty(local_scope,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011109 Handle<String>(scope_info->ParameterName(i)),
Ben Murdochc7cc0282012-03-05 14:35:55 +000011110 value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011111 NONE,
11112 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010011113 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000011114 }
11115
11116 // Second fill all stack locals.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011117 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
Steve Block1e0659c2011-05-24 12:43:12 +010011118 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +010011119 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +010011120 SetProperty(local_scope,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011121 Handle<String>(scope_info->StackLocalName(i)),
Ben Murdochc7cc0282012-03-05 14:35:55 +000011122 Handle<Object>(frame_inspector->GetExpression(i)),
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011123 NONE,
11124 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010011125 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000011126 }
11127
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011128 if (scope_info->HasContext()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011129 // Third fill all context locals.
11130 Handle<Context> frame_context(Context::cast(frame->context()));
11131 Handle<Context> function_context(frame_context->declaration_context());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011132 if (!CopyContextLocalsToScopeObject(
11133 isolate, scope_info, function_context, local_scope)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011134 return Handle<JSObject>();
11135 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011136
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011137 // Finally copy any properties from the function context extension.
11138 // These will be variables introduced by eval.
11139 if (function_context->closure() == *function) {
11140 if (function_context->has_extension() &&
11141 !function_context->IsGlobalContext()) {
11142 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011143 bool threw = false;
11144 Handle<FixedArray> keys =
11145 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11146 if (threw) return Handle<JSObject>();
11147
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011148 for (int i = 0; i < keys->length(); i++) {
11149 // Names of variables introduced by eval are strings.
11150 ASSERT(keys->get(i)->IsString());
11151 Handle<String> key(String::cast(keys->get(i)));
11152 RETURN_IF_EMPTY_HANDLE_VALUE(
11153 isolate,
11154 SetProperty(local_scope,
11155 key,
11156 GetProperty(ext, key),
11157 NONE,
11158 kNonStrictMode),
11159 Handle<JSObject>());
11160 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011161 }
11162 }
11163 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011164
Steve Blocka7e24c12009-10-30 11:49:00 +000011165 return local_scope;
11166}
11167
11168
Ben Murdochc7cc0282012-03-05 14:35:55 +000011169static Handle<JSObject> MaterializeLocalScope(
11170 Isolate* isolate,
11171 JavaScriptFrame* frame,
11172 int inlined_jsframe_index) {
11173 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11174 return MaterializeLocalScopeWithFrameInspector(isolate,
11175 frame,
11176 &frame_inspector);
11177}
11178
11179
Steve Blocka7e24c12009-10-30 11:49:00 +000011180// Create a plain JSObject which materializes the closure content for the
11181// context.
Steve Block44f0eee2011-05-26 01:26:41 +010011182static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11183 Handle<Context> context) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011184 ASSERT(context->IsFunctionContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011185
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011186 Handle<SharedFunctionInfo> shared(context->closure()->shared());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011187 Handle<ScopeInfo> scope_info(shared->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000011188
Ben Murdochc7cc0282012-03-05 14:35:55 +000011189 // Allocate and initialize a JSObject with all the content of this function
Steve Blocka7e24c12009-10-30 11:49:00 +000011190 // closure.
Steve Block44f0eee2011-05-26 01:26:41 +010011191 Handle<JSObject> closure_scope =
11192 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +000011193
Steve Blocka7e24c12009-10-30 11:49:00 +000011194 // Fill all context locals to the context extension.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011195 if (!CopyContextLocalsToScopeObject(
11196 isolate, scope_info, context, closure_scope)) {
Steve Block1e0659c2011-05-24 12:43:12 +010011197 return Handle<JSObject>();
11198 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011199
11200 // Finally copy any properties from the function context extension. This will
11201 // be variables introduced by eval.
11202 if (context->has_extension()) {
11203 Handle<JSObject> ext(JSObject::cast(context->extension()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011204 bool threw = false;
11205 Handle<FixedArray> keys =
11206 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11207 if (threw) return Handle<JSObject>();
11208
Steve Blocka7e24c12009-10-30 11:49:00 +000011209 for (int i = 0; i < keys->length(); i++) {
11210 // Names of variables introduced by eval are strings.
11211 ASSERT(keys->get(i)->IsString());
11212 Handle<String> key(String::cast(keys->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +010011213 RETURN_IF_EMPTY_HANDLE_VALUE(
11214 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011215 SetProperty(closure_scope,
11216 key,
11217 GetProperty(ext, key),
11218 NONE,
11219 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +010011220 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +000011221 }
11222 }
11223
11224 return closure_scope;
11225}
11226
11227
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011228// Create a plain JSObject which materializes the scope for the specified
11229// catch context.
11230static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11231 Handle<Context> context) {
11232 ASSERT(context->IsCatchContext());
11233 Handle<String> name(String::cast(context->extension()));
11234 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11235 Handle<JSObject> catch_scope =
11236 isolate->factory()->NewJSObject(isolate->object_function());
11237 RETURN_IF_EMPTY_HANDLE_VALUE(
11238 isolate,
11239 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11240 Handle<JSObject>());
11241 return catch_scope;
11242}
11243
11244
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011245// Create a plain JSObject which materializes the block scope for the specified
11246// block context.
11247static Handle<JSObject> MaterializeBlockScope(
11248 Isolate* isolate,
11249 Handle<Context> context) {
11250 ASSERT(context->IsBlockContext());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011251 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011252
11253 // Allocate and initialize a JSObject with all the arguments, stack locals
11254 // heap locals and extension properties of the debugged function.
11255 Handle<JSObject> block_scope =
11256 isolate->factory()->NewJSObject(isolate->object_function());
11257
11258 // Fill all context locals.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011259 if (!CopyContextLocalsToScopeObject(
11260 isolate, scope_info, context, block_scope)) {
11261 return Handle<JSObject>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011262 }
11263
11264 return block_scope;
11265}
11266
11267
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011268// Iterate over the actual scopes visible from a stack frame. The iteration
11269// proceeds from the innermost visible nested scope outwards. All scopes are
Steve Blocka7e24c12009-10-30 11:49:00 +000011270// backed by an actual context except the local scope, which is inserted
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011271// "artificially" in the context chain.
Steve Blocka7e24c12009-10-30 11:49:00 +000011272class ScopeIterator {
11273 public:
11274 enum ScopeType {
11275 ScopeTypeGlobal = 0,
11276 ScopeTypeLocal,
11277 ScopeTypeWith,
11278 ScopeTypeClosure,
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011279 ScopeTypeCatch,
11280 ScopeTypeBlock
Steve Blocka7e24c12009-10-30 11:49:00 +000011281 };
11282
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011283 ScopeIterator(Isolate* isolate,
11284 JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000011285 int inlined_jsframe_index)
Steve Block44f0eee2011-05-26 01:26:41 +010011286 : isolate_(isolate),
11287 frame_(frame),
Ben Murdochc7cc0282012-03-05 14:35:55 +000011288 inlined_jsframe_index_(inlined_jsframe_index),
Steve Blocka7e24c12009-10-30 11:49:00 +000011289 function_(JSFunction::cast(frame->function())),
11290 context_(Context::cast(frame->context())),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011291 nested_scope_chain_(4) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011292
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011293 // Catch the case when the debugger stops in an internal function.
11294 Handle<SharedFunctionInfo> shared_info(function_->shared());
11295 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11296 if (shared_info->script() == isolate->heap()->undefined_value()) {
11297 while (context_->closure() == *function_) {
11298 context_ = Handle<Context>(context_->previous(), isolate_);
11299 }
11300 return;
11301 }
11302
11303 // Get the debug info (create it if it does not exist).
11304 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11305 // Return if ensuring debug info failed.
11306 return;
11307 }
11308 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11309
11310 // Find the break point where execution has stopped.
11311 BreakLocationIterator break_location_iterator(debug_info,
11312 ALL_BREAK_LOCATIONS);
11313 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11314 if (break_location_iterator.IsExit()) {
11315 // We are within the return sequence. At the momemt it is not possible to
11316 // get a source position which is consistent with the current scope chain.
11317 // Thus all nested with, catch and block contexts are skipped and we only
11318 // provide the function scope.
11319 if (scope_info->HasContext()) {
11320 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11321 } else {
11322 while (context_->closure() == *function_) {
11323 context_ = Handle<Context>(context_->previous(), isolate_);
11324 }
11325 }
11326 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11327 } else {
11328 // Reparse the code and analyze the scopes.
11329 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11330 Handle<Script> script(Script::cast(shared_info->script()));
11331 Scope* scope = NULL;
11332
11333 // Check whether we are in global, eval or function code.
11334 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11335 if (scope_info->Type() != FUNCTION_SCOPE) {
11336 // Global or eval code.
11337 CompilationInfo info(script);
11338 if (scope_info->Type() == GLOBAL_SCOPE) {
11339 info.MarkAsGlobal();
11340 } else {
11341 ASSERT(scope_info->Type() == EVAL_SCOPE);
11342 info.MarkAsEval();
11343 info.SetCallingContext(Handle<Context>(function_->context()));
11344 }
11345 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11346 scope = info.function()->scope();
11347 }
11348 } else {
11349 // Function code
11350 CompilationInfo info(shared_info);
11351 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11352 scope = info.function()->scope();
11353 }
11354 }
11355
11356 // Retrieve the scope chain for the current position.
11357 if (scope != NULL) {
11358 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11359 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11360 } else {
11361 // A failed reparse indicates that the preparser has diverged from the
11362 // parser or that the preparse data given to the initial parse has been
11363 // faulty. We fail in debug mode but in release mode we only provide the
11364 // information we get from the context chain but nothing about
11365 // completely stack allocated scopes or stack allocated locals.
11366 UNREACHABLE();
11367 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011368 }
11369 }
11370
11371 // More scopes?
11372 bool Done() { return context_.is_null(); }
11373
11374 // Move to the next scope.
11375 void Next() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011376 ScopeType scope_type = Type();
11377 if (scope_type == ScopeTypeGlobal) {
11378 // The global scope is always the last in the chain.
11379 ASSERT(context_->IsGlobalContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011380 context_ = Handle<Context>();
11381 return;
11382 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011383 if (nested_scope_chain_.is_empty()) {
11384 context_ = Handle<Context>(context_->previous(), isolate_);
11385 } else {
11386 if (nested_scope_chain_.last()->HasContext()) {
11387 ASSERT(context_->previous() != NULL);
11388 context_ = Handle<Context>(context_->previous(), isolate_);
11389 }
11390 nested_scope_chain_.RemoveLast();
Steve Blocka7e24c12009-10-30 11:49:00 +000011391 }
11392 }
11393
11394 // Return the type of the current scope.
Ben Murdoch589d6972011-11-30 16:04:58 +000011395 ScopeType Type() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011396 if (!nested_scope_chain_.is_empty()) {
11397 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11398 switch (scope_info->Type()) {
11399 case FUNCTION_SCOPE:
11400 ASSERT(context_->IsFunctionContext() ||
11401 !scope_info->HasContext());
11402 return ScopeTypeLocal;
11403 case GLOBAL_SCOPE:
11404 ASSERT(context_->IsGlobalContext());
11405 return ScopeTypeGlobal;
11406 case WITH_SCOPE:
11407 ASSERT(context_->IsWithContext());
11408 return ScopeTypeWith;
11409 case CATCH_SCOPE:
11410 ASSERT(context_->IsCatchContext());
11411 return ScopeTypeCatch;
11412 case BLOCK_SCOPE:
11413 ASSERT(!scope_info->HasContext() ||
11414 context_->IsBlockContext());
11415 return ScopeTypeBlock;
11416 case EVAL_SCOPE:
11417 UNREACHABLE();
11418 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011419 }
11420 if (context_->IsGlobalContext()) {
11421 ASSERT(context_->global()->IsGlobalObject());
11422 return ScopeTypeGlobal;
11423 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011424 if (context_->IsFunctionContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011425 return ScopeTypeClosure;
11426 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011427 if (context_->IsCatchContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011428 return ScopeTypeCatch;
11429 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011430 if (context_->IsBlockContext()) {
11431 return ScopeTypeBlock;
11432 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011433 ASSERT(context_->IsWithContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011434 return ScopeTypeWith;
11435 }
11436
11437 // Return the JavaScript object with the content of the current scope.
11438 Handle<JSObject> ScopeObject() {
11439 switch (Type()) {
11440 case ScopeIterator::ScopeTypeGlobal:
11441 return Handle<JSObject>(CurrentContext()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +000011442 case ScopeIterator::ScopeTypeLocal:
11443 // Materialize the content of the local scope into a JSObject.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011444 ASSERT(nested_scope_chain_.length() == 1);
Ben Murdochc7cc0282012-03-05 14:35:55 +000011445 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
Steve Blocka7e24c12009-10-30 11:49:00 +000011446 case ScopeIterator::ScopeTypeWith:
Steve Blocka7e24c12009-10-30 11:49:00 +000011447 // Return the with object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011448 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11449 case ScopeIterator::ScopeTypeCatch:
11450 return MaterializeCatchScope(isolate_, CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011451 case ScopeIterator::ScopeTypeClosure:
11452 // Materialize the content of the closure scope into a JSObject.
Steve Block44f0eee2011-05-26 01:26:41 +010011453 return MaterializeClosure(isolate_, CurrentContext());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011454 case ScopeIterator::ScopeTypeBlock:
11455 return MaterializeBlockScope(isolate_, CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000011456 }
11457 UNREACHABLE();
11458 return Handle<JSObject>();
11459 }
11460
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011461 Handle<ScopeInfo> CurrentScopeInfo() {
11462 if (!nested_scope_chain_.is_empty()) {
11463 return nested_scope_chain_.last();
11464 } else if (context_->IsBlockContext()) {
11465 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11466 } else if (context_->IsFunctionContext()) {
11467 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11468 }
11469 return Handle<ScopeInfo>::null();
11470 }
11471
Steve Blocka7e24c12009-10-30 11:49:00 +000011472 // Return the context for this scope. For the local context there might not
11473 // be an actual context.
11474 Handle<Context> CurrentContext() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011475 if (Type() == ScopeTypeGlobal ||
11476 nested_scope_chain_.is_empty()) {
11477 return context_;
11478 } else if (nested_scope_chain_.last()->HasContext()) {
11479 return context_;
11480 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +000011481 return Handle<Context>();
11482 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011483 }
11484
11485#ifdef DEBUG
11486 // Debug print of the content of the current scope.
11487 void DebugPrint() {
11488 switch (Type()) {
11489 case ScopeIterator::ScopeTypeGlobal:
11490 PrintF("Global:\n");
11491 CurrentContext()->Print();
11492 break;
11493
11494 case ScopeIterator::ScopeTypeLocal: {
11495 PrintF("Local:\n");
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011496 function_->shared()->scope_info()->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011497 if (!CurrentContext().is_null()) {
11498 CurrentContext()->Print();
11499 if (CurrentContext()->has_extension()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011500 Handle<Object> extension(CurrentContext()->extension());
Steve Blocka7e24c12009-10-30 11:49:00 +000011501 if (extension->IsJSContextExtensionObject()) {
11502 extension->Print();
11503 }
11504 }
11505 }
11506 break;
11507 }
11508
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011509 case ScopeIterator::ScopeTypeWith:
Steve Blocka7e24c12009-10-30 11:49:00 +000011510 PrintF("With:\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011511 CurrentContext()->extension()->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011512 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011513
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011514 case ScopeIterator::ScopeTypeCatch:
Steve Blocka7e24c12009-10-30 11:49:00 +000011515 PrintF("Catch:\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011516 CurrentContext()->extension()->Print();
11517 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
Steve Blocka7e24c12009-10-30 11:49:00 +000011518 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011519
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011520 case ScopeIterator::ScopeTypeClosure:
Steve Blocka7e24c12009-10-30 11:49:00 +000011521 PrintF("Closure:\n");
11522 CurrentContext()->Print();
11523 if (CurrentContext()->has_extension()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011524 Handle<Object> extension(CurrentContext()->extension());
Steve Blocka7e24c12009-10-30 11:49:00 +000011525 if (extension->IsJSContextExtensionObject()) {
11526 extension->Print();
11527 }
11528 }
11529 break;
Steve Blocka7e24c12009-10-30 11:49:00 +000011530
11531 default:
11532 UNREACHABLE();
11533 }
11534 PrintF("\n");
11535 }
11536#endif
11537
11538 private:
Steve Block44f0eee2011-05-26 01:26:41 +010011539 Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011540 JavaScriptFrame* frame_;
Ben Murdochc7cc0282012-03-05 14:35:55 +000011541 int inlined_jsframe_index_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011542 Handle<JSFunction> function_;
11543 Handle<Context> context_;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011544 List<Handle<ScopeInfo> > nested_scope_chain_;
Steve Blocka7e24c12009-10-30 11:49:00 +000011545
11546 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11547};
11548
11549
Ben Murdoch8b112d22011-06-08 16:22:53 +010011550RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010011551 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011552 ASSERT(args.length() == 2);
11553
11554 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011555 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011556 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11557 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011558 if (!maybe_check->ToObject(&check)) return maybe_check;
11559 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011560 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11561
11562 // Get the frame where the debugging is performed.
11563 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011564 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000011565 JavaScriptFrame* frame = it.frame();
11566
11567 // Count the visible scopes.
11568 int n = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011569 for (ScopeIterator it(isolate, frame, 0);
11570 !it.Done();
11571 it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011572 n++;
11573 }
11574
11575 return Smi::FromInt(n);
11576}
11577
11578
11579static const int kScopeDetailsTypeIndex = 0;
11580static const int kScopeDetailsObjectIndex = 1;
11581static const int kScopeDetailsSize = 2;
11582
11583// Return an array with scope details
11584// args[0]: number: break id
11585// args[1]: number: frame index
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011586// args[2]: number: inlined frame index
11587// args[3]: number: scope index
Steve Blocka7e24c12009-10-30 11:49:00 +000011588//
11589// The array returned contains the following information:
11590// 0: Scope type
11591// 1: Scope object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011592RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010011593 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011594 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000011595
11596 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011597 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011598 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11599 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011600 if (!maybe_check->ToObject(&check)) return maybe_check;
11601 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011602 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
Ben Murdochc7cc0282012-03-05 14:35:55 +000011603 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011604 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011605
11606 // Get the frame where the debugging is performed.
11607 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011608 JavaScriptFrameIterator frame_it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000011609 JavaScriptFrame* frame = frame_it.frame();
11610
11611 // Find the requested scope.
11612 int n = 0;
Ben Murdochc7cc0282012-03-05 14:35:55 +000011613 ScopeIterator it(isolate, frame, inlined_jsframe_index);
Steve Blocka7e24c12009-10-30 11:49:00 +000011614 for (; !it.Done() && n < index; it.Next()) {
11615 n++;
11616 }
11617 if (it.Done()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011618 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011619 }
11620
11621 // Calculate the size of the result.
11622 int details_size = kScopeDetailsSize;
Steve Block44f0eee2011-05-26 01:26:41 +010011623 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +000011624
11625 // Fill in scope details.
11626 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011627 Handle<JSObject> scope_object = it.ScopeObject();
Steve Block44f0eee2011-05-26 01:26:41 +010011628 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011629 details->set(kScopeDetailsObjectIndex, *scope_object);
Steve Blocka7e24c12009-10-30 11:49:00 +000011630
Steve Block44f0eee2011-05-26 01:26:41 +010011631 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011632}
11633
11634
Ben Murdoch8b112d22011-06-08 16:22:53 +010011635RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
Steve Block44f0eee2011-05-26 01:26:41 +010011636 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011637 ASSERT(args.length() == 0);
11638
11639#ifdef DEBUG
11640 // Print the scopes for the top frame.
11641 StackFrameLocator locator;
11642 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011643 for (ScopeIterator it(isolate, frame, 0);
11644 !it.Done();
11645 it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011646 it.DebugPrint();
11647 }
11648#endif
Steve Block44f0eee2011-05-26 01:26:41 +010011649 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011650}
11651
11652
Ben Murdoch8b112d22011-06-08 16:22:53 +010011653RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010011654 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011655 ASSERT(args.length() == 1);
11656
11657 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011658 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011659 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11660 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011661 if (!maybe_result->ToObject(&result)) return maybe_result;
11662 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011663
11664 // Count all archived V8 threads.
11665 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011666 for (ThreadState* thread =
11667 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000011668 thread != NULL;
11669 thread = thread->Next()) {
11670 n++;
11671 }
11672
11673 // Total number of threads is current thread and archived threads.
11674 return Smi::FromInt(n + 1);
11675}
11676
11677
11678static const int kThreadDetailsCurrentThreadIndex = 0;
11679static const int kThreadDetailsThreadIdIndex = 1;
11680static const int kThreadDetailsSize = 2;
11681
11682// Return an array with thread details
11683// args[0]: number: break id
11684// args[1]: number: thread index
11685//
11686// The array returned contains the following information:
11687// 0: Is current thread?
11688// 1: Thread id
Ben Murdoch8b112d22011-06-08 16:22:53 +010011689RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010011690 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011691 ASSERT(args.length() == 2);
11692
11693 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011694 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011695 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11696 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011697 if (!maybe_check->ToObject(&check)) return maybe_check;
11698 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011699 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11700
11701 // Allocate array for result.
Steve Block44f0eee2011-05-26 01:26:41 +010011702 Handle<FixedArray> details =
11703 isolate->factory()->NewFixedArray(kThreadDetailsSize);
Steve Blocka7e24c12009-10-30 11:49:00 +000011704
11705 // Thread index 0 is current thread.
11706 if (index == 0) {
11707 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010011708 details->set(kThreadDetailsCurrentThreadIndex,
11709 isolate->heap()->true_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011710 details->set(kThreadDetailsThreadIdIndex,
Ben Murdoch8b112d22011-06-08 16:22:53 +010011711 Smi::FromInt(ThreadId::Current().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011712 } else {
11713 // Find the thread with the requested index.
11714 int n = 1;
Steve Block44f0eee2011-05-26 01:26:41 +010011715 ThreadState* thread =
11716 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000011717 while (index != n && thread != NULL) {
11718 thread = thread->Next();
11719 n++;
11720 }
11721 if (thread == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010011722 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011723 }
11724
11725 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010011726 details->set(kThreadDetailsCurrentThreadIndex,
11727 isolate->heap()->false_value());
Ben Murdoch8b112d22011-06-08 16:22:53 +010011728 details->set(kThreadDetailsThreadIdIndex,
11729 Smi::FromInt(thread->id().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011730 }
11731
11732 // Convert to JS array and return.
Steve Block44f0eee2011-05-26 01:26:41 +010011733 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011734}
11735
11736
Ben Murdochbb769b22010-08-11 14:56:33 +010011737// Sets the disable break state
11738// args[0]: disable break state
Ben Murdoch8b112d22011-06-08 16:22:53 +010011739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
Steve Block44f0eee2011-05-26 01:26:41 +010011740 HandleScope scope(isolate);
Ben Murdochbb769b22010-08-11 14:56:33 +010011741 ASSERT(args.length() == 1);
11742 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +010011743 isolate->debug()->set_disable_break(disable_break);
11744 return isolate->heap()->undefined_value();
Ben Murdochbb769b22010-08-11 14:56:33 +010011745}
11746
11747
Ben Murdoch8b112d22011-06-08 16:22:53 +010011748RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
Steve Block44f0eee2011-05-26 01:26:41 +010011749 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011750 ASSERT(args.length() == 1);
11751
11752 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11753 Handle<SharedFunctionInfo> shared(fun->shared());
11754 // Find the number of break points
11755 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
Steve Block44f0eee2011-05-26 01:26:41 +010011756 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011757 // Return array as JS array
Steve Block44f0eee2011-05-26 01:26:41 +010011758 return *isolate->factory()->NewJSArrayWithElements(
Steve Blocka7e24c12009-10-30 11:49:00 +000011759 Handle<FixedArray>::cast(break_locations));
11760}
11761
11762
11763// Set a break point in a function
11764// args[0]: function
11765// args[1]: number: break source position (within the function source)
11766// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011767RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011768 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011769 ASSERT(args.length() == 3);
11770 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11771 Handle<SharedFunctionInfo> shared(fun->shared());
11772 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11773 RUNTIME_ASSERT(source_position >= 0);
11774 Handle<Object> break_point_object_arg = args.at<Object>(2);
11775
11776 // Set break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011777 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11778 &source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011779
Steve Block8defd9f2010-07-08 12:39:36 +010011780 return Smi::FromInt(source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011781}
11782
11783
Steve Block44f0eee2011-05-26 01:26:41 +010011784Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11785 Handle<Script> script,
Steve Blocka7e24c12009-10-30 11:49:00 +000011786 int position) {
11787 // Iterate the heap looking for SharedFunctionInfo generated from the
11788 // script. The inner most SharedFunctionInfo containing the source position
11789 // for the requested break point is found.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011790 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
Steve Blocka7e24c12009-10-30 11:49:00 +000011791 // which is found is not compiled it is compiled and the heap is iterated
11792 // again as the compilation might create inner functions from the newly
11793 // compiled function and the actual requested break point might be in one of
11794 // these functions.
11795 bool done = false;
11796 // The current candidate for the source position:
11797 int target_start_position = RelocInfo::kNoPosition;
11798 Handle<SharedFunctionInfo> target;
Steve Blocka7e24c12009-10-30 11:49:00 +000011799 while (!done) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011800 { // Extra scope for iterator and no-allocation.
11801 isolate->heap()->EnsureHeapIsIterable();
11802 AssertNoAllocation no_alloc_during_heap_iteration;
11803 HeapIterator iterator;
11804 for (HeapObject* obj = iterator.next();
11805 obj != NULL; obj = iterator.next()) {
11806 if (obj->IsSharedFunctionInfo()) {
11807 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11808 if (shared->script() == *script) {
11809 // If the SharedFunctionInfo found has the requested script data and
11810 // contains the source position it is a candidate.
11811 int start_position = shared->function_token_position();
11812 if (start_position == RelocInfo::kNoPosition) {
11813 start_position = shared->start_position();
11814 }
11815 if (start_position <= position &&
11816 position <= shared->end_position()) {
11817 // If there is no candidate or this function is within the current
11818 // candidate this is the new candidate.
11819 if (target.is_null()) {
11820 target_start_position = start_position;
11821 target = shared;
11822 } else {
11823 if (target_start_position == start_position &&
11824 shared->end_position() == target->end_position()) {
11825 // If a top-level function contain only one function
11826 // declartion the source for the top-level and the
11827 // function is the same. In that case prefer the non
11828 // top-level function.
11829 if (!shared->is_toplevel()) {
11830 target_start_position = start_position;
11831 target = shared;
11832 }
11833 } else if (target_start_position <= start_position &&
11834 shared->end_position() <= target->end_position()) {
11835 // This containment check includes equality as a function
11836 // inside a top-level function can share either start or end
11837 // position with the top-level function.
Steve Blocka7e24c12009-10-30 11:49:00 +000011838 target_start_position = start_position;
11839 target = shared;
11840 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011841 }
11842 }
11843 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011844 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011845 } // End for loop.
11846 } // End No allocation scope.
Steve Blocka7e24c12009-10-30 11:49:00 +000011847
Steve Blocka7e24c12009-10-30 11:49:00 +000011848 if (target.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011849 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011850 }
11851
11852 // If the candidate found is compiled we are done. NOTE: when lazy
11853 // compilation of inner functions is introduced some additional checking
11854 // needs to be done here to compile inner functions.
11855 done = target->is_compiled();
11856 if (!done) {
11857 // If the candidate is not compiled compile it to reveal any inner
11858 // functions which might contain the requested source position.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011859 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +000011860 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011861 } // End while loop.
Steve Blocka7e24c12009-10-30 11:49:00 +000011862
11863 return *target;
11864}
11865
11866
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011867// Changes the state of a break point in a script and returns source position
11868// where break point was set. NOTE: Regarding performance see the NOTE for
11869// GetScriptFromScriptData.
Steve Blocka7e24c12009-10-30 11:49:00 +000011870// args[0]: script to set break point in
11871// args[1]: number: break source position (within the script source)
11872// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011873RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011874 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011875 ASSERT(args.length() == 3);
11876 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11877 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11878 RUNTIME_ASSERT(source_position >= 0);
11879 Handle<Object> break_point_object_arg = args.at<Object>(2);
11880
11881 // Get the script from the script wrapper.
11882 RUNTIME_ASSERT(wrapper->value()->IsScript());
11883 Handle<Script> script(Script::cast(wrapper->value()));
11884
11885 Object* result = Runtime::FindSharedFunctionInfoInScript(
Steve Block44f0eee2011-05-26 01:26:41 +010011886 isolate, script, source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011887 if (!result->IsUndefined()) {
11888 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11889 // Find position within function. The script position might be before the
11890 // source position of the first function.
11891 int position;
11892 if (shared->start_position() > source_position) {
11893 position = 0;
11894 } else {
11895 position = source_position - shared->start_position();
11896 }
Steve Block44f0eee2011-05-26 01:26:41 +010011897 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011898 position += shared->start_position();
11899 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011900 }
Steve Block44f0eee2011-05-26 01:26:41 +010011901 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011902}
11903
11904
11905// Clear a break point
11906// args[0]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010011907RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010011908 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011909 ASSERT(args.length() == 1);
11910 Handle<Object> break_point_object_arg = args.at<Object>(0);
11911
11912 // Clear break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011913 isolate->debug()->ClearBreakPoint(break_point_object_arg);
Steve Blocka7e24c12009-10-30 11:49:00 +000011914
Steve Block44f0eee2011-05-26 01:26:41 +010011915 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011916}
11917
11918
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011919// Change the state of break on exceptions.
11920// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11921// args[1]: Boolean indicating on/off.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011922RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010011923 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011924 ASSERT(args.length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011925 RUNTIME_ASSERT(args[0]->IsNumber());
11926 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011927
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011928 // If the number doesn't match an enum value, the ChangeBreakOnException
11929 // function will default to affecting caught exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +000011930 ExceptionBreakType type =
11931 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011932 // Update break point state.
Steve Block44f0eee2011-05-26 01:26:41 +010011933 isolate->debug()->ChangeBreakOnException(type, enable);
11934 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011935}
11936
11937
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011938// Returns the state of break on exceptions
11939// args[0]: boolean indicating uncaught exceptions
Ben Murdoch8b112d22011-06-08 16:22:53 +010011940RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010011941 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011942 ASSERT(args.length() == 1);
11943 RUNTIME_ASSERT(args[0]->IsNumber());
11944
11945 ExceptionBreakType type =
11946 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Steve Block44f0eee2011-05-26 01:26:41 +010011947 bool result = isolate->debug()->IsBreakOnException(type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011948 return Smi::FromInt(result);
11949}
11950
11951
Steve Blocka7e24c12009-10-30 11:49:00 +000011952// Prepare for stepping
11953// args[0]: break id for checking execution state
11954// args[1]: step action from the enumeration StepAction
11955// args[2]: number of times to perform the step, for step out it is the number
11956// of frames to step down.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011957RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
Steve Block44f0eee2011-05-26 01:26:41 +010011958 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011959 ASSERT(args.length() == 3);
11960 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070011961 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011962 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11963 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070011964 if (!maybe_check->ToObject(&check)) return maybe_check;
11965 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011966 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011967 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011968 }
11969
11970 // Get the step action and check validity.
11971 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11972 if (step_action != StepIn &&
11973 step_action != StepNext &&
11974 step_action != StepOut &&
11975 step_action != StepInMin &&
11976 step_action != StepMin) {
Steve Block44f0eee2011-05-26 01:26:41 +010011977 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011978 }
11979
11980 // Get the number of steps.
11981 int step_count = NumberToInt32(args[2]);
11982 if (step_count < 1) {
Steve Block44f0eee2011-05-26 01:26:41 +010011983 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000011984 }
11985
11986 // Clear all current stepping setup.
Steve Block44f0eee2011-05-26 01:26:41 +010011987 isolate->debug()->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +000011988
11989 // Prepare step.
Steve Block44f0eee2011-05-26 01:26:41 +010011990 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11991 step_count);
11992 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011993}
11994
11995
11996// Clear all stepping set by PrepareStep.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011997RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
Steve Block44f0eee2011-05-26 01:26:41 +010011998 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011999 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010012000 isolate->debug()->ClearStepping();
12001 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012002}
12003
12004
12005// Creates a copy of the with context chain. The copy of the context chain is
12006// is linked to the function context supplied.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012007static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12008 Handle<JSFunction> function,
12009 Handle<Context> base,
12010 JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000012011 int inlined_jsframe_index) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012012 HandleScope scope(isolate);
12013 List<Handle<ScopeInfo> > scope_chain;
12014 List<Handle<Context> > context_chain;
12015
Ben Murdochc7cc0282012-03-05 14:35:55 +000012016 ScopeIterator it(isolate, frame, inlined_jsframe_index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012017 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12018 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12019 ASSERT(!it.Done());
12020 scope_chain.Add(it.CurrentScopeInfo());
12021 context_chain.Add(it.CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000012022 }
12023
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012024 // At the end of the chain. Return the base context to link to.
12025 Handle<Context> context = base;
12026
12027 // Iteratively copy and or materialize the nested contexts.
12028 while (!scope_chain.is_empty()) {
12029 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12030 Handle<Context> current = context_chain.RemoveLast();
12031 ASSERT(!(scope_info->HasContext() & current.is_null()));
12032
12033 if (scope_info->Type() == CATCH_SCOPE) {
12034 Handle<String> name(String::cast(current->extension()));
12035 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12036 context =
12037 isolate->factory()->NewCatchContext(function,
12038 context,
12039 name,
12040 thrown_object);
12041 } else if (scope_info->Type() == BLOCK_SCOPE) {
12042 // Materialize the contents of the block scope into a JSObject.
12043 Handle<JSObject> block_scope_object =
12044 MaterializeBlockScope(isolate, current);
12045 if (block_scope_object.is_null()) {
12046 return Handle<Context>::null();
12047 }
12048 // Allocate a new function context for the debug evaluation and set the
12049 // extension object.
12050 Handle<Context> new_context =
12051 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12052 function);
12053 new_context->set_extension(*block_scope_object);
12054 new_context->set_previous(*context);
12055 context = new_context;
12056 } else {
12057 ASSERT(scope_info->Type() == WITH_SCOPE);
12058 ASSERT(current->IsWithContext());
12059 Handle<JSObject> extension(JSObject::cast(current->extension()));
12060 context =
12061 isolate->factory()->NewWithContext(function, context, extension);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012062 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012063 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012064
12065 return scope.CloseAndEscape(context);
Steve Blocka7e24c12009-10-30 11:49:00 +000012066}
12067
12068
12069// Helper function to find or create the arguments object for
12070// Runtime_DebugEvaluate.
Steve Block44f0eee2011-05-26 01:26:41 +010012071static Handle<Object> GetArgumentsObject(Isolate* isolate,
12072 JavaScriptFrame* frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000012073 FrameInspector* frame_inspector,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012074 Handle<ScopeInfo> scope_info,
Steve Blocka7e24c12009-10-30 11:49:00 +000012075 Handle<Context> function_context) {
12076 // Try to find the value of 'arguments' to pass as parameter. If it is not
12077 // found (that is the debugged function does not reference 'arguments' and
12078 // does not support eval) then create an 'arguments' object.
12079 int index;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012080 if (scope_info->StackLocalCount() > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +010012081 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000012082 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010012083 return Handle<Object>(frame->GetExpression(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012084 }
12085 }
12086
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012087 if (scope_info->HasHeapAllocatedLocals()) {
12088 VariableMode mode;
12089 InitializationFlag init_flag;
12090 index = scope_info->ContextSlotIndex(
12091 isolate->heap()->arguments_symbol(), &mode, &init_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +000012092 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010012093 return Handle<Object>(function_context->get(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012094 }
12095 }
12096
Ben Murdochc7cc0282012-03-05 14:35:55 +000012097 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12098 int length = frame_inspector->GetParametersCount();
Steve Block44f0eee2011-05-26 01:26:41 +010012099 Handle<JSObject> arguments =
12100 isolate->factory()->NewArgumentsObject(function, length);
12101 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Leon Clarke4515c472010-02-03 11:58:03 +000012102
12103 AssertNoAllocation no_gc;
12104 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000012105 for (int i = 0; i < length; i++) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000012106 array->set(i, frame_inspector->GetParameter(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000012107 }
12108 arguments->set_elements(*array);
12109 return arguments;
12110}
12111
12112
Steve Block44f0eee2011-05-26 01:26:41 +010012113static const char kSourceStr[] =
12114 "(function(arguments,__source__){return eval(__source__);})";
12115
12116
Steve Blocka7e24c12009-10-30 11:49:00 +000012117// Evaluate a piece of JavaScript in the context of a stack frame for
12118// debugging. This is accomplished by creating a new context which in its
12119// extension part has all the parameters and locals of the function on the
12120// stack frame. A function which calls eval with the code to evaluate is then
12121// compiled in this context and called in this context. As this context
12122// replaces the context of the function on the stack frame a new (empty)
12123// function is created as well to be used as the closure for the context.
12124// This function and the context acts as replacements for the function on the
12125// stack frame presenting the same view of the values of parameters and
12126// local variables as if the piece of JavaScript was evaluated at the point
12127// where the function on the stack frame is currently stopped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012128RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
Steve Block44f0eee2011-05-26 01:26:41 +010012129 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012130
12131 // Check the execution state and decode arguments frame and source to be
12132 // evaluated.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012133 ASSERT(args.length() == 6);
John Reck59135872010-11-02 12:39:01 -070012134 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010012135 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12136 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070012137 if (!maybe_check_result->ToObject(&check_result)) {
12138 return maybe_check_result;
12139 }
12140 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012141 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012142 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012143 CONVERT_ARG_CHECKED(String, source, 3);
12144 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12145 Handle<Object> additional_context(args[5]);
Steve Blocka7e24c12009-10-30 11:49:00 +000012146
12147 // Handle the processing of break.
12148 DisableBreak disable_break_save(disable_break);
12149
12150 // Get the frame where the debugging is performed.
12151 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012152 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000012153 JavaScriptFrame* frame = it.frame();
Ben Murdochc7cc0282012-03-05 14:35:55 +000012154 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12155 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012156 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000012157
12158 // Traverse the saved contexts chain to find the active context for the
12159 // selected frame.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012160 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12161
Steve Block44f0eee2011-05-26 01:26:41 +010012162 SaveContext savex(isolate);
12163 isolate->set_context(*(save->context()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012164
12165 // Create the (empty) function replacing the function on the stack frame for
12166 // the purpose of evaluating in the context created below. It is important
12167 // that this function does not describe any parameters and local variables
12168 // in the context. If it does then this will cause problems with the lookup
12169 // in Context::Lookup, where context slots for parameters and local variables
12170 // are looked at before the extension object.
12171 Handle<JSFunction> go_between =
Steve Block44f0eee2011-05-26 01:26:41 +010012172 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12173 isolate->factory()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012174 go_between->set_context(function->context());
12175#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012176 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12177 ASSERT(go_between_scope_info->ParameterCount() == 0);
12178 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012179#endif
12180
12181 // Materialize the content of the local scope into a JSObject.
Ben Murdochc7cc0282012-03-05 14:35:55 +000012182 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12183 isolate, frame, &frame_inspector);
Steve Block44f0eee2011-05-26 01:26:41 +010012184 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
Steve Blocka7e24c12009-10-30 11:49:00 +000012185
12186 // Allocate a new context for the debug evaluation and set the extension
12187 // object build.
12188 Handle<Context> context =
Steve Block44f0eee2011-05-26 01:26:41 +010012189 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12190 go_between);
Steve Blocka7e24c12009-10-30 11:49:00 +000012191 context->set_extension(*local_scope);
12192 // Copy any with contexts present and chain them in front of this context.
12193 Handle<Context> frame_context(Context::cast(frame->context()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012194 Handle<Context> function_context;
12195 // Get the function's context if it has one.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012196 if (scope_info->HasContext()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012197 function_context = Handle<Context>(frame_context->declaration_context());
12198 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012199 context = CopyNestedScopeContextChain(isolate,
12200 go_between,
12201 context,
12202 frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000012203 inlined_jsframe_index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012204
Ben Murdochb0fe1622011-05-05 13:52:32 +010012205 if (additional_context->IsJSObject()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012206 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
12207 context =
12208 isolate->factory()->NewWithContext(go_between, context, extension);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012209 }
12210
Steve Blocka7e24c12009-10-30 11:49:00 +000012211 // Wrap the evaluation statement in a new function compiled in the newly
12212 // created context. The function has one parameter which has to be called
12213 // 'arguments'. This it to have access to what would have been 'arguments' in
12214 // the function being debugged.
12215 // function(arguments,__source__) {return eval(__source__);}
Steve Block44f0eee2011-05-26 01:26:41 +010012216
Steve Blocka7e24c12009-10-30 11:49:00 +000012217 Handle<String> function_source =
Steve Block44f0eee2011-05-26 01:26:41 +010012218 isolate->factory()->NewStringFromAscii(
12219 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
Steve Block1e0659c2011-05-24 12:43:12 +010012220
12221 // Currently, the eval code will be executed in non-strict mode,
12222 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010012223 Handle<SharedFunctionInfo> shared =
Steve Blocka7e24c12009-10-30 11:49:00 +000012224 Compiler::CompileEval(function_source,
12225 context,
Steve Block1e0659c2011-05-24 12:43:12 +010012226 context->IsGlobalContext(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012227 CLASSIC_MODE,
12228 RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +010012229 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000012230 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010012231 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
Steve Blocka7e24c12009-10-30 11:49:00 +000012232
12233 // Invoke the result of the compilation to get the evaluation function.
12234 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010012235 Handle<Object> receiver(frame->receiver(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012236 Handle<Object> evaluation_function =
12237 Execution::Call(compiled_function, receiver, 0, NULL,
12238 &has_pending_exception);
12239 if (has_pending_exception) return Failure::Exception();
12240
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012241 Handle<Object> arguments = GetArgumentsObject(isolate,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012242 frame,
Ben Murdochc7cc0282012-03-05 14:35:55 +000012243 &frame_inspector,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012244 scope_info,
12245 function_context);
Steve Blocka7e24c12009-10-30 11:49:00 +000012246
12247 // Invoke the evaluation function and return the result.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012248 Handle<Object> argv[] = { arguments, source };
Steve Blocka7e24c12009-10-30 11:49:00 +000012249 Handle<Object> result =
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012250 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12251 receiver,
12252 ARRAY_SIZE(argv),
12253 argv,
12254 &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +000012255 if (has_pending_exception) return Failure::Exception();
12256
12257 // Skip the global proxy as it has no properties and always delegates to the
12258 // real global object.
12259 if (result->IsJSGlobalProxy()) {
12260 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12261 }
12262
12263 return *result;
12264}
12265
12266
Ben Murdoch8b112d22011-06-08 16:22:53 +010012267RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
Steve Block44f0eee2011-05-26 01:26:41 +010012268 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012269
12270 // Check the execution state and decode arguments frame and source to be
12271 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +010012272 ASSERT(args.length() == 4);
John Reck59135872010-11-02 12:39:01 -070012273 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010012274 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12275 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070012276 if (!maybe_check_result->ToObject(&check_result)) {
12277 return maybe_check_result;
12278 }
12279 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012280 CONVERT_ARG_CHECKED(String, source, 1);
12281 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012282 Handle<Object> additional_context(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +000012283
12284 // Handle the processing of break.
12285 DisableBreak disable_break_save(disable_break);
12286
12287 // Enter the top context from before the debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010012288 SaveContext save(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012289 SaveContext* top = &save;
Steve Block44f0eee2011-05-26 01:26:41 +010012290 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012291 top = top->prev();
12292 }
12293 if (top != NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010012294 isolate->set_context(*top->context());
Steve Blocka7e24c12009-10-30 11:49:00 +000012295 }
12296
12297 // Get the global context now set to the top context from before the
12298 // debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010012299 Handle<Context> context = isolate->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000012300
Ben Murdochb0fe1622011-05-05 13:52:32 +010012301 bool is_global = true;
12302
12303 if (additional_context->IsJSObject()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012304 // Create a new with context with the additional context information between
12305 // the context of the debugged function and the eval code to be executed.
12306 context = isolate->factory()->NewWithContext(
12307 Handle<JSFunction>(context->closure()),
12308 context,
12309 Handle<JSObject>::cast(additional_context));
Ben Murdochb0fe1622011-05-05 13:52:32 +010012310 is_global = false;
12311 }
12312
Steve Blocka7e24c12009-10-30 11:49:00 +000012313 // Compile the source to be evaluated.
Steve Block1e0659c2011-05-24 12:43:12 +010012314 // Currently, the eval code will be executed in non-strict mode,
12315 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010012316 Handle<SharedFunctionInfo> shared =
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012317 Compiler::CompileEval(source,
12318 context,
12319 is_global,
12320 CLASSIC_MODE,
12321 RelocInfo::kNoPosition);
Steve Block6ded16b2010-05-10 14:33:55 +010012322 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000012323 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010012324 Handle<JSFunction>(
12325 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12326 context));
Steve Blocka7e24c12009-10-30 11:49:00 +000012327
12328 // Invoke the result of the compilation to get the evaluation function.
12329 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010012330 Handle<Object> receiver = isolate->global();
Steve Blocka7e24c12009-10-30 11:49:00 +000012331 Handle<Object> result =
12332 Execution::Call(compiled_function, receiver, 0, NULL,
12333 &has_pending_exception);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012334 // Clear the oneshot breakpoints so that the debugger does not step further.
12335 isolate->debug()->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +000012336 if (has_pending_exception) return Failure::Exception();
12337 return *result;
12338}
12339
12340
Ben Murdoch8b112d22011-06-08 16:22:53 +010012341RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
Steve Block44f0eee2011-05-26 01:26:41 +010012342 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012343 ASSERT(args.length() == 0);
12344
12345 // Fill the script objects.
Steve Block44f0eee2011-05-26 01:26:41 +010012346 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
Steve Blocka7e24c12009-10-30 11:49:00 +000012347
12348 // Convert the script objects to proper JS objects.
12349 for (int i = 0; i < instances->length(); i++) {
12350 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12351 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12352 // because using
12353 // instances->set(i, *GetScriptWrapper(script))
12354 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
Ben Murdochc7cc0282012-03-05 14:35:55 +000012355 // already have dereferenced the instances handle.
Steve Blocka7e24c12009-10-30 11:49:00 +000012356 Handle<JSValue> wrapper = GetScriptWrapper(script);
12357 instances->set(i, *wrapper);
12358 }
12359
12360 // Return result as a JS array.
Steve Block44f0eee2011-05-26 01:26:41 +010012361 Handle<JSObject> result =
12362 isolate->factory()->NewJSObject(isolate->array_function());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012363 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012364 return *result;
12365}
12366
12367
12368// Helper function used by Runtime_DebugReferencedBy below.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012369static int DebugReferencedBy(HeapIterator* iterator,
12370 JSObject* target,
Steve Blocka7e24c12009-10-30 11:49:00 +000012371 Object* instance_filter, int max_references,
12372 FixedArray* instances, int instances_size,
12373 JSFunction* arguments_function) {
12374 NoHandleAllocation ha;
12375 AssertNoAllocation no_alloc;
12376
12377 // Iterate the heap.
12378 int count = 0;
12379 JSObject* last = NULL;
Leon Clarked91b9f72010-01-27 17:25:45 +000012380 HeapObject* heap_obj = NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012381 while (((heap_obj = iterator->next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000012382 (max_references == 0 || count < max_references)) {
12383 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012384 if (heap_obj->IsJSObject()) {
12385 // Skip context extension objects and argument arrays as these are
12386 // checked in the context of functions using them.
12387 JSObject* obj = JSObject::cast(heap_obj);
12388 if (obj->IsJSContextExtensionObject() ||
12389 obj->map()->constructor() == arguments_function) {
12390 continue;
12391 }
12392
12393 // Check if the JS object has a reference to the object looked for.
12394 if (obj->ReferencesObject(target)) {
12395 // Check instance filter if supplied. This is normally used to avoid
12396 // references from mirror objects (see Runtime_IsInPrototypeChain).
12397 if (!instance_filter->IsUndefined()) {
12398 Object* V = obj;
12399 while (true) {
12400 Object* prototype = V->GetPrototype();
12401 if (prototype->IsNull()) {
12402 break;
12403 }
12404 if (instance_filter == prototype) {
12405 obj = NULL; // Don't add this object.
12406 break;
12407 }
12408 V = prototype;
12409 }
12410 }
12411
12412 if (obj != NULL) {
12413 // Valid reference found add to instance array if supplied an update
12414 // count.
12415 if (instances != NULL && count < instances_size) {
12416 instances->set(count, obj);
12417 }
12418 last = obj;
12419 count++;
12420 }
12421 }
12422 }
12423 }
12424
12425 // Check for circular reference only. This can happen when the object is only
12426 // referenced from mirrors and has a circular reference in which case the
12427 // object is not really alive and would have been garbage collected if not
12428 // referenced from the mirror.
12429 if (count == 1 && last == target) {
12430 count = 0;
12431 }
12432
12433 // Return the number of referencing objects found.
12434 return count;
12435}
12436
12437
12438// Scan the heap for objects with direct references to an object
12439// args[0]: the object to find references to
12440// args[1]: constructor function for instances to exclude (Mirror)
12441// args[2]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010012442RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012443 ASSERT(args.length() == 3);
12444
12445 // First perform a full GC in order to avoid references from dead objects.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012446 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12447 // The heap iterator reserves the right to do a GC to make the heap iterable.
12448 // Due to the GC above we know it won't need to do that, but it seems cleaner
12449 // to get the heap iterator constructed before we start having unprotected
12450 // Object* locals that are not protected by handles.
Steve Blocka7e24c12009-10-30 11:49:00 +000012451
12452 // Check parameters.
12453 CONVERT_CHECKED(JSObject, target, args[0]);
12454 Object* instance_filter = args[1];
12455 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12456 instance_filter->IsJSObject());
12457 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12458 RUNTIME_ASSERT(max_references >= 0);
12459
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012460
Steve Blocka7e24c12009-10-30 11:49:00 +000012461 // Get the constructor function for context extension and arguments array.
12462 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +010012463 isolate->context()->global_context()->arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +000012464 JSFunction* arguments_function =
12465 JSFunction::cast(arguments_boilerplate->map()->constructor());
12466
12467 // Get the number of referencing objects.
12468 int count;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012469 HeapIterator heap_iterator;
12470 count = DebugReferencedBy(&heap_iterator,
12471 target, instance_filter, max_references,
Steve Blocka7e24c12009-10-30 11:49:00 +000012472 NULL, 0, arguments_function);
12473
12474 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070012475 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010012476 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070012477 if (!maybe_object->ToObject(&object)) return maybe_object;
12478 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012479 FixedArray* instances = FixedArray::cast(object);
12480
12481 // Fill the referencing objects.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012482 // AllocateFixedArray above does not make the heap non-iterable.
12483 ASSERT(HEAP->IsHeapIterable());
12484 HeapIterator heap_iterator2;
12485 count = DebugReferencedBy(&heap_iterator2,
12486 target, instance_filter, max_references,
Steve Blocka7e24c12009-10-30 11:49:00 +000012487 instances, count, arguments_function);
12488
12489 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070012490 Object* result;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012491 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
Steve Block44f0eee2011-05-26 01:26:41 +010012492 isolate->context()->global_context()->array_function());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012493 if (!maybe_result->ToObject(&result)) return maybe_result;
12494 return JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012495}
12496
12497
12498// Helper function used by Runtime_DebugConstructedBy below.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012499static int DebugConstructedBy(HeapIterator* iterator,
12500 JSFunction* constructor,
12501 int max_references,
12502 FixedArray* instances,
12503 int instances_size) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012504 AssertNoAllocation no_alloc;
12505
12506 // Iterate the heap.
12507 int count = 0;
Leon Clarked91b9f72010-01-27 17:25:45 +000012508 HeapObject* heap_obj = NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012509 while (((heap_obj = iterator->next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000012510 (max_references == 0 || count < max_references)) {
12511 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000012512 if (heap_obj->IsJSObject()) {
12513 JSObject* obj = JSObject::cast(heap_obj);
12514 if (obj->map()->constructor() == constructor) {
12515 // Valid reference found add to instance array if supplied an update
12516 // count.
12517 if (instances != NULL && count < instances_size) {
12518 instances->set(count, obj);
12519 }
12520 count++;
12521 }
12522 }
12523 }
12524
12525 // Return the number of referencing objects found.
12526 return count;
12527}
12528
12529
12530// Scan the heap for objects constructed by a specific function.
12531// args[0]: the constructor to find instances of
12532// args[1]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010012533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012534 ASSERT(args.length() == 2);
12535
12536 // First perform a full GC in order to avoid dead objects.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012537 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
Steve Blocka7e24c12009-10-30 11:49:00 +000012538
12539 // Check parameters.
12540 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12541 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12542 RUNTIME_ASSERT(max_references >= 0);
12543
12544 // Get the number of referencing objects.
12545 int count;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012546 HeapIterator heap_iterator;
12547 count = DebugConstructedBy(&heap_iterator,
12548 constructor,
12549 max_references,
12550 NULL,
12551 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000012552
12553 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070012554 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010012555 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070012556 if (!maybe_object->ToObject(&object)) return maybe_object;
12557 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012558 FixedArray* instances = FixedArray::cast(object);
12559
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012560 ASSERT(HEAP->IsHeapIterable());
Steve Blocka7e24c12009-10-30 11:49:00 +000012561 // Fill the referencing objects.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012562 HeapIterator heap_iterator2;
12563 count = DebugConstructedBy(&heap_iterator2,
12564 constructor,
12565 max_references,
12566 instances,
12567 count);
Steve Blocka7e24c12009-10-30 11:49:00 +000012568
12569 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070012570 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010012571 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12572 isolate->context()->global_context()->array_function());
John Reck59135872010-11-02 12:39:01 -070012573 if (!maybe_result->ToObject(&result)) return maybe_result;
12574 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012575 return JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000012576}
12577
12578
12579// Find the effective prototype object as returned by __proto__.
12580// args[0]: the object to find the prototype for.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012582 ASSERT(args.length() == 1);
12583
12584 CONVERT_CHECKED(JSObject, obj, args[0]);
12585
12586 // Use the __proto__ accessor.
12587 return Accessors::ObjectPrototype.getter(obj, NULL);
12588}
12589
12590
Ben Murdoch8b112d22011-06-08 16:22:53 +010012591RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012592 ASSERT(args.length() == 0);
12593 CPU::DebugBreak();
Steve Block44f0eee2011-05-26 01:26:41 +010012594 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012595}
12596
12597
Ben Murdoch8b112d22011-06-08 16:22:53 +010012598RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012599#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012600 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012601 ASSERT(args.length() == 1);
12602 // Get the function and make sure it is compiled.
12603 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000012604 Handle<SharedFunctionInfo> shared(func->shared());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012605 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012606 return Failure::Exception();
12607 }
12608 func->code()->PrintLn();
12609#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012610 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012611}
12612
12613
Ben Murdoch8b112d22011-06-08 16:22:53 +010012614RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012615#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012616 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012617 ASSERT(args.length() == 1);
12618 // Get the function and make sure it is compiled.
12619 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000012620 Handle<SharedFunctionInfo> shared(func->shared());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012621 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012622 return Failure::Exception();
12623 }
Leon Clarke4515c472010-02-03 11:58:03 +000012624 shared->construct_stub()->PrintLn();
Steve Blocka7e24c12009-10-30 11:49:00 +000012625#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010012626 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012627}
12628
12629
Ben Murdoch8b112d22011-06-08 16:22:53 +010012630RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012631 NoHandleAllocation ha;
12632 ASSERT(args.length() == 1);
12633
12634 CONVERT_CHECKED(JSFunction, f, args[0]);
12635 return f->shared()->inferred_name();
12636}
Steve Blockd0582a62009-12-15 09:54:21 +000012637
Steve Block6ded16b2010-05-10 14:33:55 +010012638
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012639static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12640 Script* script,
Steve Block44f0eee2011-05-26 01:26:41 +010012641 FixedArray* buffer) {
Steve Block6ded16b2010-05-10 14:33:55 +010012642 AssertNoAllocation no_allocations;
Steve Block6ded16b2010-05-10 14:33:55 +010012643 int counter = 0;
12644 int buffer_size = buffer->length();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012645 for (HeapObject* obj = iterator->next();
12646 obj != NULL;
12647 obj = iterator->next()) {
Steve Block6ded16b2010-05-10 14:33:55 +010012648 ASSERT(obj != NULL);
12649 if (!obj->IsSharedFunctionInfo()) {
12650 continue;
12651 }
12652 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12653 if (shared->script() != script) {
12654 continue;
12655 }
12656 if (counter < buffer_size) {
12657 buffer->set(counter, shared);
12658 }
12659 counter++;
12660 }
12661 return counter;
12662}
12663
12664// For a script finds all SharedFunctionInfo's in the heap that points
12665// to this script. Returns JSArray of SharedFunctionInfo wrapped
12666// in OpaqueReferences.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012667RUNTIME_FUNCTION(MaybeObject*,
12668 Runtime_LiveEditFindSharedFunctionInfosForScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012669 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012670 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012671 CONVERT_CHECKED(JSValue, script_value, args[0]);
12672
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012673
Steve Block6ded16b2010-05-10 14:33:55 +010012674 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12675
12676 const int kBufferSize = 32;
12677
12678 Handle<FixedArray> array;
Steve Block44f0eee2011-05-26 01:26:41 +010012679 array = isolate->factory()->NewFixedArray(kBufferSize);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012680 int number;
12681 {
12682 isolate->heap()->EnsureHeapIsIterable();
12683 AssertNoAllocation no_allocations;
12684 HeapIterator heap_iterator;
12685 Script* scr = *script;
12686 FixedArray* arr = *array;
12687 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12688 }
Steve Block6ded16b2010-05-10 14:33:55 +010012689 if (number > kBufferSize) {
Steve Block44f0eee2011-05-26 01:26:41 +010012690 array = isolate->factory()->NewFixedArray(number);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012691 isolate->heap()->EnsureHeapIsIterable();
12692 AssertNoAllocation no_allocations;
12693 HeapIterator heap_iterator;
12694 Script* scr = *script;
12695 FixedArray* arr = *array;
12696 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
Steve Block6ded16b2010-05-10 14:33:55 +010012697 }
12698
Steve Block44f0eee2011-05-26 01:26:41 +010012699 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
Steve Block6ded16b2010-05-10 14:33:55 +010012700 result->set_length(Smi::FromInt(number));
12701
12702 LiveEdit::WrapSharedFunctionInfos(result);
12703
12704 return *result;
12705}
12706
12707// For a script calculates compilation information about all its functions.
12708// The script source is explicitly specified by the second argument.
12709// The source of the actual script is not used, however it is important that
12710// all generated code keeps references to this particular instance of script.
12711// Returns a JSArray of compilation infos. The array is ordered so that
12712// each function with all its descendant is always stored in a continues range
12713// with the function itself going first. The root function is a script function.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012714RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
Steve Block6ded16b2010-05-10 14:33:55 +010012715 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012716 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012717 CONVERT_CHECKED(JSValue, script, args[0]);
12718 CONVERT_ARG_CHECKED(String, source, 1);
12719 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12720
12721 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12722
Steve Block44f0eee2011-05-26 01:26:41 +010012723 if (isolate->has_pending_exception()) {
Steve Block6ded16b2010-05-10 14:33:55 +010012724 return Failure::Exception();
12725 }
12726
12727 return result;
12728}
12729
12730// Changes the source of the script to a new_source.
12731// If old_script_name is provided (i.e. is a String), also creates a copy of
12732// the script with its original source and sends notification to debugger.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012733RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012734 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010012735 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012736 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12737 CONVERT_ARG_CHECKED(String, new_source, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012738 Handle<Object> old_script_name(args[2], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012739
12740 CONVERT_CHECKED(Script, original_script_pointer,
12741 original_script_value->value());
12742 Handle<Script> original_script(original_script_pointer);
12743
12744 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12745 new_source,
12746 old_script_name);
12747
12748 if (old_script->IsScript()) {
12749 Handle<Script> script_handle(Script::cast(old_script));
12750 return *(GetScriptWrapper(script_handle));
12751 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010012752 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012753 }
12754}
12755
Ben Murdochb0fe1622011-05-05 13:52:32 +010012756
Ben Murdoch8b112d22011-06-08 16:22:53 +010012757RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010012758 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010012759 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012760 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12761 return LiveEdit::FunctionSourceUpdated(shared_info);
12762}
12763
12764
Steve Block6ded16b2010-05-10 14:33:55 +010012765// Replaces code of SharedFunctionInfo with a new one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012766RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
Steve Block6ded16b2010-05-10 14:33:55 +010012767 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012768 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012769 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12770 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12771
12772 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
12773}
12774
12775// Connects SharedFunctionInfo to another script.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012776RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010012777 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012778 HandleScope scope(isolate);
12779 Handle<Object> function_object(args[0], isolate);
12780 Handle<Object> script_object(args[1], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012781
12782 if (function_object->IsJSValue()) {
12783 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12784 if (script_object->IsJSValue()) {
12785 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
Steve Block44f0eee2011-05-26 01:26:41 +010012786 script_object = Handle<Object>(script, isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012787 }
12788
12789 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12790 } else {
12791 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12792 // and we check it in this function.
12793 }
12794
Steve Block44f0eee2011-05-26 01:26:41 +010012795 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012796}
12797
12798
12799// In a code of a parent function replaces original function as embedded object
12800// with a substitution one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012801RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
Steve Block6ded16b2010-05-10 14:33:55 +010012802 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010012803 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012804
12805 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12806 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12807 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12808
12809 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12810 subst_wrapper);
12811
Steve Block44f0eee2011-05-26 01:26:41 +010012812 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010012813}
12814
12815
12816// Updates positions of a shared function info (first parameter) according
12817// to script source change. Text change is described in second parameter as
12818// array of groups of 3 numbers:
12819// (change_begin, change_end, change_end_new_position).
12820// Each group describes a change in text; groups are sorted by change_begin.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012821RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
Steve Block6ded16b2010-05-10 14:33:55 +010012822 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012823 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012824 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12825 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12826
12827 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
12828}
12829
12830
12831// For array of SharedFunctionInfo's (each wrapped in JSValue)
12832// checks that none of them have activations on stacks (of any thread).
12833// Returns array of the same length with corresponding results of
12834// LiveEdit::FunctionPatchabilityStatus type.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012835RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
Steve Block6ded16b2010-05-10 14:33:55 +010012836 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012837 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012838 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12839 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
12840
12841 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
12842}
12843
Ben Murdochb8e0da22011-05-16 14:20:40 +010012844// Compares 2 strings line-by-line, then token-wise and returns diff in form
12845// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12846// of diff chunks.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012847RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
Steve Block6ded16b2010-05-10 14:33:55 +010012848 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012849 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012850 CONVERT_ARG_CHECKED(String, s1, 0);
12851 CONVERT_ARG_CHECKED(String, s2, 1);
12852
Ben Murdochb8e0da22011-05-16 14:20:40 +010012853 return *LiveEdit::CompareStrings(s1, s2);
Steve Block6ded16b2010-05-10 14:33:55 +010012854}
12855
12856
Steve Block6ded16b2010-05-10 14:33:55 +010012857// A testing entry. Returns statement position which is the closest to
12858// source_position.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
Steve Block6ded16b2010-05-10 14:33:55 +010012860 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012861 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012862 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12863 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12864
Steve Block44f0eee2011-05-26 01:26:41 +010012865 Handle<Code> code(function->code(), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012866
Ben Murdochb0fe1622011-05-05 13:52:32 +010012867 if (code->kind() != Code::FUNCTION &&
12868 code->kind() != Code::OPTIMIZED_FUNCTION) {
Steve Block44f0eee2011-05-26 01:26:41 +010012869 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010012870 }
12871
12872 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
Steve Block6ded16b2010-05-10 14:33:55 +010012873 int closest_pc = 0;
12874 int distance = kMaxInt;
12875 while (!it.done()) {
12876 int statement_position = static_cast<int>(it.rinfo()->data());
12877 // Check if this break point is closer that what was previously found.
12878 if (source_position <= statement_position &&
12879 statement_position - source_position < distance) {
12880 closest_pc =
12881 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
12882 distance = statement_position - source_position;
12883 // Check whether we can't get any closer.
12884 if (distance == 0) break;
12885 }
12886 it.next();
12887 }
12888
12889 return Smi::FromInt(closest_pc);
12890}
12891
12892
12893// Calls specified function with or without entering the debugger.
12894// This is used in unit tests to run code as if debugger is entered or simply
12895// to have a stack with C++ frame in the middle.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012896RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
Steve Block6ded16b2010-05-10 14:33:55 +010012897 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010012898 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010012899 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12900 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12901
12902 Handle<Object> result;
12903 bool pending_exception;
12904 {
12905 if (without_debugger) {
Steve Block44f0eee2011-05-26 01:26:41 +010012906 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010012907 &pending_exception);
12908 } else {
12909 EnterDebugger enter_debugger;
Steve Block44f0eee2011-05-26 01:26:41 +010012910 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010012911 &pending_exception);
12912 }
12913 }
12914 if (!pending_exception) {
12915 return *result;
12916 } else {
12917 return Failure::Exception();
12918 }
12919}
12920
12921
Ben Murdoch086aeea2011-05-13 15:57:08 +010012922// Sets a v8 flag.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012923RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
Ben Murdoch086aeea2011-05-13 15:57:08 +010012924 CONVERT_CHECKED(String, arg, args[0]);
Ben Murdoch589d6972011-11-30 16:04:58 +000012925 SmartArrayPointer<char> flags =
Ben Murdoch086aeea2011-05-13 15:57:08 +010012926 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12927 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
Steve Block44f0eee2011-05-26 01:26:41 +010012928 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010012929}
12930
12931
12932// Performs a GC.
12933// Presently, it only does a full GC.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012934RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
Steve Block44f0eee2011-05-26 01:26:41 +010012935 isolate->heap()->CollectAllGarbage(true);
12936 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010012937}
12938
12939
12940// Gets the current heap usage.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012941RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
Steve Block44f0eee2011-05-26 01:26:41 +010012942 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
Ben Murdoch086aeea2011-05-13 15:57:08 +010012943 if (!Smi::IsValid(usage)) {
Steve Block44f0eee2011-05-26 01:26:41 +010012944 return *isolate->factory()->NewNumberFromInt(usage);
Ben Murdoch086aeea2011-05-13 15:57:08 +010012945 }
12946 return Smi::FromInt(usage);
12947}
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012948
12949
12950// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012951RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012952#ifdef LIVE_OBJECT_LIST
Steve Block44f0eee2011-05-26 01:26:41 +010012953 return isolate->heap()->true_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012954#else
Steve Block44f0eee2011-05-26 01:26:41 +010012955 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012956#endif
12957}
12958
12959
12960// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012961RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012962#ifdef LIVE_OBJECT_LIST
12963 return LiveObjectList::Capture();
12964#else
Steve Block44f0eee2011-05-26 01:26:41 +010012965 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012966#endif
12967}
12968
12969
12970// Deletes the specified live object list.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012971RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012972#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012973 CONVERT_SMI_ARG_CHECKED(id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012974 bool success = LiveObjectList::Delete(id);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012975 return isolate->heap()->ToBoolean(success);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012976#else
Steve Block44f0eee2011-05-26 01:26:41 +010012977 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012978#endif
12979}
12980
12981
12982// Generates the response to a debugger request for a dump of the objects
12983// contained in the difference between the captured live object lists
12984// specified by id1 and id2.
12985// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12986// dumped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012987RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012988#ifdef LIVE_OBJECT_LIST
12989 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012990 CONVERT_SMI_ARG_CHECKED(id1, 0);
12991 CONVERT_SMI_ARG_CHECKED(id2, 1);
12992 CONVERT_SMI_ARG_CHECKED(start, 2);
12993 CONVERT_SMI_ARG_CHECKED(count, 3);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012994 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12995 EnterDebugger enter_debugger;
12996 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12997#else
Steve Block44f0eee2011-05-26 01:26:41 +010012998 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010012999#endif
13000}
13001
13002
13003// Gets the specified object as requested by the debugger.
13004// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013006#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013007 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013008 Object* result = LiveObjectList::GetObj(obj_id);
13009 return result;
13010#else
Steve Block44f0eee2011-05-26 01:26:41 +010013011 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013012#endif
13013}
13014
13015
13016// Gets the obj id for the specified address if valid.
13017// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013019#ifdef LIVE_OBJECT_LIST
13020 HandleScope scope;
13021 CONVERT_ARG_CHECKED(String, address, 0);
13022 Object* result = LiveObjectList::GetObjId(address);
13023 return result;
13024#else
Steve Block44f0eee2011-05-26 01:26:41 +010013025 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013026#endif
13027}
13028
13029
13030// Gets the retainers that references the specified object alive.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013031RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013032#ifdef LIVE_OBJECT_LIST
13033 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013034 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013035 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13036 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13037 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13038 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13039 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13040
13041 Handle<JSObject> instance_filter;
13042 if (args[1]->IsJSObject()) {
13043 instance_filter = args.at<JSObject>(1);
13044 }
13045 bool verbose = false;
13046 if (args[2]->IsBoolean()) {
13047 verbose = args[2]->IsTrue();
13048 }
13049 int start = 0;
13050 if (args[3]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013051 start = args.smi_at(3);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013052 }
13053 int limit = Smi::kMaxValue;
13054 if (args[4]->IsSmi()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013055 limit = args.smi_at(4);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013056 }
13057
13058 return LiveObjectList::GetObjRetainers(obj_id,
13059 instance_filter,
13060 verbose,
13061 start,
13062 limit,
13063 filter_obj);
13064#else
Steve Block44f0eee2011-05-26 01:26:41 +010013065 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013066#endif
13067}
13068
13069
13070// Gets the reference path between 2 objects.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013071RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013072#ifdef LIVE_OBJECT_LIST
13073 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013074 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13075 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013076 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13077
13078 Handle<JSObject> instance_filter;
13079 if (args[2]->IsJSObject()) {
13080 instance_filter = args.at<JSObject>(2);
13081 }
13082
13083 Object* result =
13084 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13085 return result;
13086#else
Steve Block44f0eee2011-05-26 01:26:41 +010013087 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013088#endif
13089}
13090
13091
13092// Generates the response to a debugger request for a list of all
13093// previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013094RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013095#ifdef LIVE_OBJECT_LIST
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013096 CONVERT_SMI_ARG_CHECKED(start, 0);
13097 CONVERT_SMI_ARG_CHECKED(count, 1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013098 return LiveObjectList::Info(start, count);
13099#else
Steve Block44f0eee2011-05-26 01:26:41 +010013100 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013101#endif
13102}
13103
13104
13105// Gets a dump of the specified object as requested by the debugger.
13106// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013107RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013108#ifdef LIVE_OBJECT_LIST
13109 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013110 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013111 Object* result = LiveObjectList::PrintObj(obj_id);
13112 return result;
13113#else
Steve Block44f0eee2011-05-26 01:26:41 +010013114 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013115#endif
13116}
13117
13118
13119// Resets and releases all previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013120RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013121#ifdef LIVE_OBJECT_LIST
13122 LiveObjectList::Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010013123 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013124#else
Steve Block44f0eee2011-05-26 01:26:41 +010013125 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013126#endif
13127}
13128
13129
13130// Generates the response to a debugger request for a summary of the types
13131// of objects in the difference between the captured live object lists
13132// specified by id1 and id2.
13133// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13134// summarized.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013135RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013136#ifdef LIVE_OBJECT_LIST
13137 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013138 CONVERT_SMI_ARG_CHECKED(id1, 0);
13139 CONVERT_SMI_ARG_CHECKED(id2, 1);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013140 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13141
13142 EnterDebugger enter_debugger;
13143 return LiveObjectList::Summarize(id1, id2, filter_obj);
13144#else
Steve Block44f0eee2011-05-26 01:26:41 +010013145 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013146#endif
13147}
13148
Steve Blocka7e24c12009-10-30 11:49:00 +000013149#endif // ENABLE_DEBUGGER_SUPPORT
13150
Steve Blockd0582a62009-12-15 09:54:21 +000013151
Ben Murdoch8b112d22011-06-08 16:22:53 +010013152RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
Steve Blockd0582a62009-12-15 09:54:21 +000013153 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013154 v8::V8::ResumeProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +010013155 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000013156}
13157
13158
Ben Murdoch8b112d22011-06-08 16:22:53 +010013159RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
Steve Blockd0582a62009-12-15 09:54:21 +000013160 NoHandleAllocation ha;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013161 v8::V8::PauseProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +010013162 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000013163}
13164
Steve Blocka7e24c12009-10-30 11:49:00 +000013165
13166// Finds the script object from the script data. NOTE: This operation uses
13167// heap traversal to find the function generated for the source position
13168// for the requested break point. For lazily compiled functions several heap
13169// traversals might be required rendering this operation as a rather slow
13170// operation. However for setting break points which is normally done through
13171// some kind of user interaction the performance is not crucial.
13172static Handle<Object> Runtime_GetScriptFromScriptName(
13173 Handle<String> script_name) {
13174 // Scan the heap for Script objects to find the script with the requested
13175 // script data.
13176 Handle<Script> script;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013177 script_name->GetHeap()->EnsureHeapIsIterable();
13178 AssertNoAllocation no_allocation_during_heap_iteration;
Steve Blocka7e24c12009-10-30 11:49:00 +000013179 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000013180 HeapObject* obj = NULL;
13181 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013182 // If a script is found check if it has the script data requested.
13183 if (obj->IsScript()) {
13184 if (Script::cast(obj)->name()->IsString()) {
13185 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13186 script = Handle<Script>(Script::cast(obj));
13187 }
13188 }
13189 }
13190 }
13191
13192 // If no script with the requested script data is found return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +010013193 if (script.is_null()) return FACTORY->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000013194
13195 // Return the script found.
13196 return GetScriptWrapper(script);
13197}
13198
13199
13200// Get the script object from script data. NOTE: Regarding performance
13201// see the NOTE for GetScriptFromScriptData.
13202// args[0]: script data for the script to find the source for
Ben Murdoch8b112d22011-06-08 16:22:53 +010013203RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +010013204 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013205
13206 ASSERT(args.length() == 1);
13207
13208 CONVERT_CHECKED(String, script_name, args[0]);
13209
13210 // Find the requested script.
13211 Handle<Object> result =
13212 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13213 return *result;
13214}
13215
13216
13217// Determines whether the given stack frame should be displayed in
13218// a stack trace. The caller is the error constructor that asked
13219// for the stack trace to be collected. The first time a construct
13220// call to this function is encountered it is skipped. The seen_caller
13221// in/out parameter is used to remember if the caller has been seen
13222// yet.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013223static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13224 Object* caller,
13225 bool* seen_caller) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013226 // Only display JS frames.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013227 if (!raw_frame->is_java_script()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013228 return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013229 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013230 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13231 Object* raw_fun = frame->function();
13232 // Not sure when this can happen but skip it just in case.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013233 if (!raw_fun->IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013234 return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013235 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013236 if ((raw_fun == caller) && !(*seen_caller)) {
13237 *seen_caller = true;
13238 return false;
13239 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013240 // Skip all frames until we've seen the caller.
13241 if (!(*seen_caller)) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013242 // Also, skip non-visible built-in functions and any call with the builtins
13243 // object as receiver, so as to not reveal either the builtins object or
13244 // an internal function.
13245 // The --builtins-in-stack-traces command line flag allows including
13246 // internal call sites in the stack trace for debugging purposes.
13247 if (!FLAG_builtins_in_stack_traces) {
13248 JSFunction* fun = JSFunction::cast(raw_fun);
13249 if (frame->receiver()->IsJSBuiltinsObject() ||
13250 (fun->IsBuiltin() && !fun->shared()->native())) {
13251 return false;
13252 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013253 }
13254 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000013255}
13256
13257
Ben Murdochb0fe1622011-05-05 13:52:32 +010013258// Collect the raw data for a stack trace. Returns an array of 4
13259// element segments each containing a receiver, function, code and
13260// native code offset.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013261RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013262 ASSERT_EQ(args.length(), 2);
13263 Handle<Object> caller = args.at<Object>(0);
13264 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13265
Steve Block44f0eee2011-05-26 01:26:41 +010013266 HandleScope scope(isolate);
13267 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000013268
Leon Clarkee46be812010-01-19 14:06:41 +000013269 limit = Max(limit, 0); // Ensure that limit is not negative.
13270 int initial_size = Min(limit, 10);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013271 Handle<FixedArray> elements =
Steve Block44f0eee2011-05-26 01:26:41 +010013272 factory->NewFixedArrayWithHoles(initial_size * 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000013273
Ben Murdoch8b112d22011-06-08 16:22:53 +010013274 StackFrameIterator iter(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013275 // If the caller parameter is a function we skip frames until we're
13276 // under it before starting to collect.
13277 bool seen_caller = !caller->IsJSFunction();
13278 int cursor = 0;
13279 int frames_seen = 0;
13280 while (!iter.done() && frames_seen < limit) {
13281 StackFrame* raw_frame = iter.frame();
13282 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
13283 frames_seen++;
13284 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Ben Murdoch8b112d22011-06-08 16:22:53 +010013285 // Set initial size to the maximum inlining level + 1 for the outermost
13286 // function.
13287 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +010013288 frame->Summarize(&frames);
13289 for (int i = frames.length() - 1; i >= 0; i--) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013290 if (cursor + 4 > elements->length()) {
13291 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13292 Handle<FixedArray> new_elements =
Steve Block44f0eee2011-05-26 01:26:41 +010013293 factory->NewFixedArrayWithHoles(new_capacity);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013294 for (int i = 0; i < cursor; i++) {
13295 new_elements->set(i, elements->get(i));
13296 }
13297 elements = new_elements;
13298 }
13299 ASSERT(cursor + 4 <= elements->length());
13300
Ben Murdochb0fe1622011-05-05 13:52:32 +010013301 Handle<Object> recv = frames[i].receiver();
13302 Handle<JSFunction> fun = frames[i].function();
13303 Handle<Code> code = frames[i].code();
13304 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013305 elements->set(cursor++, *recv);
13306 elements->set(cursor++, *fun);
13307 elements->set(cursor++, *code);
13308 elements->set(cursor++, *offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000013309 }
13310 }
13311 iter.Advance();
13312 }
Steve Block44f0eee2011-05-26 01:26:41 +010013313 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Leon Clarke4515c472010-02-03 11:58:03 +000013314 result->set_length(Smi::FromInt(cursor));
Steve Blocka7e24c12009-10-30 11:49:00 +000013315 return *result;
13316}
13317
13318
Steve Block3ce2e202009-11-05 08:53:23 +000013319// Returns V8 version as a string.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013320RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
Steve Block3ce2e202009-11-05 08:53:23 +000013321 ASSERT_EQ(args.length(), 0);
13322
13323 NoHandleAllocation ha;
13324
13325 const char* version_string = v8::V8::GetVersion();
13326
Steve Block44f0eee2011-05-26 01:26:41 +010013327 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13328 NOT_TENURED);
Steve Block3ce2e202009-11-05 08:53:23 +000013329}
13330
13331
Ben Murdoch8b112d22011-06-08 16:22:53 +010013332RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013333 ASSERT(args.length() == 2);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013334 OS::PrintError("abort: %s\n",
13335 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
Steve Block44f0eee2011-05-26 01:26:41 +010013336 isolate->PrintStack();
Steve Blocka7e24c12009-10-30 11:49:00 +000013337 OS::Abort();
13338 UNREACHABLE();
13339 return NULL;
13340}
13341
13342
Ben Murdoch8b112d22011-06-08 16:22:53 +010013343RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
Steve Block6ded16b2010-05-10 14:33:55 +010013344 // This is only called from codegen, so checks might be more lax.
Ben Murdochb8e0da22011-05-16 14:20:40 +010013345 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +010013346 Object* key = args[1];
13347
Ben Murdochb8e0da22011-05-16 14:20:40 +010013348 int finger_index = cache->finger_index();
Steve Block6ded16b2010-05-10 14:33:55 +010013349 Object* o = cache->get(finger_index);
13350 if (o == key) {
13351 // The fastest case: hit the same place again.
13352 return cache->get(finger_index + 1);
13353 }
13354
13355 for (int i = finger_index - 2;
13356 i >= JSFunctionResultCache::kEntriesIndex;
13357 i -= 2) {
13358 o = cache->get(i);
13359 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010013360 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010013361 return cache->get(i + 1);
13362 }
13363 }
13364
Ben Murdochb8e0da22011-05-16 14:20:40 +010013365 int size = cache->size();
Steve Block6ded16b2010-05-10 14:33:55 +010013366 ASSERT(size <= cache->length());
13367
13368 for (int i = size - 2; i > finger_index; i -= 2) {
13369 o = cache->get(i);
13370 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010013371 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010013372 return cache->get(i + 1);
13373 }
13374 }
13375
Ben Murdochb8e0da22011-05-16 14:20:40 +010013376 // There is no value in the cache. Invoke the function and cache result.
Steve Block44f0eee2011-05-26 01:26:41 +010013377 HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +010013378
13379 Handle<JSFunctionResultCache> cache_handle(cache);
13380 Handle<Object> key_handle(key);
13381 Handle<Object> value;
13382 {
13383 Handle<JSFunction> factory(JSFunction::cast(
13384 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13385 // TODO(antonm): consider passing a receiver when constructing a cache.
Steve Block44f0eee2011-05-26 01:26:41 +010013386 Handle<Object> receiver(isolate->global_context()->global());
Ben Murdochb8e0da22011-05-16 14:20:40 +010013387 // This handle is nor shared, nor used later, so it's safe.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013388 Handle<Object> argv[] = { key_handle };
13389 bool pending_exception;
Ben Murdochb8e0da22011-05-16 14:20:40 +010013390 value = Execution::Call(factory,
13391 receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013392 ARRAY_SIZE(argv),
Ben Murdochb8e0da22011-05-16 14:20:40 +010013393 argv,
13394 &pending_exception);
13395 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +010013396 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013397
13398#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013399 if (FLAG_verify_heap) {
13400 cache_handle->JSFunctionResultCacheVerify();
13401 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013402#endif
13403
13404 // Function invocation may have cleared the cache. Reread all the data.
13405 finger_index = cache_handle->finger_index();
13406 size = cache_handle->size();
13407
13408 // If we have spare room, put new data into it, otherwise evict post finger
13409 // entry which is likely to be the least recently used.
13410 int index = -1;
13411 if (size < cache_handle->length()) {
13412 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13413 index = size;
13414 } else {
13415 index = finger_index + JSFunctionResultCache::kEntrySize;
13416 if (index == cache_handle->length()) {
13417 index = JSFunctionResultCache::kEntriesIndex;
13418 }
13419 }
13420
13421 ASSERT(index % 2 == 0);
13422 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13423 ASSERT(index < cache_handle->length());
13424
13425 cache_handle->set(index, *key_handle);
13426 cache_handle->set(index + 1, *value);
13427 cache_handle->set_finger_index(index);
13428
13429#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013430 if (FLAG_verify_heap) {
13431 cache_handle->JSFunctionResultCacheVerify();
13432 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010013433#endif
13434
13435 return *value;
Steve Block6ded16b2010-05-10 14:33:55 +010013436}
13437
Steve Block1e0659c2011-05-24 12:43:12 +010013438
Ben Murdoch8b112d22011-06-08 16:22:53 +010013439RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
Steve Block44f0eee2011-05-26 01:26:41 +010013440 HandleScope scope(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +010013441 CONVERT_ARG_CHECKED(String, type, 0);
13442 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010013443 return *isolate->factory()->NewJSMessageObject(
13444 type,
13445 arguments,
13446 0,
13447 0,
13448 isolate->factory()->undefined_value(),
13449 isolate->factory()->undefined_value(),
13450 isolate->factory()->undefined_value());
Steve Block1e0659c2011-05-24 12:43:12 +010013451}
13452
13453
Ben Murdoch8b112d22011-06-08 16:22:53 +010013454RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
Steve Block1e0659c2011-05-24 12:43:12 +010013455 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13456 return message->type();
13457}
13458
13459
Ben Murdoch8b112d22011-06-08 16:22:53 +010013460RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
Steve Block1e0659c2011-05-24 12:43:12 +010013461 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13462 return message->arguments();
13463}
13464
13465
Ben Murdoch8b112d22011-06-08 16:22:53 +010013466RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
Steve Block1e0659c2011-05-24 12:43:12 +010013467 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13468 return Smi::FromInt(message->start_position());
13469}
13470
13471
Ben Murdoch8b112d22011-06-08 16:22:53 +010013472RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
Steve Block1e0659c2011-05-24 12:43:12 +010013473 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13474 return message->script();
13475}
13476
13477
Steve Blocka7e24c12009-10-30 11:49:00 +000013478#ifdef DEBUG
13479// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13480// Exclude the code in release mode.
Ben Murdoch8b112d22011-06-08 16:22:53 +010013481RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013482 ASSERT(args.length() == 0);
13483 HandleScope scope;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013484#define COUNT_ENTRY(Name, argc, ressize) + 1
13485 int entry_count = 0
13486 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13487 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13488 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13489#undef COUNT_ENTRY
Steve Block44f0eee2011-05-26 01:26:41 +010013490 Factory* factory = isolate->factory();
13491 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
Steve Blocka7e24c12009-10-30 11:49:00 +000013492 int index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010013493 bool inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013494#define ADD_ENTRY(Name, argc, ressize) \
13495 { \
13496 HandleScope inner; \
Steve Block6ded16b2010-05-10 14:33:55 +010013497 Handle<String> name; \
13498 /* Inline runtime functions have an underscore in front of the name. */ \
13499 if (inline_runtime_functions) { \
Steve Block44f0eee2011-05-26 01:26:41 +010013500 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010013501 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13502 } else { \
Steve Block44f0eee2011-05-26 01:26:41 +010013503 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010013504 Vector<const char>(#Name, StrLength(#Name))); \
13505 } \
Steve Block44f0eee2011-05-26 01:26:41 +010013506 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013507 pair_elements->set(0, *name); \
13508 pair_elements->set(1, Smi::FromInt(argc)); \
Steve Block44f0eee2011-05-26 01:26:41 +010013509 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013510 elements->set(index++, *pair); \
Steve Blocka7e24c12009-10-30 11:49:00 +000013511 }
Steve Block6ded16b2010-05-10 14:33:55 +010013512 inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013513 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010013514 inline_runtime_functions = true;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013515 INLINE_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010013516 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Blocka7e24c12009-10-30 11:49:00 +000013517#undef ADD_ENTRY
Ben Murdoche0cee9b2011-05-25 10:26:03 +010013518 ASSERT_EQ(index, entry_count);
Steve Block44f0eee2011-05-26 01:26:41 +010013519 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +000013520 return *result;
13521}
13522#endif
13523
13524
Ben Murdoch8b112d22011-06-08 16:22:53 +010013525RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013526 ASSERT(args.length() == 2);
13527 CONVERT_CHECKED(String, format, args[0]);
13528 CONVERT_CHECKED(JSArray, elms, args[1]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013529 String::FlatContent format_content = format->GetFlatContent();
13530 RUNTIME_ASSERT(format_content.IsAscii());
13531 Vector<const char> chars = format_content.ToAsciiVector();
Steve Block44f0eee2011-05-26 01:26:41 +010013532 LOGGER->LogRuntime(chars, elms);
13533 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000013534}
13535
13536
Ben Murdoch8b112d22011-06-08 16:22:53 +010013537RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013538 UNREACHABLE(); // implemented as macro in the parser
13539 return NULL;
13540}
13541
13542
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013543#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13544 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13545 CONVERT_CHECKED(JSObject, obj, args[0]); \
13546 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13547 }
13548
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013549ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013550ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13551ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13552ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13553ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13554ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13555ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13556ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13557ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13558ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13559ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13560ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13561ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13562ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13563
13564#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13565
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013566
13567RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13568 ASSERT(args.length() == 2);
13569 CONVERT_CHECKED(JSObject, obj1, args[0]);
13570 CONVERT_CHECKED(JSObject, obj2, args[1]);
13571 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13572}
13573
Steve Blocka7e24c12009-10-30 11:49:00 +000013574// ----------------------------------------------------------------------------
13575// Implementation of Runtime
13576
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013577#define F(name, number_of_args, result_size) \
13578 { Runtime::k##name, Runtime::RUNTIME, #name, \
13579 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
Steve Blocka7e24c12009-10-30 11:49:00 +000013580
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013581
13582#define I(name, number_of_args, result_size) \
13583 { Runtime::kInline##name, Runtime::INLINE, \
13584 "_" #name, NULL, number_of_args, result_size },
13585
Steve Block44f0eee2011-05-26 01:26:41 +010013586static const Runtime::Function kIntrinsicFunctions[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000013587 RUNTIME_FUNCTION_LIST(F)
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013588 INLINE_FUNCTION_LIST(I)
13589 INLINE_RUNTIME_FUNCTION_LIST(I)
Steve Blocka7e24c12009-10-30 11:49:00 +000013590};
13591
Steve Blocka7e24c12009-10-30 11:49:00 +000013592
Steve Block44f0eee2011-05-26 01:26:41 +010013593MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13594 Object* dictionary) {
13595 ASSERT(Isolate::Current()->heap() == heap);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013596 ASSERT(dictionary != NULL);
13597 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13598 for (int i = 0; i < kNumFunctions; ++i) {
John Reck59135872010-11-02 12:39:01 -070013599 Object* name_symbol;
13600 { MaybeObject* maybe_name_symbol =
Steve Block44f0eee2011-05-26 01:26:41 +010013601 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
John Reck59135872010-11-02 12:39:01 -070013602 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13603 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013604 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
John Reck59135872010-11-02 12:39:01 -070013605 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13606 String::cast(name_symbol),
13607 Smi::FromInt(i),
13608 PropertyDetails(NONE, NORMAL));
13609 if (!maybe_dictionary->ToObject(&dictionary)) {
13610 // Non-recoverable failure. Calling code must restart heap
13611 // initialization.
13612 return maybe_dictionary;
13613 }
13614 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013615 }
13616 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000013617}
13618
13619
Steve Block44f0eee2011-05-26 01:26:41 +010013620const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13621 Heap* heap = name->GetHeap();
13622 int entry = heap->intrinsic_function_names()->FindEntry(*name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013623 if (entry != kNotFound) {
Steve Block44f0eee2011-05-26 01:26:41 +010013624 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013625 int function_index = Smi::cast(smi_index)->value();
13626 return &(kIntrinsicFunctions[function_index]);
Steve Blocka7e24c12009-10-30 11:49:00 +000013627 }
13628 return NULL;
13629}
13630
13631
Steve Block44f0eee2011-05-26 01:26:41 +010013632const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010013633 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13634}
13635
13636
Steve Blocka7e24c12009-10-30 11:49:00 +000013637void Runtime::PerformGC(Object* result) {
Steve Block44f0eee2011-05-26 01:26:41 +010013638 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000013639 Failure* failure = Failure::cast(result);
13640 if (failure->IsRetryAfterGC()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013641 if (isolate->heap()->new_space()->AddFreshPage()) {
13642 return;
13643 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013644 // Try to do a garbage collection; ignore it if it fails. The C
13645 // entry stub will throw an out-of-memory exception in that case.
Steve Block44f0eee2011-05-26 01:26:41 +010013646 isolate->heap()->CollectGarbage(failure->allocation_space());
Steve Blocka7e24c12009-10-30 11:49:00 +000013647 } else {
13648 // Handle last resort GC and make sure to allow future allocations
13649 // to grow the heap without causing GCs (if possible).
Steve Block44f0eee2011-05-26 01:26:41 +010013650 isolate->counters()->gc_last_resort_from_js()->Increment();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000013651 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
Steve Blocka7e24c12009-10-30 11:49:00 +000013652 }
13653}
13654
13655
13656} } // namespace v8::internal