blob: 855bd41cb9a48c2f66203de3fe20d89e20cc0930 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 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"
Steve Block6ded16b2010-05-10 14:33:55 +010035#include "codegen.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036#include "compilation-cache.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037#include "compiler.h"
38#include "cpu.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "dateparser-inl.h"
40#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010041#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042#include "execution.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010043#include "global-handles.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "jsregexp.h"
Steve Block6ded16b2010-05-10 14:33:55 +010045#include "liveedit.h"
Ben Murdoche0cee9b2011-05-25 10:26:03 +010046#include "liveobjectlist-inl.h"
Steve Block3ce2e202009-11-05 08:53:23 +000047#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000048#include "platform.h"
49#include "runtime.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010050#include "runtime-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000051#include "scopeinfo.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000052#include "smart-pointer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000053#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000054#include "v8threads.h"
Steve Block59151502010-09-22 15:07:15 +010055#include "string-search.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000056
57namespace v8 {
58namespace internal {
59
60
61#define RUNTIME_ASSERT(value) \
Steve Block44f0eee2011-05-26 01:26:41 +010062 if (!(value)) return isolate->ThrowIllegalOperation();
Steve Blocka7e24c12009-10-30 11:49:00 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
75// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
82// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
89// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
Steve Blocka7e24c12009-10-30 11:49:00 +0000103
Steve Block44f0eee2011-05-26 01:26:41 +0100104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +0000108
Steve Block44f0eee2011-05-26 01:26:41 +0100109 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -0700110 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
John Reck59135872010-11-02 12:39:01 -0700112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000122 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
Leon Clarke4515c472010-02-03 11:58:03 +0000126 properties->set(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 }
128 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000133 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
John Reck59135872010-11-02 12:39:01 -0700135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
Leon Clarke4515c472010-02-03 11:58:03 +0000137 copy->InObjectPropertyAtPut(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 }
139 }
140 } else {
John Reck59135872010-11-02 12:39:01 -0700141 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
John Reck59135872010-11-02 12:39:01 -0700143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
Leon Clarke4515c472010-02-03 11:58:03 +0000149 String* key_string = String::cast(names->get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 PropertyAttributes attributes =
Leon Clarke4515c472010-02-03 11:58:03 +0000151 copy->GetLocalPropertyAttribute(key_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
John Reck59135872010-11-02 12:39:01 -0700156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 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 }
163 { MaybeObject* maybe_result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -0700166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
173 // Pixel elements cannot be created using an object literal.
Steve Block44f0eee2011-05-26 01:26:41 +0100174 ASSERT(!copy->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
Steve Block44f0eee2011-05-26 01:26:41 +0100178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
John Reck59135872010-11-02 12:39:01 -0700192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
Iain Merrick75681382010-08-19 15:07:18 +0100194 elements->set(i, result);
195 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 }
197 }
198 break;
199 }
200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000208 JSObject* js_object = JSObject::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +0100209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
John Reck59135872010-11-02 12:39:01 -0700211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
222 }
223 return copy;
224}
225
226
Ben Murdoch8b112d22011-06-08 16:22:53 +0100227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +0100229 return DeepCopyBoilerplate(isolate, boilerplate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000230}
231
232
Ben Murdoch8b112d22011-06-08 16:22:53 +0100233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +0100235 return isolate->heap()->CopyJSObject(boilerplate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000236}
237
238
239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
242 bool* is_result_from_cache) {
Steve Block44f0eee2011-05-26 01:26:41 +0100243 Isolate* isolate = context->GetIsolate();
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 if (FLAG_canonicalize_object_literal_maps) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100247 // Check that there are only symbols and array indices among keys.
Steve Blocka7e24c12009-10-30 11:49:00 +0000248 int number_of_symbol_keys = 0;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
Steve Blocka7e24c12009-10-30 11:49:00 +0000266 const int kMaxKeys = 10;
267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
269 // Create the fixed array with the key.
Steve Block44f0eee2011-05-26 01:26:41 +0100270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 }
282 *is_result_from_cache = true;
Steve Block44f0eee2011-05-26 01:26:41 +0100283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 }
285 }
286 *is_result_from_cache = false;
Steve Block44f0eee2011-05-26 01:26:41 +0100287 return isolate->factory()->CopyMap(
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
290}
291
292
293static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100294 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
297
298
299static Handle<Object> CreateObjectLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100300 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000301 Handle<FixedArray> literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100302 Handle<FixedArray> constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100303 bool should_have_fast_elements,
304 bool has_function_literal) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
Steve Block44f0eee2011-05-26 01:26:41 +0100314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
Steve Blocka7e24c12009-10-30 11:49:00 +0000324
Steve Block44f0eee2011-05-26 01:26:41 +0100325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
Steve Block6ded16b2010-05-10 14:33:55 +0100326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
Steve Block44f0eee2011-05-26 01:26:41 +0100330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000360 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
Ben Murdoch086aeea2011-05-13 15:57:08 +0100363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 }
Steve Block44f0eee2011-05-26 01:26:41 +0100366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000383 }
Steve Block44f0eee2011-05-26 01:26:41 +0100384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 }
399
400 return boilerplate;
401}
402
403
404static Handle<Object> CreateArrayLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100405 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
Steve Block44f0eee2011-05-26 01:26:41 +0100411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
Steve Blocka7e24c12009-10-30 11:49:00 +0000412
Steve Block44f0eee2011-05-26 01:26:41 +0100413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
Iain Merrick75681382010-08-19 15:07:18 +0100415 Handle<FixedArray> copied_elements =
Steve Block44f0eee2011-05-26 01:26:41 +0100416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
Iain Merrick75681382010-08-19 15:07:18 +0100419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
Steve Block44f0eee2011-05-26 01:26:41 +0100430 // simple object or array literal.
Iain Merrick75681382010-08-19 15:07:18 +0100431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
Steve Block44f0eee2011-05-26 01:26:41 +0100433 CreateLiteralBoilerplate(isolate, literals, fa);
Iain Merrick75681382010-08-19 15:07:18 +0100434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
Steve Block44f0eee2011-05-26 01:26:41 +0100447 Isolate* isolate,
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
Steve Block44f0eee2011-05-26 01:26:41 +0100451 const bool kHasNoFunctionLiteral = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 switch (CompileTimeValue::GetType(array)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
Steve Block6ded16b2010-05-10 14:33:55 +0100459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
Steve Block44f0eee2011-05-26 01:26:41 +0100460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 case CompileTimeValue::ARRAY_LITERAL:
Steve Block44f0eee2011-05-26 01:26:41 +0100466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
Ben Murdoch8b112d22011-06-08 16:22:53 +0100474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
Steve Block44f0eee2011-05-26 01:26:41 +0100480 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
485
Steve Block44f0eee2011-05-26 01:26:41 +0100486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000488 if (object.is_null()) return Failure::Exception();
489
490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
493}
494
495
Ben Murdoch8b112d22011-06-08 16:22:53 +0100496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100497 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100498 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000505
506 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100511 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100512 should_have_fast_elements,
513 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
Steve Block44f0eee2011-05-26 01:26:41 +0100518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000519}
520
521
Ben Murdoch8b112d22011-06-08 16:22:53 +0100522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100523 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100524 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
Leon Clarkee46be812010-01-19 14:06:41 +0000531
532 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100537 constant_properties,
Steve Block44f0eee2011-05-26 01:26:41 +0100538 should_have_fast_elements,
539 has_function_literal);
Leon Clarkee46be812010-01-19 14:06:41 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
Steve Block44f0eee2011-05-26 01:26:41 +0100544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000545}
546
547
Ben Murdoch8b112d22011-06-08 16:22:53 +0100548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +0100549 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
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 = CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
Steve Block44f0eee2011-05-26 01:26:41 +0100563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000564}
565
566
Ben Murdoch8b112d22011-06-08 16:22:53 +0100567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
Steve Block44f0eee2011-05-26 01:26:41 +0100568 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
Steve Block44f0eee2011-05-26 01:26:41 +0100575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
Iain Merrick75681382010-08-19 15:07:18 +0100582 if (JSObject::cast(*boilerplate)->elements()->map() ==
Steve Block44f0eee2011-05-26 01:26:41 +0100583 isolate->heap()->fixed_cow_array_map()) {
584 isolate->counters()->cow_arrays_created_runtime()->Increment();
Iain Merrick75681382010-08-19 15:07:18 +0100585 }
Steve Block44f0eee2011-05-26 01:26:41 +0100586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
Leon Clarkee46be812010-01-19 14:06:41 +0000587}
588
589
Ben Murdoch8b112d22011-06-08 16:22:53 +0100590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
Steve Block44f0eee2011-05-26 01:26:41 +0100596 isolate->context()->global_context()->
597 context_extension_function();
John Reck59135872010-11-02 12:39:01 -0700598 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +0100599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -0700600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
John Reck59135872010-11-02 12:39:01 -0700604 { MaybeObject* maybe_value =
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -0700608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 return object;
611}
612
613
Ben Murdoch8b112d22011-06-08 16:22:53 +0100614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +0100618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 return JSObject::cast(obj)->class_name();
620}
621
622
Ben Murdoch8b112d22011-06-08 16:22:53 +0100623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 V = prototype;
634 }
635}
636
637
638// Inserts an object as the hidden prototype of another object.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
John Reck59135872010-11-02 12:39:01 -0700653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
John Reck59135872010-11-02 12:39:01 -0700661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
Steve Block44f0eee2011-05-26 01:26:41 +0100677 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000678}
679
680
Ben Murdoch8b112d22011-06-08 16:22:53 +0100681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000682 NoHandleAllocation ha;
683 ASSERT(args.length() == 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100684 JavaScriptFrameIterator it(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +0100685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000686}
687
688
Leon Clarkee46be812010-01-19 14:06:41 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
Steve Block1e0659c2011-05-24 12:43:12 +0100705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100732 Isolate* isolate = obj->GetIsolate();
Steve Block1e0659c2011-05-24 12:43:12 +0100733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100735 !isolate->MayNamedAccess(current, name, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
Steve Block44f0eee2011-05-26 01:26:41 +0100772 isolate->ReportFailedAccessCheck(current, access_type);
Steve Block1e0659c2011-05-24 12:43:12 +0100773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
Steve Block1e0659c2011-05-24 12:43:12 +0100783 return false;
784 }
785
786 return true;
787}
788
789
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
Leon Clarkee46be812010-01-19 14:06:41 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
Ben Murdoch8b112d22011-06-08 16:22:53 +0100809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
Leon Clarkee46be812010-01-19 14:06:41 +0000810 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +0100811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
Leon Clarkee46be812010-01-19 14:06:41 +0000815 LookupResult result;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000818
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
Steve Block44f0eee2011-05-26 01:26:41 +0100824 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100825
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
Steve Block1e0659c2011-05-24 12:43:12 +0100833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100834
Steve Block44f0eee2011-05-26 01:26:41 +0100835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100836 elms->set(VALUE_INDEX, *substr);
Steve Block44f0eee2011-05-26 01:26:41 +0100837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
Steve Block44f0eee2011-05-26 01:26:41 +0100845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100846 Handle<Object> value = GetElement(obj, index);
Steve Block44f0eee2011-05-26 01:26:41 +0100847 RETURN_IF_EMPTY_HANDLE(isolate, value);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100848 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +0100849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
Steve Block1e0659c2011-05-24 12:43:12 +0100856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100859 if (proto->IsNull()) return heap->undefined_value();
Steve Block1e0659c2011-05-24 12:43:12 +0100860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
Steve Block44f0eee2011-05-26 01:26:41 +0100872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +0100873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100879 break;
880 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100881 case NORMAL: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100882 // This is a data property.
Steve Block44f0eee2011-05-26 01:26:41 +0100883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100884 Handle<Object> value = GetElement(obj, index);
885 ASSERT(!value.is_null());
886 elms->set(VALUE_INDEX, *value);
Steve Block44f0eee2011-05-26 01:26:41 +0100887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100888 break;
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100889 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100890 default:
891 UNREACHABLE();
892 break;
893 }
Steve Block44f0eee2011-05-26 01:26:41 +0100894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100896 return *desc;
897 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100898 }
899 }
900
Leon Clarkee46be812010-01-19 14:06:41 +0000901 // Use recursive implementation to also traverse hidden prototypes
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100902 GetOwnPropertyImplementation(*obj, *name, &result);
Leon Clarkee46be812010-01-19 14:06:41 +0000903
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100904 if (!result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100905 return heap->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100906 }
Steve Block1e0659c2011-05-24 12:43:12 +0100907
908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
Steve Block44f0eee2011-05-26 01:26:41 +0100909 return heap->false_value();
Leon Clarkee46be812010-01-19 14:06:41 +0000910 }
911
Steve Block44f0eee2011-05-26 01:26:41 +0100912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
Steve Block1e0659c2011-05-24 12:43:12 +0100914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
Steve Block44f0eee2011-05-26 01:26:41 +0100920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
Steve Block1e0659c2011-05-24 12:43:12 +0100921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
929 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
Steve Block1e0659c2011-05-24 12:43:12 +0100932
933 PropertyAttributes attrs;
934 Object* value;
935 // GetProperty will check access and report any violations.
936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
Leon Clarkee46be812010-01-19 14:06:41 +0000942 return *desc;
943}
944
945
Ben Murdoch8b112d22011-06-08 16:22:53 +0100946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
Steve Block8defd9f2010-07-08 12:39:36 +0100947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
Steve Block1e0659c2011-05-24 12:43:12 +0100952
Ben Murdoch8b112d22011-06-08 16:22:53 +0100953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
Leon Clarkee46be812010-01-19 14:06:41 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
Steve Block1e0659c2011-05-24 12:43:12 +0100956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100958 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +0100959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
Steve Block44f0eee2011-05-26 01:26:41 +0100962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
Leon Clarkee46be812010-01-19 14:06:41 +0000964}
965
966
Ben Murdoch8b112d22011-06-08 16:22:53 +0100967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +0100968 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 ASSERT(args.length() == 3);
970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
976}
977
978
Ben Murdoch8b112d22011-06-08 16:22:53 +0100979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +0100980 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 ASSERT(args.length() == 1);
982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100983 return *isolate->factory()->CreateApiFunction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000984}
985
986
Ben Murdoch8b112d22011-06-08 16:22:53 +0100987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
Steve Block44f0eee2011-05-26 01:26:41 +0100991 return isolate->heap()->ToBoolean(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000992}
993
994
Ben Murdoch8b112d22011-06-08 16:22:53 +0100995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
998 CONVERT_CHECKED(Smi, field, args[1]);
999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
Steve Block3ce2e202009-11-05 08:53:23 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
1011}
1012
1013
Ben Murdoch8b112d22011-06-08 16:22:53 +01001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
1017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -07001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
Steve Block44f0eee2011-05-26 01:26:41 +01001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001031}
1032
1033
Ben Murdoch8b112d22011-06-08 16:22:53 +01001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
1037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -07001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
Steve Block44f0eee2011-05-26 01:26:41 +01001048 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001049}
1050
1051
Steve Block44f0eee2011-05-26 01:26:41 +01001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
Steve Blocka7e24c12009-10-30 11:49:00 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00001062}
1063
1064
Ben Murdoch8b112d22011-06-08 16:22:53 +01001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001066 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001070
Steve Block3ce2e202009-11-05 08:53:23 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
1084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
Steve Block44f0eee2011-05-26 01:26:41 +01001087 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 Handle<String> name(String::cast(pairs->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +01001089 Handle<Object> value(pairs->get(i + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001119 return ThrowRedeclarationError(isolate, type, name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001131 return ThrowRedeclarationError(isolate, "const", name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001132 }
1133 // Otherwise, we check for locally conflicting declarations.
Steve Blocka7e24c12009-10-30 11:49:00 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001136 return ThrowRedeclarationError(isolate, type, name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
Steve Block6ded16b2010-05-10 14:33:55 +01001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 Handle<JSFunction> function =
Steve Block44f0eee2011-05-26 01:26:41 +01001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001172 return ThrowRedeclarationError(isolate, type, name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001173 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001174
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
1183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
Steve Blocka7e24c12009-10-30 11:49:00 +00001187 }
Steve Block44f0eee2011-05-26 01:26:41 +01001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001190 name,
1191 value,
1192 attributes));
Steve Blocka7e24c12009-10-30 11:49:00 +00001193 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 }
1201 }
1202
Steve Block44f0eee2011-05-26 01:26:41 +01001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001205}
1206
1207
Ben Murdoch8b112d22011-06-08 16:22:53 +01001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001209 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 ASSERT(args.length() == 4);
1211
1212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
1214 PropertyAttributes mode =
1215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Steve Block44f0eee2011-05-26 01:26:41 +01001217 Handle<Object> initial_value(args[3], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
1225 Handle<Object> holder =
1226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
Steve Block44f0eee2011-05-26 01:26:41 +01001236 return ThrowRedeclarationError(isolate, type, name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
Steve Blockd0582a62009-12-15 09:54:21 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001255 if (result.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
1259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
Steve Block1e0659c2011-05-24 12:43:12 +01001260 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001261 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 }
1265 }
1266
1267 } else {
1268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
1272 if (context->has_extension()) {
1273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
Steve Block44f0eee2011-05-26 01:26:41 +01001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
Steve Blocka7e24c12009-10-30 11:49:00 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
1284
1285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
Steve Block44f0eee2011-05-26 01:26:41 +01001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 if (*initial_value != NULL) value = initial_value;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001302 return ThrowRedeclarationError(isolate, "const", name);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001303 }
1304 }
Steve Block44f0eee2011-05-26 01:26:41 +01001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001307 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 }
1309
Steve Block44f0eee2011-05-26 01:26:41 +01001310 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001311}
1312
1313
Ben Murdoch8b112d22011-06-08 16:22:53 +01001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 NoHandleAllocation nha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
Steve Blocka7e24c12009-10-30 11:49:00 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
Steve Blocka7e24c12009-10-30 11:49:00 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01001326 GlobalObject* global = isolate->context()->global();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
1337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001340 // to assign to the property.
Steve Blockd0582a62009-12-15 09:54:21 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
Steve Blocka7e24c12009-10-30 11:49:00 +00001344 LookupResult lookup;
Steve Blockd0582a62009-12-15 09:54:21 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
Steve Block44f0eee2011-05-26 01:26:41 +01001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
Steve Blockd0582a62009-12-15 09:54:21 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
Steve Block44f0eee2011-05-26 01:26:41 +01001361 HandleScope handle_scope(isolate);
Steve Blockd0582a62009-12-15 09:54:21 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
Steve Block44f0eee2011-05-26 01:26:41 +01001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
Steve Blockd0582a62009-12-15 09:54:21 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
Steve Block44f0eee2011-05-26 01:26:41 +01001382 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
Steve Block44f0eee2011-05-26 01:26:41 +01001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001389 }
Steve Blockd0582a62009-12-15 09:54:21 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 }
1400
Steve Block44f0eee2011-05-26 01:26:41 +01001401 global = isolate->context()->global();
Steve Blockd0582a62009-12-15 09:54:21 +00001402 if (assign) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001403 return global->SetProperty(*name, args[2], attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 }
Steve Block44f0eee2011-05-26 01:26:41 +01001405 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001406}
1407
1408
Ben Murdoch8b112d22011-06-08 16:22:53 +01001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
Steve Block44f0eee2011-05-26 01:26:41 +01001418 GlobalObject* global = isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
Ben Murdoch086aeea2011-05-13 15:57:08 +01001429 // We use SetLocalPropertyIgnoreAttributes instead
Steve Blocka7e24c12009-10-30 11:49:00 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
Steve Block44f0eee2011-05-26 01:26:41 +01001443 return ThrowRedeclarationError(isolate, "var", name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01001451 return ThrowRedeclarationError(isolate, "var", name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
Steve Block44f0eee2011-05-26 01:26:41 +01001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001459
Steve Block1e0659c2011-05-24 12:43:12 +01001460 // BUG 1213575: Handle the case where we have to set a read-only
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001463 // Passing non-strict mode because the property is writable.
Steve Block44f0eee2011-05-26 01:26:41 +01001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001476 // Strict mode handling not needed (const disallowed in strict mode).
Steve Blocka7e24c12009-10-30 11:49:00 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
1485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
1487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
Ben Murdoch8b112d22011-06-08 16:22:53 +01001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01001500 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 ASSERT(args.length() == 3);
1502
Steve Block44f0eee2011-05-26 01:26:41 +01001503 Handle<Object> value(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
1513 ContextLookupFlags flags = FOLLOW_CHAINS;
1514 Handle<Object> holder =
1515 context->Lookup(name, flags, &index, &attributes);
1516
1517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
1529 if (index >= 0) {
1530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001543 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001544 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001545 SetElement(arguments, index, value, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001546 }
1547 return *value;
1548 }
1549
1550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
Steve Block44f0eee2011-05-26 01:26:41 +01001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001557 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001558 SetProperty(global, name, value, NONE, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001559 return *value;
1560 }
1561
1562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
1564
1565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
1583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
1585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
1590 }
1591 } else {
1592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001595 // Strict mode not needed (const disallowed in strict mode).
Steve Block1e0659c2011-05-24 12:43:12 +01001596 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01001597 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 }
1600 }
1601
1602 return *value;
1603}
1604
1605
Ben Murdoch8b112d22011-06-08 16:22:53 +01001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01001608 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
Ben Murdoch8b112d22011-06-08 16:22:53 +01001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
Steve Block44f0eee2011-05-26 01:26:41 +01001620 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 ASSERT(args.length() == 4);
1622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
1624 // Due to the way the JS calls are constructed this must be less than the
1625 // length of a string, i.e. it is always a Smi. We check anyway for security.
1626 CONVERT_SMI_CHECKED(index, args[2]);
1627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
1628 RUNTIME_ASSERT(last_match_info->HasFastElements());
1629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
Steve Block44f0eee2011-05-26 01:26:41 +01001631 isolate->counters()->regexp_entry_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
1634 index,
1635 last_match_info);
1636 if (result.is_null()) return Failure::Exception();
1637 return *result;
1638}
1639
1640
Ben Murdoch8b112d22011-06-08 16:22:53 +01001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
Steve Block6ded16b2010-05-10 14:33:55 +01001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
Steve Block44f0eee2011-05-26 01:26:41 +01001645 return isolate->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01001646 }
John Reck59135872010-11-02 12:39:01 -07001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
Steve Block44f0eee2011-05-26 01:26:41 +01001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
John Reck59135872010-11-02 12:39:01 -07001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
Steve Block6ded16b2010-05-10 14:33:55 +01001652 FixedArray* elements = FixedArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
John Reck59135872010-11-02 12:39:01 -07001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
Steve Block6ded16b2010-05-10 14:33:55 +01001657 {
1658 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +01001659 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001660 reinterpret_cast<HeapObject*>(new_object)->
Steve Block44f0eee2011-05-26 01:26:41 +01001661 set_map(isolate->global_context()->regexp_result_map());
Steve Block6ded16b2010-05-10 14:33:55 +01001662 }
1663 JSArray* array = JSArray::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01001664 array->set_properties(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
Ben Murdoch8b112d22011-06-08 16:22:53 +01001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
Steve Block6ded16b2010-05-10 14:33:55 +01001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
Steve Block44f0eee2011-05-26 01:26:41 +01001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001682
1683 Object* ignoreCase = args[3];
Steve Block44f0eee2011-05-26 01:26:41 +01001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001685
1686 Object* multiline = args[4];
Steve Block44f0eee2011-05-26 01:26:41 +01001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
Steve Block44f0eee2011-05-26 01:26:41 +01001706 // Map has changed, so use generic, but slower, method.
Steve Block6ded16b2010-05-10 14:33:55 +01001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
Steve Block44f0eee2011-05-26 01:26:41 +01001711 Heap* heap = isolate->heap();
John Reck59135872010-11-02 12:39:01 -07001712 MaybeObject* result;
Steve Block44f0eee2011-05-26 01:26:41 +01001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001714 source,
1715 final);
John Reck59135872010-11-02 12:39:01 -07001716 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001718 global,
1719 final);
John Reck59135872010-11-02 12:39:01 -07001720 ASSERT(!result->IsFailure());
1721 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001723 ignoreCase,
1724 final);
John Reck59135872010-11-02 12:39:01 -07001725 ASSERT(!result->IsFailure());
Steve Block44f0eee2011-05-26 01:26:41 +01001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001727 multiline,
1728 final);
John Reck59135872010-11-02 12:39:01 -07001729 ASSERT(!result->IsFailure());
1730 result =
Steve Block44f0eee2011-05-26 01:26:41 +01001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
Ben Murdoch086aeea2011-05-13 15:57:08 +01001732 Smi::FromInt(0),
1733 writable);
John Reck59135872010-11-02 12:39:01 -07001734 ASSERT(!result->IsFailure());
1735 USE(result);
Steve Block6ded16b2010-05-10 14:33:55 +01001736 return regexp;
1737}
1738
1739
Ben Murdoch8b112d22011-06-08 16:22:53 +01001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
Steve Block44f0eee2011-05-26 01:26:41 +01001741 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
Steve Block44f0eee2011-05-26 01:26:41 +01001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +01001747 return Smi::FromInt(0);
1748}
1749
1750
Steve Block44f0eee2011-05-26 01:26:41 +01001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
Steve Block6ded16b2010-05-10 14:33:55 +01001753 const char* name,
Kristian Monsen25f61362010-05-21 11:50:48 +01001754 Builtins::Name builtin_name) {
Steve Block44f0eee2011-05-26 01:26:41 +01001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
Steve Block6ded16b2010-05-10 14:33:55 +01001763 optimized->shared()->DontAdaptArguments();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +01001765 return optimized;
1766}
1767
1768
Ben Murdoch8b112d22011-06-08 16:22:53 +01001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
Steve Block44f0eee2011-05-26 01:26:41 +01001770 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
Steve Block44f0eee2011-05-26 01:26:41 +01001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
Steve Block6ded16b2010-05-10 14:33:55 +01001781
1782 return *holder;
1783}
1784
1785
Ben Murdoch8b112d22011-06-08 16:22:53 +01001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
Steve Block6ded16b2010-05-10 14:33:55 +01001787 // Returns a real global receiver, not one of builtins object.
Steve Block44f0eee2011-05-26 01:26:41 +01001788 Context* global_context =
1789 isolate->context()->global()->global_context();
Steve Block6ded16b2010-05-10 14:33:55 +01001790 return global_context->global()->global_receiver();
1791}
1792
1793
Ben Murdoch8b112d22011-06-08 16:22:53 +01001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
Steve Block44f0eee2011-05-26 01:26:41 +01001795 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
1802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
1807 Handle<JSFunction> constructor =
1808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
1810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
1813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
1815 if (has_pending_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01001816 ASSERT(isolate->has_pending_exception());
Steve Blocka7e24c12009-10-30 11:49:00 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
Ben Murdoch8b112d22011-06-08 16:22:53 +01001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
Ben Murdoch8b112d22011-06-08 16:22:53 +01001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001840 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001841}
1842
1843
Ben Murdoch8b112d22011-06-08 16:22:53 +01001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
Steve Block6ded16b2010-05-10 14:33:55 +01001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +01001851
Steve Block44f0eee2011-05-26 01:26:41 +01001852 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01001853}
1854
1855
Ben Murdoch8b112d22011-06-08 16:22:53 +01001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +01001857 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
Ben Murdoch8b112d22011-06-08 16:22:53 +01001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
Ben Murdoch8b112d22011-06-08 16:22:53 +01001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
Ben Murdoch8b112d22011-06-08 16:22:53 +01001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001888 ASSERT(args.length() == 2);
1889
Ben Murdochb0fe1622011-05-05 13:52:32 +01001890 CONVERT_CHECKED(Code, code, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
Steve Blocka7e24c12009-10-30 11:49:00 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001896 return Smi::FromInt(code->SourcePosition(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001897}
1898
1899
Ben Murdoch8b112d22011-06-08 16:22:53 +01001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001907 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001908}
1909
1910
Ben Murdoch8b112d22011-06-08 16:22:53 +01001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
Ben Murdoch8b112d22011-06-08 16:22:53 +01001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 NoHandleAllocation ha;
1924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01001927 ASSERT(fun->should_have_prototype());
John Reck59135872010-11-02 12:39:01 -07001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001933 return args[0]; // return TOS
1934}
1935
1936
Ben Murdoch8b112d22011-06-08 16:22:53 +01001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001944}
1945
Steve Block44f0eee2011-05-26 01:26:41 +01001946
Ben Murdoch8b112d22011-06-08 16:22:53 +01001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001954}
1955
1956
Ben Murdoch8b112d22011-06-08 16:22:53 +01001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001958 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001959 ASSERT(args.length() == 2);
1960
1961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
1962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Leon Clarke4515c472010-02-03 11:58:03 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
Leon Clarke4515c472010-02-03 11:58:03 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 return Failure::Exception();
1973 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
Iain Merrick75681382010-08-19 15:07:18 +01001980 target->shared()->set_code(shared->code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001981 target->ReplaceCode(shared->code());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001982 target->shared()->set_scope_info(shared->scope_info());
Leon Clarke4515c472010-02-03 11:58:03 +00001983 target->shared()->set_length(shared->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001984 target->shared()->set_formal_parameter_count(
Leon Clarke4515c472010-02-03 11:58:03 +00001985 shared->formal_parameter_count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
Steve Block44f0eee2011-05-26 01:26:41 +01001990 target->shared()->set_script(isolate->heap()->undefined_value());
Ben Murdochb8e0da22011-05-16 14:20:40 +01001991 target->shared()->code()->set_optimizable(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
1995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
1999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
Steve Block44f0eee2011-05-26 01:26:41 +01002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00002002 if (number_of_literals > 0) {
2003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
2006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
2008 }
Leon Clarke4515c472010-02-03 11:58:03 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
Steve Blocka7e24c12009-10-30 11:49:00 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
Steve Block44f0eee2011-05-26 01:26:41 +01002012 target->set_next_function_link(isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
Ben Murdoch8b112d22011-06-08 16:22:53 +01002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01002021 HandleScope scope(isolate);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
Steve Block44f0eee2011-05-26 01:26:41 +01002027 return isolate->heap()->undefined_value();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002028}
2029
2030
Steve Block44f0eee2011-05-26 01:26:41 +01002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
Leon Clarkee46be812010-01-19 14:06:41 +00002033 uint32_t code;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002034 if (char_code->ToArrayIndex(&code)) {
Leon Clarkee46be812010-01-19 14:06:41 +00002035 if (code <= 0xffff) {
Steve Block44f0eee2011-05-26 01:26:41 +01002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
Leon Clarkee46be812010-01-19 14:06:41 +00002037 }
2038 }
Steve Block44f0eee2011-05-26 01:26:41 +01002039 return isolate->heap()->empty_string();
Leon Clarkee46be812010-01-19 14:06:41 +00002040}
2041
2042
Ben Murdoch8b112d22011-06-08 16:22:53 +01002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002049 RUNTIME_ASSERT(index->IsNumber());
Steve Blocka7e24c12009-10-30 11:49:00 +00002050
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
Steve Block44f0eee2011-05-26 01:26:41 +01002054 if (value < 0) return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
Leon Clarkee46be812010-01-19 14:06:41 +00002060 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
John Reck59135872010-11-02 12:39:01 -07002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
Steve Block44f0eee2011-05-26 01:26:41 +01002072 return isolate->heap()->nan_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
Leon Clarkee46be812010-01-19 14:06:41 +00002076}
2077
2078
Ben Murdoch8b112d22011-06-08 16:22:53 +01002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01002082 return CharFromCode(isolate, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00002083}
2084
Steve Block6ded16b2010-05-10 14:33:55 +01002085
2086class FixedArrayBuilder {
2087 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
Steve Block6ded16b2010-05-10 14:33:55 +01002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
Steve Block44f0eee2011-05-26 01:26:41 +01002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
Steve Block6ded16b2010-05-10 14:33:55 +01002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
Steve Block6ded16b2010-05-10 14:33:55 +01002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
Steve Blocka7e24c12009-10-30 11:49:00 +00002167// Forward declarations.
Steve Block6ded16b2010-05-10 14:33:55 +01002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
Steve Blocka7e24c12009-10-30 11:49:00 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
Steve Block6ded16b2010-05-10 14:33:55 +01002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
Steve Blocka7e24c12009-10-30 11:49:00 +00002184
2185class ReplacementStringBuilder {
2186 public:
Steve Block44f0eee2011-05-26 01:26:41 +01002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
Steve Block6ded16b2010-05-10 14:33:55 +01002192 subject_(subject),
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 character_count_(0),
2194 is_ascii_(subject->IsAsciiRepresentation()) {
2195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
Steve Block6ded16b2010-05-10 14:33:55 +01002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
Steve Block6ded16b2010-05-10 14:33:55 +01002210 builder->Add(Smi::FromInt(encoded_slice));
Steve Blocka7e24c12009-10-30 11:49:00 +00002211 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00002212 // Otherwise encode as two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00002215 }
Steve Block6ded16b2010-05-10 14:33:55 +01002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
2226 IncrementCharacterCount(to - from);
Steve Blocka7e24c12009-10-30 11:49:00 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
2234 if (!string->IsAsciiRepresentation()) {
2235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
Steve Block6ded16b2010-05-10 14:33:55 +01002242 if (array_builder_.length() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01002243 return heap_->isolate()->factory()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002254 *array_builder_.array(),
2255 array_builder_.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002264 *array_builder_.array(),
2265 array_builder_.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
Leon Clarkee46be812010-01-19 14:06:41 +00002272 if (character_count_ > String::kMaxLength - by) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
Steve Block6ded16b2010-05-10 14:33:55 +01002278 Handle<JSArray> GetParts() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002279 return array_builder_.ToJSArray();
Steve Block6ded16b2010-05-10 14:33:55 +01002280 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002281
Steve Block6ded16b2010-05-10 14:33:55 +01002282 private:
Steve Blocka7e24c12009-10-30 11:49:00 +00002283 Handle<String> NewRawAsciiString(int size) {
Steve Block44f0eee2011-05-26 01:26:41 +01002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
Steve Blocka7e24c12009-10-30 11:49:00 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
Steve Block44f0eee2011-05-26 01:26:41 +01002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
Steve Blocka7e24c12009-10-30 11:49:00 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
Steve Block6ded16b2010-05-10 14:33:55 +01002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
Steve Blocka7e24c12009-10-30 11:49:00 +00002299 }
2300
Steve Block44f0eee2011-05-26 01:26:41 +01002301 Heap* heap_;
Steve Block6ded16b2010-05-10 14:33:55 +01002302 FixedArrayBuilder array_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002303 Handle<String> subject_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
2466 ASSERT(capture_ref <= capture_count);
2467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
2497 if (replacement->IsAsciiRepresentation()) {
2498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
2504 ASSERT(replacement->IsTwoByteRepresentation());
2505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
Steve Block44f0eee2011-05-26 01:26:41 +01002512 Isolate* isolate = replacement->GetIsolate();
Steve Blockd0582a62009-12-15 09:54:21 +00002513 // Find substrings of replacement string and create them as String objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
Steve Block44f0eee2011-05-26 01:26:41 +01002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
Steve Blocka7e24c12009-10-30 11:49:00 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
2553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
John Reck59135872010-11-02 12:39:01 -07002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
Steve Block44f0eee2011-05-26 01:26:41 +01002574 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
Steve Block44f0eee2011-05-26 01:26:41 +01002582 HandleScope handles(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
2603 CompilationZoneScope zone(DELETE_ON_EXIT);
2604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
Steve Block44f0eee2011-05-26 01:26:41 +01002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
Steve Blocka7e24c12009-10-30 11:49:00 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
Steve Blockd0582a62009-12-15 09:54:21 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
Steve Block44f0eee2011-05-26 01:26:41 +01002634 HandleScope loop_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
2638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
2640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
Leon Clarkeac952652010-07-15 11:15:24 +01002684template <typename ResultSeqString>
John Reck59135872010-11-02 12:39:01 -07002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
Steve Block44f0eee2011-05-26 01:26:41 +01002686 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
Leon Clarkeac952652010-07-15 11:15:24 +01002690 ASSERT(subject->IsFlat());
2691
Steve Block44f0eee2011-05-26 01:26:41 +01002692 HandleScope handles(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
Leon Clarkeac952652010-07-15 11:15:24 +01002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
Steve Block053d10c2011-06-13 19:13:29 +01002716 int length = subject_handle->length();
Leon Clarkeac952652010-07-15 11:15:24 +01002717 int new_length = length - (end - start);
2718 if (new_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01002719 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
Steve Block44f0eee2011-05-26 01:26:41 +01002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01002725 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
Leon Clarkeac952652010-07-15 11:15:24 +01002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
Steve Block44f0eee2011-05-26 01:26:41 +01002775 HandleScope loop_scope(isolate);
Leon Clarkeac952652010-07-15 11:15:24 +01002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01002795 return isolate->heap()->empty_string();
Leon Clarkeac952652010-07-15 11:15:24 +01002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
Steve Block44f0eee2011-05-26 01:26:41 +01002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
Leon Clarkeac952652010-07-15 11:15:24 +01002808
2809 return *answer;
2810}
2811
2812
Ben Murdoch8b112d22011-06-08 16:22:53 +01002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
Leon Clarkeac952652010-07-15 11:15:24 +01002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
Steve Block44f0eee2011-05-26 01:26:41 +01002846 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
Steve Block44f0eee2011-05-26 01:26:41 +01002849 isolate, subject, regexp, last_match_info);
Leon Clarkeac952652010-07-15 11:15:24 +01002850 }
2851 }
2852
Steve Block44f0eee2011-05-26 01:26:41 +01002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
Steve Blocka7e24c12009-10-30 11:49:00 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
Steve Blocka7e24c12009-10-30 11:49:00 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
Ben Murdochb0fe1622011-05-05 13:52:32 +01002863// and should check that pat->length() + start_index <= sub->length().
Steve Block44f0eee2011-05-26 01:26:41 +01002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
Steve Blocka7e24c12009-10-30 11:49:00 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
2869 ASSERT(start_index <= sub->length());
2870
2871 int pattern_length = pat->length();
2872 if (pattern_length == 0) return start_index;
2873
2874 int subject_length = sub->length();
2875 if (start_index + pattern_length > subject_length) return -1;
2876
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +00002879
2880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
Steve Block8defd9f2010-07-08 12:39:36 +01002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
Steve Block8defd9f2010-07-08 12:39:36 +01002884 String* seq_pat = *pat;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
Steve Block8defd9f2010-07-08 12:39:36 +01002886
Steve Blocka7e24c12009-10-30 11:49:00 +00002887 // dispatch on type of strings
Steve Block8defd9f2010-07-08 12:39:36 +01002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002895 }
Steve Block44f0eee2011-05-26 01:26:41 +01002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002900 }
Steve Block8defd9f2010-07-08 12:39:36 +01002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002907 }
Steve Block44f0eee2011-05-26 01:26:41 +01002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002912}
2913
2914
Ben Murdoch8b112d22011-06-08 16:22:53 +01002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01002916 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00002917 ASSERT(args.length() == 3);
2918
2919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
2922 Object* index = args[2];
2923 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002925
2926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
Steve Block44f0eee2011-05-26 01:26:41 +01002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002929 return Smi::FromInt(position);
2930}
2931
2932
Andrei Popescu402d9372010-02-26 13:31:12 +00002933template <typename schar, typename pchar>
Steve Block59151502010-09-22 15:07:15 +01002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
Andrei Popescu402d9372010-02-26 13:31:12 +00002936 int idx) {
Steve Block59151502010-09-22 15:07:15 +01002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
Andrei Popescu402d9372010-02-26 13:31:12 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
Steve Block59151502010-09-22 15:07:15 +01002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
Andrei Popescu402d9372010-02-26 13:31:12 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
Steve Block59151502010-09-22 15:07:15 +01002950 pchar pattern_first_char = pattern[0];
Andrei Popescu402d9372010-02-26 13:31:12 +00002951 for (int i = idx; i >= 0; i--) {
Steve Block59151502010-09-22 15:07:15 +01002952 if (subject[i] != pattern_first_char) continue;
Andrei Popescu402d9372010-02-26 13:31:12 +00002953 int j = 1;
Steve Block59151502010-09-22 15:07:15 +01002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002956 break;
2957 }
2958 j++;
2959 }
Steve Block59151502010-09-22 15:07:15 +01002960 if (j == pattern_length) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
Ben Murdoch8b112d22011-06-08 16:22:53 +01002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
Steve Block44f0eee2011-05-26 01:26:41 +01002968 HandleScope scope(isolate); // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00002969 ASSERT(args.length() == 3);
2970
Andrei Popescu402d9372010-02-26 13:31:12 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
Steve Blocka7e24c12009-10-30 11:49:00 +00002974 Object* index = args[2];
Steve Blocka7e24c12009-10-30 11:49:00 +00002975 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002977
Andrei Popescu402d9372010-02-26 13:31:12 +00002978 uint32_t pat_length = pat->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00002979 uint32_t sub_length = sub->length();
2980
Andrei Popescu402d9372010-02-26 13:31:12 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00002983 }
2984
Andrei Popescu402d9372010-02-26 13:31:12 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
Andrei Popescu402d9372010-02-26 13:31:12 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +00003021}
3022
3023
Ben Murdoch8b112d22011-06-08 16:22:53 +01003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
3032 int str1_length = str1->length();
3033 int str2_length = str2->length();
3034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
3048 int d = str1->Get(0) - str2->Get(0);
3049 if (d != 0) return Smi::FromInt(d);
3050
Steve Block6ded16b2010-05-10 14:33:55 +01003051 str1->TryFlatten();
3052 str2->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003053
Steve Block44f0eee2011-05-26 01:26:41 +01003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
Steve Blocka7e24c12009-10-30 11:49:00 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
Ben Murdoch8b112d22011-06-08 16:22:53 +01003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
Steve Blockd0582a62009-12-15 09:54:21 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
3093 RUNTIME_ASSERT(end <= value->length());
Steve Block44f0eee2011-05-26 01:26:41 +01003094 isolate->counters()->sub_string_runtime()->Increment();
Steve Blockd0582a62009-12-15 09:54:21 +00003095 return value->SubString(start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +00003096}
3097
3098
Ben Murdoch8b112d22011-06-08 16:22:53 +01003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003113 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003114 }
3115 int length = subject->length();
3116
3117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
3118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
3124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
3125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
Steve Block44f0eee2011-05-26 01:26:41 +01003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
Steve Blocka7e24c12009-10-30 11:49:00 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
Steve Block44f0eee2011-05-26 01:26:41 +01003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003143 elements->set(i, *match);
Steve Blocka7e24c12009-10-30 11:49:00 +00003144 }
Steve Block44f0eee2011-05-26 01:26:41 +01003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
Steve Block6ded16b2010-05-10 14:33:55 +01003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
Ben Murdochf87a2032010-10-22 12:50:53 +01003171template <typename SubjectChar, typename PatternChar>
Steve Block44f0eee2011-05-26 01:26:41 +01003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
Ben Murdochf87a2032010-10-22 12:50:53 +01003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
Steve Block6ded16b2010-05-10 14:33:55 +01003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
Ben Murdochf87a2032010-10-22 12:50:53 +01003180 int pattern_length = pattern.length();
Steve Block6ded16b2010-05-10 14:33:55 +01003181 int max_search_start = subject_length - pattern_length;
Steve Block44f0eee2011-05-26 01:26:41 +01003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
Ben Murdochf87a2032010-10-22 12:50:53 +01003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
Steve Block6ded16b2010-05-10 14:33:55 +01003197 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01003201 break;
Ben Murdochf87a2032010-10-22 12:50:53 +01003202 }
Steve Block6ded16b2010-05-10 14:33:55 +01003203 }
Ben Murdochf87a2032010-10-22 12:50:53 +01003204
Steve Block6ded16b2010-05-10 14:33:55 +01003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
Steve Block44f0eee2011-05-26 01:26:41 +01003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
Steve Block6ded16b2010-05-10 14:33:55 +01003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
Steve Block6ded16b2010-05-10 14:33:55 +01003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01003234 pattern->ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003235 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003236 builder,
3237 &match_pos)) break;
3238 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01003241 pattern->ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003242 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01003251 pattern->ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003252 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003253 builder,
3254 &match_pos)) break;
3255 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01003258 pattern->ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01003259 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003278 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
Steve Block44f0eee2011-05-26 01:26:41 +01003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
Steve Block6ded16b2010-05-10 14:33:55 +01003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
Steve Block44f0eee2011-05-26 01:26:41 +01003345 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
Steve Block44f0eee2011-05-26 01:26:41 +01003389 HandleScope temp_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
Steve Block44f0eee2011-05-26 01:26:41 +01003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003397 elements->set(0, *match);
Steve Block6ded16b2010-05-10 14:33:55 +01003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
Steve Block44f0eee2011-05-26 01:26:41 +01003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
Steve Block6ded16b2010-05-10 14:33:55 +01003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
Steve Block44f0eee2011-05-26 01:26:41 +01003409 elements->set(i, isolate->heap()->undefined_value());
Steve Block6ded16b2010-05-10 14:33:55 +01003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
Steve Block44f0eee2011-05-26 01:26:41 +01003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
Steve Block6ded16b2010-05-10 14:33:55 +01003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
Steve Block791712a2010-08-27 10:21:07 +01003418 Vector<int32_t> tmp = prev_register_vector;
Steve Block6ded16b2010-05-10 14:33:55 +01003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
Ben Murdoch8b112d22011-06-08 16:22:53 +01003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
Steve Block6ded16b2010-05-10 14:33:55 +01003466 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01003467 HandleScope handles(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
Steve Block6ded16b2010-05-10 14:33:55 +01003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003489 ASSERT(pattern->IsFlat());
Steve Block44f0eee2011-05-26 01:26:41 +01003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
Steve Block6ded16b2010-05-10 14:33:55 +01003492 return *builder.ToJSArray(result_array);
3493 }
Steve Block44f0eee2011-05-26 01:26:41 +01003494 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
Steve Block6ded16b2010-05-10 14:33:55 +01003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
Steve Block6ded16b2010-05-10 14:33:55 +01003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
Steve Block44f0eee2011-05-26 01:26:41 +01003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
Ben Murdoch8b112d22011-06-08 16:22:53 +01003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
3524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
Steve Block44f0eee2011-05-26 01:26:41 +01003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
Steve Blocka7e24c12009-10-30 11:49:00 +00003534 }
3535 }
3536
3537 // Slow case.
3538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003545 }
Steve Block44f0eee2011-05-26 01:26:41 +01003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
Ben Murdoch8b112d22011-06-08 16:22:53 +01003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003570 }
Steve Block44f0eee2011-05-26 01:26:41 +01003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003579 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01003580 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00003581}
3582
3583
Ben Murdoch8b112d22011-06-08 16:22:53 +01003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003595 }
Steve Block44f0eee2011-05-26 01:26:41 +01003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003604 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01003605 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00003606}
3607
3608
Ben Murdoch8b112d22011-06-08 16:22:53 +01003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003620 }
Steve Block44f0eee2011-05-26 01:26:41 +01003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
Steve Blocka7e24c12009-10-30 11:49:00 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
Steve Block44f0eee2011-05-26 01:26:41 +01003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003629 DeleteArray(str);
Steve Block44f0eee2011-05-26 01:26:41 +01003630 return res;
Steve Blocka7e24c12009-10-30 11:49:00 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
3636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
3637 if (index < static_cast<uint32_t>(string->length())) {
Steve Block6ded16b2010-05-10 14:33:55 +01003638 string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003639 return LookupSingleCharacterStringFromCode(
3640 string->Get(index));
3641 }
3642 return Execution::CharAt(string, index);
3643}
3644
3645
Steve Block44f0eee2011-05-26 01:26:41 +01003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07003648 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
3651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
3653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
3657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
3661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
3664 Handle<Object> prototype = GetPrototype(object);
3665 return prototype->GetElement(index);
3666 }
3667
Steve Block6ded16b2010-05-10 14:33:55 +01003668 return GetElement(object, index);
3669}
3670
3671
John Reck59135872010-11-02 12:39:01 -07003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003673 return object->GetElement(index);
3674}
3675
3676
Steve Block44f0eee2011-05-26 01:26:41 +01003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07003679 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01003680 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003681
3682 if (object->IsUndefined() || object->IsNull()) {
3683 Handle<Object> args[2] = { key, object };
3684 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003692 if (key->ToArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003693 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
3697 Handle<String> name;
3698 if (key->IsString()) {
3699 name = Handle<String>::cast(key);
3700 } else {
3701 bool has_pending_exception = false;
3702 Handle<Object> converted =
3703 Execution::ToString(key, &has_pending_exception);
3704 if (has_pending_exception) return Failure::Exception();
3705 name = Handle<String>::cast(converted);
3706 }
3707
3708 // Check if the name is trivially convertible to an index and get
3709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003711 return GetElementOrCharAt(isolate, object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003712 } else {
3713 PropertyAttributes attr;
3714 return object->GetProperty(*name, &attr);
3715 }
3716}
3717
3718
Ben Murdoch8b112d22011-06-08 16:22:53 +01003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
3724 Handle<Object> key = args.at<Object>(1);
3725
Steve Block44f0eee2011-05-26 01:26:41 +01003726 return Runtime::GetObjectProperty(isolate, object, key);
Steve Blocka7e24c12009-10-30 11:49:00 +00003727}
3728
3729
Steve Blocka7e24c12009-10-30 11:49:00 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
3735 // Fast cases for getting named properties of the receiver JSObject
3736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
3739 // the global proxy object can return a valid result even though the
3740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
3746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
3748 !args[0]->IsAccessCheckNeeded() &&
3749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
3754 Map* receiver_map = receiver->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
Steve Blocka7e24c12009-10-30 11:49:00 +00003757 if (offset != -1) {
3758 Object* value = receiver->FastPropertyAt(offset);
Steve Block44f0eee2011-05-26 01:26:41 +01003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003760 }
3761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
3762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00003764 if (result.IsProperty() && result.type() == FIELD) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003765 int offset = result.GetFieldIndex();
Steve Block44f0eee2011-05-26 01:26:41 +01003766 keyed_lookup_cache->Update(receiver_map, key, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00003767 return receiver->FastPropertyAt(offset);
3768 }
3769 } else {
3770 // Attempt dictionary lookup.
3771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
3774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
3775 Object* value = dictionary->ValueAt(entry);
3776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
3780 }
3781 }
Leon Clarkee46be812010-01-19 14:06:41 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
Steve Block44f0eee2011-05-26 01:26:41 +01003784 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
Steve Block1e0659c2011-05-24 12:43:12 +01003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003791 }
3792
3793 // Fall back to GetObjectProperty.
Steve Block44f0eee2011-05-26 01:26:41 +01003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00003796 args.at<Object>(1));
3797}
3798
Steve Block1e0659c2011-05-24 12:43:12 +01003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00003806 ASSERT(args.length() == 5);
Steve Block44f0eee2011-05-26 01:26:41 +01003807 HandleScope scope(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Andrei Popescu31002712010-02-23 13:46:05 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
Andrei Popescu402d9372010-02-26 13:31:12 +00003824 if (result.IsProperty() &&
Andrei Popescu31002712010-02-23 13:46:05 +00003825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
John Reck59135872010-11-02 12:39:01 -07003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
Andrei Popescu31002712010-02-23 13:46:05 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
Steve Block1e0659c2011-05-24 12:43:12 +01003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
Andrei Popescu31002712010-02-23 13:46:05 +00003843 ASSERT(args.length() == 4);
Steve Block44f0eee2011-05-26 01:26:41 +01003844 HandleScope scope(isolate);
Andrei Popescu31002712010-02-23 13:46:05 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
Steve Block1e0659c2011-05-24 12:43:12 +01003865 if (js_object->IsJSGlobalProxy()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
Steve Block1e0659c2011-05-24 12:43:12 +01003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
3873 }
John Reck59135872010-11-02 12:39:01 -07003874 NormalizeElements(js_object);
3875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
John Reck59135872010-11-02 12:39:01 -07003879 NumberDictionarySet(dictionary, index, obj_value, details);
Steve Block1e0659c2011-05-24 12:43:12 +01003880 return *obj_value;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003881 }
3882
Andrei Popescu31002712010-02-23 13:46:05 +00003883 LookupResult result;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003884 js_object->LookupRealNamedProperty(*name, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00003885
Steve Block44f0eee2011-05-26 01:26:41 +01003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
3891 return isolate->heap()->undefined_value();
3892 }
3893
Andrei Popescu31002712010-02-23 13:46:05 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
Andrei Popescu31002712010-02-23 13:46:05 +00003902 // New attributes - normalize to avoid writing to instance descriptor
Steve Block1e0659c2011-05-24 12:43:12 +01003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
3907 }
John Reck59135872010-11-02 12:39:01 -07003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
Ben Murdoch086aeea2011-05-13 15:57:08 +01003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00003914 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003915
Steve Block44f0eee2011-05-26 01:26:41 +01003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00003921}
3922
3923
Steve Block44f0eee2011-05-26 01:26:41 +01003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
John Reck59135872010-11-02 12:39:01 -07003926 Handle<Object> key,
3927 Handle<Object> value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003928 PropertyAttributes attr,
3929 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003930 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003931
3932 if (object->IsUndefined() || object->IsNull()) {
3933 Handle<Object> args[2] = { key, object };
3934 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
3943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
3945 // Check if the given key is an array index.
3946 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003947 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
3955 if (js_object->IsStringObjectWithCharacterAt(index)) {
3956 return *value;
3957 }
3958
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003960 if (result.is_null()) return Failure::Exception();
3961 return *value;
3962 }
3963
3964 if (key->IsString()) {
3965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003967 result = SetElement(js_object, index, value, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003968 } else {
3969 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01003970 key_string->TryFlatten();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003972 }
3973 if (result.is_null()) return Failure::Exception();
3974 return *value;
3975 }
3976
3977 // Call-back into JavaScript to convert the key to a string.
3978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003984 return js_object->SetElement(index, *value, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003985 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003987 }
3988}
3989
3990
Steve Block44f0eee2011-05-26 01:26:41 +01003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
John Reck59135872010-11-02 12:39:01 -07003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
Steve Block44f0eee2011-05-26 01:26:41 +01003996 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004000 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004012 return js_object->SetElement(index, *value, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004017 return js_object->SetElement(index, *value, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01004020 key_string->TryFlatten();
Ben Murdoch086aeea2011-05-13 15:57:08 +01004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004034 return js_object->SetElement(index, *value, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004035 } else {
Ben Murdoch086aeea2011-05-13 15:57:08 +01004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00004037 }
4038}
4039
4040
Steve Block44f0eee2011-05-26 01:26:41 +01004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
John Reck59135872010-11-02 12:39:01 -07004043 Handle<Object> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004044 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004048 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004056 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
Steve Block6ded16b2010-05-10 14:33:55 +01004073 key_string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
Ben Murdoch8b112d22011-06-08 16:22:53 +01004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004079 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
Steve Blocka7e24c12009-10-30 11:49:00 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004088 // Compute attributes.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
4092 StrictModeFlag strict_mode = kNonStrictMode;
4093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
4097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
Steve Blocka7e24c12009-10-30 11:49:00 +00004098 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004099
Steve Block44f0eee2011-05-26 01:26:41 +01004100 return Runtime::SetObjectProperty(isolate,
4101 object,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004112 NoHandleAllocation ha;
4113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
4114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
4116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
4126
4127 return object->
Ben Murdoch086aeea2011-05-13 15:57:08 +01004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004129}
4130
4131
Ben Murdoch8b112d22011-06-08 16:22:53 +01004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004133 NoHandleAllocation ha;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004134 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004138 CONVERT_SMI_CHECKED(strict, args[2]);
4139 return object->DeleteProperty(key, (strict == kStrictMode)
4140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
Steve Blocka7e24c12009-10-30 11:49:00 +00004142}
4143
4144
Steve Block44f0eee2011-05-26 01:26:41 +01004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
Steve Blocka7e24c12009-10-30 11:49:00 +00004147 Handle<String> key) {
Steve Block44f0eee2011-05-26 01:26:41 +01004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004158 }
Steve Block44f0eee2011-05-26 01:26:41 +01004159 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004160}
4161
4162
Ben Murdoch8b112d22011-06-08 16:22:53 +01004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
4168 Object* obj = args[0];
4169 // Only JS objects can have properties.
4170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
Steve Block44f0eee2011-05-26 01:26:41 +01004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
Steve Block44f0eee2011-05-26 01:26:41 +01004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
Steve Blocka7e24c12009-10-30 11:49:00 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
4181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
4184 String* string = String::cast(obj);
4185 if (index < static_cast<uint32_t>(string->length()))
Steve Block44f0eee2011-05-26 01:26:41 +01004186 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004187 }
4188 }
Steve Block44f0eee2011-05-26 01:26:41 +01004189 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004190}
4191
4192
Ben Murdoch8b112d22011-06-08 16:22:53 +01004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004202 }
Steve Block44f0eee2011-05-26 01:26:41 +01004203 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004204}
4205
4206
Ben Murdoch8b112d22011-06-08 16:22:53 +01004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
Steve Block44f0eee2011-05-26 01:26:41 +01004216 if (object->HasElement(index)) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004217 }
Steve Block44f0eee2011-05-26 01:26:41 +01004218 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004219}
4220
4221
Ben Murdoch8b112d22011-06-08 16:22:53 +01004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004231 return isolate->heap()->ToBoolean(object->HasElement(index));
Steve Blocka7e24c12009-10-30 11:49:00 +00004232 }
4233
4234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
Steve Block44f0eee2011-05-26 01:26:41 +01004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004236}
4237
4238
Ben Murdoch8b112d22011-06-08 16:22:53 +01004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004240 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004241 ASSERT(args.length() == 1);
4242 CONVERT_ARG_CHECKED(JSObject, object, 0);
4243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
Steve Block44f0eee2011-05-26 01:26:41 +01004259 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004260 Handle<JSObject> object(raw_object);
4261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
4263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
Leon Clarkee46be812010-01-19 14:06:41 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004289 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004292 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
Leon Clarke4515c472010-02-03 11:58:03 +00004299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00004306 }
Leon Clarkee46be812010-01-19 14:06:41 +00004307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
Steve Block6ded16b2010-05-10 14:33:55 +01004314 ScopedVector<int> local_property_count(length);
Leon Clarkee46be812010-01-19 14:06:41 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00004318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
Leon Clarke4515c472010-02-03 11:58:03 +00004325 }
Leon Clarkee46be812010-01-19 14:06:41 +00004326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
Steve Block44f0eee2011-05-26 01:26:41 +01004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
Leon Clarkee46be812010-01-19 14:06:41 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
Ben Murdoch6d7cb002011-08-04 19:25:22 +01004342 int next_copy_index = 0;
Leon Clarkee46be812010-01-19 14:06:41 +00004343 for (int i = 0; i < length; i++) {
Ben Murdoch6d7cb002011-08-04 19:25:22 +01004344 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4345 next_copy_index += local_property_count[i];
Leon Clarkee46be812010-01-19 14:06:41 +00004346 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4347 proto_with_hidden_properties++;
4348 }
4349 if (i < length - 1) {
4350 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4351 }
4352 }
4353
4354 // Filter out name of hidden propeties object.
4355 if (proto_with_hidden_properties > 0) {
4356 Handle<FixedArray> old_names = names;
Steve Block44f0eee2011-05-26 01:26:41 +01004357 names = isolate->factory()->NewFixedArray(
Leon Clarkee46be812010-01-19 14:06:41 +00004358 names->length() - proto_with_hidden_properties);
4359 int dest_pos = 0;
4360 for (int i = 0; i < total_property_count; i++) {
4361 Object* name = old_names->get(i);
Steve Block44f0eee2011-05-26 01:26:41 +01004362 if (name == isolate->heap()->hidden_symbol()) {
Leon Clarkee46be812010-01-19 14:06:41 +00004363 continue;
4364 }
4365 names->set(dest_pos++, name);
4366 }
4367 }
4368
Steve Block44f0eee2011-05-26 01:26:41 +01004369 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00004370}
4371
4372
4373// Return the names of the local indexed properties.
4374// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004375RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004376 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004377 ASSERT(args.length() == 1);
4378 if (!args[0]->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004379 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004380 }
4381 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4382
4383 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01004384 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
Leon Clarkee46be812010-01-19 14:06:41 +00004385 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
Steve Block44f0eee2011-05-26 01:26:41 +01004386 return *isolate->factory()->NewJSArrayWithElements(names);
Leon Clarkee46be812010-01-19 14:06:41 +00004387}
4388
4389
4390// Return information on whether an object has a named or indexed interceptor.
4391// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004392RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
Steve Block44f0eee2011-05-26 01:26:41 +01004393 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004394 ASSERT(args.length() == 1);
4395 if (!args[0]->IsJSObject()) {
4396 return Smi::FromInt(0);
4397 }
4398 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4399
4400 int result = 0;
4401 if (obj->HasNamedInterceptor()) result |= 2;
4402 if (obj->HasIndexedInterceptor()) result |= 1;
4403
4404 return Smi::FromInt(result);
4405}
4406
4407
4408// Return property names from named interceptor.
4409// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004410RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004411 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004412 ASSERT(args.length() == 1);
4413 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4414
4415 if (obj->HasNamedInterceptor()) {
4416 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4417 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4418 }
Steve Block44f0eee2011-05-26 01:26:41 +01004419 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004420}
4421
4422
4423// Return element names from indexed interceptor.
4424// args[0]: object
Ben Murdoch8b112d22011-06-08 16:22:53 +01004425RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
Steve Block44f0eee2011-05-26 01:26:41 +01004426 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00004427 ASSERT(args.length() == 1);
4428 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4429
4430 if (obj->HasIndexedInterceptor()) {
4431 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4432 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4433 }
Steve Block44f0eee2011-05-26 01:26:41 +01004434 return isolate->heap()->undefined_value();
Leon Clarkee46be812010-01-19 14:06:41 +00004435}
4436
4437
Ben Murdoch8b112d22011-06-08 16:22:53 +01004438RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004439 ASSERT_EQ(args.length(), 1);
4440 CONVERT_CHECKED(JSObject, raw_object, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01004441 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004442 Handle<JSObject> object(raw_object);
Steve Block1e0659c2011-05-24 12:43:12 +01004443
4444 if (object->IsJSGlobalProxy()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004445 // Do access checks before going to the global object.
4446 if (object->IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004447 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004448 v8::ACCESS_KEYS)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004449 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4450 return *isolate->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004451 }
4452
Steve Block1e0659c2011-05-24 12:43:12 +01004453 Handle<Object> proto(object->GetPrototype());
4454 // If proxy is detached we simply return an empty array.
Steve Block44f0eee2011-05-26 01:26:41 +01004455 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
Steve Block1e0659c2011-05-24 12:43:12 +01004456 object = Handle<JSObject>::cast(proto);
4457 }
4458
Steve Blocka7e24c12009-10-30 11:49:00 +00004459 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4460 LOCAL_ONLY);
4461 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4462 // property array and since the result is mutable we have to create
4463 // a fresh clone on each invocation.
4464 int length = contents->length();
Steve Block44f0eee2011-05-26 01:26:41 +01004465 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00004466 for (int i = 0; i < length; i++) {
4467 Object* entry = contents->get(i);
4468 if (entry->IsString()) {
4469 copy->set(i, entry);
4470 } else {
4471 ASSERT(entry->IsNumber());
Steve Block44f0eee2011-05-26 01:26:41 +01004472 HandleScope scope(isolate);
4473 Handle<Object> entry_handle(entry, isolate);
4474 Handle<Object> entry_str =
4475 isolate->factory()->NumberToString(entry_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +00004476 copy->set(i, *entry_str);
4477 }
4478 }
Steve Block44f0eee2011-05-26 01:26:41 +01004479 return *isolate->factory()->NewJSArrayWithElements(copy);
Steve Blocka7e24c12009-10-30 11:49:00 +00004480}
4481
4482
Ben Murdoch8b112d22011-06-08 16:22:53 +01004483RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004484 NoHandleAllocation ha;
4485 ASSERT(args.length() == 1);
4486
4487 // Compute the frame holding the arguments.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004488 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004489 it.AdvanceToArgumentsFrame();
4490 JavaScriptFrame* frame = it.frame();
4491
4492 // Get the actual number of provided arguments.
Steve Block44f0eee2011-05-26 01:26:41 +01004493 const uint32_t n = frame->ComputeParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00004494
4495 // Try to convert the key to an index. If successful and within
4496 // index return the the argument from the frame.
4497 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004498 if (args[0]->ToArrayIndex(&index) && index < n) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004499 return frame->GetParameter(index);
4500 }
4501
4502 // Convert the key to a string.
Steve Block44f0eee2011-05-26 01:26:41 +01004503 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004504 bool exception = false;
4505 Handle<Object> converted =
4506 Execution::ToString(args.at<Object>(0), &exception);
4507 if (exception) return Failure::Exception();
4508 Handle<String> key = Handle<String>::cast(converted);
4509
4510 // Try to convert the string key into an array index.
4511 if (key->AsArrayIndex(&index)) {
4512 if (index < n) {
4513 return frame->GetParameter(index);
4514 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004515 return isolate->initial_object_prototype()->GetElement(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004516 }
4517 }
4518
4519 // Handle special arguments properties.
Steve Block44f0eee2011-05-26 01:26:41 +01004520 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4521 if (key->Equals(isolate->heap()->callee_symbol())) {
4522 Object* function = frame->function();
4523 if (function->IsJSFunction() &&
4524 JSFunction::cast(function)->shared()->strict_mode()) {
4525 return isolate->Throw(*isolate->factory()->NewTypeError(
4526 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4527 }
4528 return function;
4529 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004530
4531 // Lookup in the initial Object.prototype object.
Steve Block44f0eee2011-05-26 01:26:41 +01004532 return isolate->initial_object_prototype()->GetProperty(*key);
Steve Blocka7e24c12009-10-30 11:49:00 +00004533}
4534
4535
Ben Murdoch8b112d22011-06-08 16:22:53 +01004536RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01004537 HandleScope scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00004538
Steve Blocka7e24c12009-10-30 11:49:00 +00004539 ASSERT(args.length() == 1);
4540 Handle<Object> object = args.at<Object>(0);
4541 if (object->IsJSObject()) {
4542 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
Andrei Popescu402d9372010-02-26 13:31:12 +00004543 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07004544 MaybeObject* ok = js_object->TransformToFastProperties(0);
4545 if (ok->IsRetryAfterGC()) return ok;
Andrei Popescu402d9372010-02-26 13:31:12 +00004546 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004547 }
4548 return *object;
4549}
4550
4551
Ben Murdoch8b112d22011-06-08 16:22:53 +01004552RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
Steve Block44f0eee2011-05-26 01:26:41 +01004553 HandleScope scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00004554
Steve Blocka7e24c12009-10-30 11:49:00 +00004555 ASSERT(args.length() == 1);
4556 Handle<Object> object = args.at<Object>(0);
Steve Block1e0659c2011-05-24 12:43:12 +01004557 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004558 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
John Reck59135872010-11-02 12:39:01 -07004559 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004560 }
4561 return *object;
4562}
4563
4564
Ben Murdoch8b112d22011-06-08 16:22:53 +01004565RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004566 NoHandleAllocation ha;
4567 ASSERT(args.length() == 1);
4568
4569 return args[0]->ToBoolean();
4570}
4571
4572
4573// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4574// Possible optimizations: put the type string into the oddballs.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004575RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004576 NoHandleAllocation ha;
4577
4578 Object* obj = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01004579 if (obj->IsNumber()) return isolate->heap()->number_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004580 HeapObject* heap_obj = HeapObject::cast(obj);
4581
4582 // typeof an undetectable object is 'undefined'
Steve Block44f0eee2011-05-26 01:26:41 +01004583 if (heap_obj->map()->is_undetectable()) {
4584 return isolate->heap()->undefined_symbol();
4585 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004586
4587 InstanceType instance_type = heap_obj->map()->instance_type();
4588 if (instance_type < FIRST_NONSTRING_TYPE) {
Steve Block44f0eee2011-05-26 01:26:41 +01004589 return isolate->heap()->string_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004590 }
4591
4592 switch (instance_type) {
4593 case ODDBALL_TYPE:
4594 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004595 return isolate->heap()->boolean_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004596 }
4597 if (heap_obj->IsNull()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004598 return isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004599 }
4600 ASSERT(heap_obj->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01004601 return isolate->heap()->undefined_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004602 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01004603 return isolate->heap()->function_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004604 default:
4605 // For any kind of object not handled above, the spec rule for
4606 // host objects gives that it is okay to return "object"
Steve Block44f0eee2011-05-26 01:26:41 +01004607 return isolate->heap()->object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00004608 }
4609}
4610
4611
Steve Block6ded16b2010-05-10 14:33:55 +01004612static bool AreDigits(const char*s, int from, int to) {
4613 for (int i = from; i < to; i++) {
4614 if (s[i] < '0' || s[i] > '9') return false;
4615 }
4616
4617 return true;
4618}
4619
4620
4621static int ParseDecimalInteger(const char*s, int from, int to) {
4622 ASSERT(to - from < 10); // Overflow is not possible.
4623 ASSERT(from < to);
4624 int d = s[from] - '0';
4625
4626 for (int i = from + 1; i < to; i++) {
4627 d = 10 * d + (s[i] - '0');
4628 }
4629
4630 return d;
4631}
4632
4633
Ben Murdoch8b112d22011-06-08 16:22:53 +01004634RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004635 NoHandleAllocation ha;
4636 ASSERT(args.length() == 1);
4637 CONVERT_CHECKED(String, subject, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01004638 subject->TryFlatten();
4639
4640 // Fast case: short integer or some sorts of junk values.
4641 int len = subject->length();
4642 if (subject->IsSeqAsciiString()) {
4643 if (len == 0) return Smi::FromInt(0);
4644
4645 char const* data = SeqAsciiString::cast(subject)->GetChars();
4646 bool minus = (data[0] == '-');
4647 int start_pos = (minus ? 1 : 0);
4648
4649 if (start_pos == len) {
Steve Block44f0eee2011-05-26 01:26:41 +01004650 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004651 } else if (data[start_pos] > '9') {
4652 // Fast check for a junk value. A valid string may start from a
4653 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4654 // the 'I' character ('Infinity'). All of that have codes not greater than
4655 // '9' except 'I'.
4656 if (data[start_pos] != 'I') {
Steve Block44f0eee2011-05-26 01:26:41 +01004657 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004658 }
4659 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4660 // The maximal/minimal smi has 10 digits. If the string has less digits we
4661 // know it will fit into the smi-data type.
4662 int d = ParseDecimalInteger(data, start_pos, len);
4663 if (minus) {
Steve Block44f0eee2011-05-26 01:26:41 +01004664 if (d == 0) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004665 d = -d;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004666 } else if (!subject->HasHashCode() &&
4667 len <= String::kMaxArrayIndexSize &&
4668 (len == 1 || data[0] != '0')) {
4669 // String hash is not calculated yet but all the data are present.
4670 // Update the hash field to speed up sequential convertions.
Iain Merrick9ac36c92010-09-13 15:29:50 +01004671 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004672#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004673 subject->Hash(); // Force hash calculation.
4674 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4675 static_cast<int>(hash));
4676#endif
4677 subject->set_hash_field(hash);
Steve Block6ded16b2010-05-10 14:33:55 +01004678 }
4679 return Smi::FromInt(d);
4680 }
4681 }
4682
4683 // Slower case.
Ben Murdoch8b112d22011-06-08 16:22:53 +01004684 return isolate->heap()->NumberFromDouble(
4685 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
Steve Blocka7e24c12009-10-30 11:49:00 +00004686}
4687
4688
Ben Murdoch8b112d22011-06-08 16:22:53 +01004689RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004690 NoHandleAllocation ha;
4691 ASSERT(args.length() == 1);
4692
4693 CONVERT_CHECKED(JSArray, codes, args[0]);
4694 int length = Smi::cast(codes->length())->value();
4695
4696 // Check if the string can be ASCII.
4697 int i;
4698 for (i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07004699 Object* element;
4700 { MaybeObject* maybe_element = codes->GetElement(i);
4701 // We probably can't get an exception here, but just in order to enforce
4702 // the checking of inputs in the runtime calls we check here.
4703 if (!maybe_element->ToObject(&element)) return maybe_element;
4704 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004705 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4706 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4707 break;
4708 }
4709
John Reck59135872010-11-02 12:39:01 -07004710 MaybeObject* maybe_object = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00004711 if (i == length) { // The string is ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01004712 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00004713 } else { // The string is not ASCII.
Steve Block44f0eee2011-05-26 01:26:41 +01004714 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00004715 }
4716
John Reck59135872010-11-02 12:39:01 -07004717 Object* object = NULL;
4718 if (!maybe_object->ToObject(&object)) return maybe_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00004719 String* result = String::cast(object);
4720 for (int i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07004721 Object* element;
4722 { MaybeObject* maybe_element = codes->GetElement(i);
4723 if (!maybe_element->ToObject(&element)) return maybe_element;
4724 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004725 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4726 result->Set(i, chr & 0xffff);
4727 }
4728 return result;
4729}
4730
4731
4732// kNotEscaped is generated by the following:
4733//
4734// #!/bin/perl
4735// for (my $i = 0; $i < 256; $i++) {
4736// print "\n" if $i % 16 == 0;
4737// my $c = chr($i);
4738// my $escaped = 1;
4739// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4740// print $escaped ? "0, " : "1, ";
4741// }
4742
4743
4744static bool IsNotEscaped(uint16_t character) {
4745 // Only for 8 bit characters, the rest are always escaped (in a different way)
4746 ASSERT(character < 256);
4747 static const char kNotEscaped[256] = {
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4750 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4753 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4754 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4755 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4764 };
4765 return kNotEscaped[character] != 0;
4766}
4767
4768
Ben Murdoch8b112d22011-06-08 16:22:53 +01004769RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004770 const char hex_chars[] = "0123456789ABCDEF";
4771 NoHandleAllocation ha;
4772 ASSERT(args.length() == 1);
4773 CONVERT_CHECKED(String, source, args[0]);
4774
Steve Block6ded16b2010-05-10 14:33:55 +01004775 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004776
4777 int escaped_length = 0;
4778 int length = source->length();
4779 {
Steve Block44f0eee2011-05-26 01:26:41 +01004780 Access<StringInputBuffer> buffer(
4781 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004782 buffer->Reset(source);
4783 while (buffer->has_more()) {
4784 uint16_t character = buffer->GetNext();
4785 if (character >= 256) {
4786 escaped_length += 6;
4787 } else if (IsNotEscaped(character)) {
4788 escaped_length++;
4789 } else {
4790 escaped_length += 3;
4791 }
Steve Block3ce2e202009-11-05 08:53:23 +00004792 // We don't allow strings that are longer than a maximal length.
Leon Clarkee46be812010-01-19 14:06:41 +00004793 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
Steve Block3ce2e202009-11-05 08:53:23 +00004794 if (escaped_length > String::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +01004795 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00004796 return Failure::OutOfMemoryException();
4797 }
4798 }
4799 }
4800 // No length change implies no change. Return original string if no change.
4801 if (escaped_length == length) {
4802 return source;
4803 }
John Reck59135872010-11-02 12:39:01 -07004804 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01004805 { MaybeObject* maybe_o =
4806 isolate->heap()->AllocateRawAsciiString(escaped_length);
John Reck59135872010-11-02 12:39:01 -07004807 if (!maybe_o->ToObject(&o)) return maybe_o;
4808 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004809 String* destination = String::cast(o);
4810 int dest_position = 0;
4811
Steve Block44f0eee2011-05-26 01:26:41 +01004812 Access<StringInputBuffer> buffer(
4813 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004814 buffer->Rewind();
4815 while (buffer->has_more()) {
4816 uint16_t chr = buffer->GetNext();
4817 if (chr >= 256) {
4818 destination->Set(dest_position, '%');
4819 destination->Set(dest_position+1, 'u');
4820 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4821 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4822 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4823 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
4824 dest_position += 6;
4825 } else if (IsNotEscaped(chr)) {
4826 destination->Set(dest_position, chr);
4827 dest_position++;
4828 } else {
4829 destination->Set(dest_position, '%');
4830 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4831 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
4832 dest_position += 3;
4833 }
4834 }
4835 return destination;
4836}
4837
4838
4839static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4840 static const signed char kHexValue['g'] = {
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4844 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4845 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4847 -1, 10, 11, 12, 13, 14, 15 };
4848
4849 if (character1 > 'f') return -1;
4850 int hi = kHexValue[character1];
4851 if (hi == -1) return -1;
4852 if (character2 > 'f') return -1;
4853 int lo = kHexValue[character2];
4854 if (lo == -1) return -1;
4855 return (hi << 4) + lo;
4856}
4857
4858
4859static inline int Unescape(String* source,
4860 int i,
4861 int length,
4862 int* step) {
4863 uint16_t character = source->Get(i);
4864 int32_t hi = 0;
4865 int32_t lo = 0;
4866 if (character == '%' &&
4867 i <= length - 6 &&
4868 source->Get(i + 1) == 'u' &&
4869 (hi = TwoDigitHex(source->Get(i + 2),
4870 source->Get(i + 3))) != -1 &&
4871 (lo = TwoDigitHex(source->Get(i + 4),
4872 source->Get(i + 5))) != -1) {
4873 *step = 6;
4874 return (hi << 8) + lo;
4875 } else if (character == '%' &&
4876 i <= length - 3 &&
4877 (lo = TwoDigitHex(source->Get(i + 1),
4878 source->Get(i + 2))) != -1) {
4879 *step = 3;
4880 return lo;
4881 } else {
4882 *step = 1;
4883 return character;
4884 }
4885}
4886
4887
Ben Murdoch8b112d22011-06-08 16:22:53 +01004888RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004889 NoHandleAllocation ha;
4890 ASSERT(args.length() == 1);
4891 CONVERT_CHECKED(String, source, args[0]);
4892
Steve Block6ded16b2010-05-10 14:33:55 +01004893 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004894
4895 bool ascii = true;
4896 int length = source->length();
4897
4898 int unescaped_length = 0;
4899 for (int i = 0; i < length; unescaped_length++) {
4900 int step;
4901 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
4902 ascii = false;
4903 }
4904 i += step;
4905 }
4906
4907 // No length change implies no change. Return original string if no change.
4908 if (unescaped_length == length)
4909 return source;
4910
John Reck59135872010-11-02 12:39:01 -07004911 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01004912 { MaybeObject* maybe_o =
4913 ascii ?
4914 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4915 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
John Reck59135872010-11-02 12:39:01 -07004916 if (!maybe_o->ToObject(&o)) return maybe_o;
4917 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004918 String* destination = String::cast(o);
4919
4920 int dest_position = 0;
4921 for (int i = 0; i < length; dest_position++) {
4922 int step;
4923 destination->Set(dest_position, Unescape(source, i, length, &step));
4924 i += step;
4925 }
4926 return destination;
4927}
4928
4929
Ben Murdochb0fe1622011-05-05 13:52:32 +01004930static const unsigned int kQuoteTableLength = 128u;
4931
4932static const int kJsonQuotesCharactersPerEntry = 8;
4933static const char* const JsonQuotes =
4934 "\\u0000 \\u0001 \\u0002 \\u0003 "
4935 "\\u0004 \\u0005 \\u0006 \\u0007 "
4936 "\\b \\t \\n \\u000b "
4937 "\\f \\r \\u000e \\u000f "
4938 "\\u0010 \\u0011 \\u0012 \\u0013 "
4939 "\\u0014 \\u0015 \\u0016 \\u0017 "
4940 "\\u0018 \\u0019 \\u001a \\u001b "
4941 "\\u001c \\u001d \\u001e \\u001f "
4942 " ! \\\" # "
4943 "$ % & ' "
4944 "( ) * + "
4945 ", - . / "
4946 "0 1 2 3 "
4947 "4 5 6 7 "
4948 "8 9 : ; "
4949 "< = > ? "
4950 "@ A B C "
4951 "D E F G "
4952 "H I J K "
4953 "L M N O "
4954 "P Q R S "
4955 "T U V W "
4956 "X Y Z [ "
4957 "\\\\ ] ^ _ "
4958 "` a b c "
4959 "d e f g "
4960 "h i j k "
4961 "l m n o "
4962 "p q r s "
4963 "t u v w "
4964 "x y z { "
4965 "| } ~ \177 ";
4966
4967
4968// For a string that is less than 32k characters it should always be
4969// possible to allocate it in new space.
4970static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4971
4972
4973// Doing JSON quoting cannot make the string more than this many times larger.
4974static const int kJsonQuoteWorstCaseBlowup = 6;
4975
4976
4977// Covers the entire ASCII range (all other characters are unchanged by JSON
4978// quoting).
4979static const byte JsonQuoteLengths[kQuoteTableLength] = {
4980 6, 6, 6, 6, 6, 6, 6, 6,
4981 2, 2, 2, 6, 2, 2, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 6, 6, 6, 6, 6, 6, 6, 6,
4984 1, 1, 2, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 1, 1, 1, 1,
4991 1, 1, 1, 1, 2, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995 1, 1, 1, 1, 1, 1, 1, 1,
4996};
4997
4998
4999template <typename StringType>
Steve Block44f0eee2011-05-26 01:26:41 +01005000MaybeObject* AllocateRawString(Isolate* isolate, int length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005001
5002
5003template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005004MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5005 return isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005006}
5007
5008
5009template <>
Steve Block44f0eee2011-05-26 01:26:41 +01005010MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5011 return isolate->heap()->AllocateRawAsciiString(length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005012}
5013
5014
Ben Murdochb8e0da22011-05-16 14:20:40 +01005015template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005016static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5017 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005018 int length = characters.length();
5019 const Char* read_cursor = characters.start();
5020 const Char* end = read_cursor + length;
Ben Murdochb8e0da22011-05-16 14:20:40 +01005021 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005022 int quoted_length = kSpaceForQuotes;
5023 while (read_cursor < end) {
5024 Char c = *(read_cursor++);
5025 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5026 quoted_length++;
5027 } else {
5028 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
5029 }
5030 }
Steve Block44f0eee2011-05-26 01:26:41 +01005031 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5032 quoted_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005033 Object* new_object;
5034 if (!new_alloc->ToObject(&new_object)) {
5035 return new_alloc;
5036 }
5037 StringType* new_string = StringType::cast(new_object);
5038
5039 Char* write_cursor = reinterpret_cast<Char*>(
5040 new_string->address() + SeqAsciiString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005041 if (comma) *(write_cursor++) = ',';
Ben Murdochb0fe1622011-05-05 13:52:32 +01005042 *(write_cursor++) = '"';
5043
5044 read_cursor = characters.start();
5045 while (read_cursor < end) {
5046 Char c = *(read_cursor++);
5047 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5048 *(write_cursor++) = c;
5049 } else {
5050 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5051 const char* replacement = JsonQuotes +
5052 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5053 for (int i = 0; i < len; i++) {
5054 *write_cursor++ = *replacement++;
5055 }
5056 }
5057 }
5058 *(write_cursor++) = '"';
5059 return new_string;
5060}
5061
5062
Ben Murdochb8e0da22011-05-16 14:20:40 +01005063template <typename Char, typename StringType, bool comma>
Steve Block44f0eee2011-05-26 01:26:41 +01005064static MaybeObject* QuoteJsonString(Isolate* isolate,
5065 Vector<const Char> characters) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005066 int length = characters.length();
Steve Block44f0eee2011-05-26 01:26:41 +01005067 isolate->counters()->quote_json_char_count()->Increment(length);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005068 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005069 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5070 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
Steve Block44f0eee2011-05-26 01:26:41 +01005071 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005072 }
5073
Steve Block44f0eee2011-05-26 01:26:41 +01005074 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5075 worst_case_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005076 Object* new_object;
5077 if (!new_alloc->ToObject(&new_object)) {
5078 return new_alloc;
5079 }
Steve Block44f0eee2011-05-26 01:26:41 +01005080 if (!isolate->heap()->new_space()->Contains(new_object)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005081 // Even if our string is small enough to fit in new space we still have to
5082 // handle it being allocated in old space as may happen in the third
5083 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5084 // CEntryStub::GenerateCore.
Steve Block44f0eee2011-05-26 01:26:41 +01005085 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005086 }
5087 StringType* new_string = StringType::cast(new_object);
Steve Block44f0eee2011-05-26 01:26:41 +01005088 ASSERT(isolate->heap()->new_space()->Contains(new_string));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005089
5090 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5091 Char* write_cursor = reinterpret_cast<Char*>(
5092 new_string->address() + SeqAsciiString::kHeaderSize);
Ben Murdochb8e0da22011-05-16 14:20:40 +01005093 if (comma) *(write_cursor++) = ',';
Ben Murdochb0fe1622011-05-05 13:52:32 +01005094 *(write_cursor++) = '"';
5095
5096 const Char* read_cursor = characters.start();
5097 const Char* end = read_cursor + length;
5098 while (read_cursor < end) {
5099 Char c = *(read_cursor++);
5100 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5101 *(write_cursor++) = c;
5102 } else {
5103 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5104 const char* replacement = JsonQuotes +
5105 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5106 write_cursor[0] = replacement[0];
5107 if (len > 1) {
5108 write_cursor[1] = replacement[1];
5109 if (len > 2) {
5110 ASSERT(len == 6);
5111 write_cursor[2] = replacement[2];
5112 write_cursor[3] = replacement[3];
5113 write_cursor[4] = replacement[4];
5114 write_cursor[5] = replacement[5];
5115 }
5116 }
5117 write_cursor += len;
5118 }
5119 }
5120 *(write_cursor++) = '"';
5121
5122 int final_length = static_cast<int>(
5123 write_cursor - reinterpret_cast<Char*>(
5124 new_string->address() + SeqAsciiString::kHeaderSize));
Steve Block44f0eee2011-05-26 01:26:41 +01005125 isolate->heap()->new_space()->
5126 template ShrinkStringAtAllocationBoundary<StringType>(
5127 new_string, final_length);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005128 return new_string;
5129}
5130
5131
Ben Murdoch8b112d22011-06-08 16:22:53 +01005132RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005133 NoHandleAllocation ha;
5134 CONVERT_CHECKED(String, str, args[0]);
5135 if (!str->IsFlat()) {
5136 MaybeObject* try_flatten = str->TryFlatten();
5137 Object* flat;
5138 if (!try_flatten->ToObject(&flat)) {
5139 return try_flatten;
5140 }
5141 str = String::cast(flat);
5142 ASSERT(str->IsFlat());
5143 }
5144 if (str->IsTwoByteRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005145 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5146 str->ToUC16Vector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005147 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005148 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5149 str->ToAsciiVector());
Ben Murdochb0fe1622011-05-05 13:52:32 +01005150 }
5151}
5152
5153
Ben Murdoch8b112d22011-06-08 16:22:53 +01005154RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01005155 NoHandleAllocation ha;
5156 CONVERT_CHECKED(String, str, args[0]);
5157 if (!str->IsFlat()) {
5158 MaybeObject* try_flatten = str->TryFlatten();
5159 Object* flat;
5160 if (!try_flatten->ToObject(&flat)) {
5161 return try_flatten;
5162 }
5163 str = String::cast(flat);
5164 ASSERT(str->IsFlat());
5165 }
5166 if (str->IsTwoByteRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005167 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5168 str->ToUC16Vector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005169 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005170 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5171 str->ToAsciiVector());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005172 }
5173}
5174
Ben Murdoch8b112d22011-06-08 16:22:53 +01005175RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005176 NoHandleAllocation ha;
5177
5178 CONVERT_CHECKED(String, s, args[0]);
Steve Blockd0582a62009-12-15 09:54:21 +00005179 CONVERT_SMI_CHECKED(radix, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00005180
Steve Block6ded16b2010-05-10 14:33:55 +01005181 s->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00005182
Steve Block6ded16b2010-05-10 14:33:55 +01005183 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
Ben Murdoch8b112d22011-06-08 16:22:53 +01005184 double value = StringToInt(isolate->unicode_cache(), s, radix);
Steve Block44f0eee2011-05-26 01:26:41 +01005185 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005186}
5187
5188
Ben Murdoch8b112d22011-06-08 16:22:53 +01005189RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005190 NoHandleAllocation ha;
5191 CONVERT_CHECKED(String, str, args[0]);
5192
5193 // ECMA-262 section 15.1.2.3, empty string is NaN
Ben Murdoch8b112d22011-06-08 16:22:53 +01005194 double value = StringToDouble(isolate->unicode_cache(),
5195 str, ALLOW_TRAILING_JUNK, OS::nan_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005196
5197 // Create a number object from the value.
Steve Block44f0eee2011-05-26 01:26:41 +01005198 return isolate->heap()->NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00005199}
5200
5201
Steve Blocka7e24c12009-10-30 11:49:00 +00005202template <class Converter>
John Reck59135872010-11-02 12:39:01 -07005203MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01005204 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -07005205 String* s,
5206 int length,
5207 int input_string_length,
5208 unibrow::Mapping<Converter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005209 // We try this twice, once with the assumption that the result is no longer
5210 // than the input and, if that assumption breaks, again with the exact
5211 // length. This may not be pretty, but it is nicer than what was here before
5212 // and I hereby claim my vaffel-is.
5213 //
5214 // Allocate the resulting string.
5215 //
5216 // NOTE: This assumes that the upper/lower case of an ascii
5217 // character is also ascii. This is currently the case, but it
5218 // might break in the future if we implement more context and locale
5219 // dependent upper/lower conversions.
John Reck59135872010-11-02 12:39:01 -07005220 Object* o;
5221 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
Steve Block44f0eee2011-05-26 01:26:41 +01005222 ? isolate->heap()->AllocateRawAsciiString(length)
5223 : isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07005224 if (!maybe_o->ToObject(&o)) return maybe_o;
5225 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005226 String* result = String::cast(o);
5227 bool has_changed_character = false;
5228
5229 // Convert all characters to upper case, assuming that they will fit
5230 // in the buffer
Steve Block44f0eee2011-05-26 01:26:41 +01005231 Access<StringInputBuffer> buffer(
5232 isolate->runtime_state()->string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005233 buffer->Reset(s);
5234 unibrow::uchar chars[Converter::kMaxWidth];
5235 // We can assume that the string is not empty
5236 uc32 current = buffer->GetNext();
5237 for (int i = 0; i < length;) {
5238 bool has_next = buffer->has_more();
5239 uc32 next = has_next ? buffer->GetNext() : 0;
5240 int char_length = mapping->get(current, next, chars);
5241 if (char_length == 0) {
5242 // The case conversion of this character is the character itself.
5243 result->Set(i, current);
5244 i++;
5245 } else if (char_length == 1) {
5246 // Common case: converting the letter resulted in one character.
5247 ASSERT(static_cast<uc32>(chars[0]) != current);
5248 result->Set(i, chars[0]);
5249 has_changed_character = true;
5250 i++;
5251 } else if (length == input_string_length) {
5252 // We've assumed that the result would be as long as the
5253 // input but here is a character that converts to several
5254 // characters. No matter, we calculate the exact length
5255 // of the result and try the whole thing again.
5256 //
5257 // Note that this leaves room for optimization. We could just
5258 // memcpy what we already have to the result string. Also,
5259 // the result string is the last object allocated we could
5260 // "realloc" it and probably, in the vast majority of cases,
5261 // extend the existing string to be able to hold the full
5262 // result.
5263 int next_length = 0;
5264 if (has_next) {
5265 next_length = mapping->get(next, 0, chars);
5266 if (next_length == 0) next_length = 1;
5267 }
5268 int current_length = i + char_length + next_length;
5269 while (buffer->has_more()) {
5270 current = buffer->GetNext();
5271 // NOTE: we use 0 as the next character here because, while
5272 // the next character may affect what a character converts to,
5273 // it does not in any case affect the length of what it convert
5274 // to.
5275 int char_length = mapping->get(current, 0, chars);
5276 if (char_length == 0) char_length = 1;
5277 current_length += char_length;
5278 if (current_length > Smi::kMaxValue) {
Steve Block44f0eee2011-05-26 01:26:41 +01005279 isolate->context()->mark_out_of_memory();
Steve Blocka7e24c12009-10-30 11:49:00 +00005280 return Failure::OutOfMemoryException();
5281 }
5282 }
5283 // Try again with the real length.
5284 return Smi::FromInt(current_length);
5285 } else {
5286 for (int j = 0; j < char_length; j++) {
5287 result->Set(i, chars[j]);
5288 i++;
5289 }
5290 has_changed_character = true;
5291 }
5292 current = next;
5293 }
5294 if (has_changed_character) {
5295 return result;
5296 } else {
5297 // If we didn't actually change anything in doing the conversion
5298 // we simple return the result and let the converted string
5299 // become garbage; there is no reason to keep two identical strings
5300 // alive.
5301 return s;
5302 }
5303}
5304
5305
Steve Block6ded16b2010-05-10 14:33:55 +01005306namespace {
5307
John Reck59135872010-11-02 12:39:01 -07005308static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5309
5310
5311// Given a word and two range boundaries returns a word with high bit
5312// set in every byte iff the corresponding input byte was strictly in
5313// the range (m, n). All the other bits in the result are cleared.
5314// This function is only useful when it can be inlined and the
5315// boundaries are statically known.
5316// Requires: all bytes in the input word and the boundaries must be
5317// ascii (less than 0x7F).
5318static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5319 // Every byte in an ascii string is less than or equal to 0x7F.
5320 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5321 // Use strict inequalities since in edge cases the function could be
5322 // further simplified.
5323 ASSERT(0 < m && m < n && n < 0x7F);
5324 // Has high bit set in every w byte less than n.
5325 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5326 // Has high bit set in every w byte greater than m.
5327 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5328 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5329}
5330
5331
5332enum AsciiCaseConversion {
5333 ASCII_TO_LOWER,
5334 ASCII_TO_UPPER
5335};
5336
5337
5338template <AsciiCaseConversion dir>
5339struct FastAsciiConverter {
5340 static bool Convert(char* dst, char* src, int length) {
5341#ifdef DEBUG
5342 char* saved_dst = dst;
5343 char* saved_src = src;
5344#endif
5345 // We rely on the distance between upper and lower case letters
5346 // being a known power of 2.
5347 ASSERT('a' - 'A' == (1 << 5));
5348 // Boundaries for the range of input characters than require conversion.
5349 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5350 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5351 bool changed = false;
5352 char* const limit = src + length;
5353#ifdef V8_HOST_CAN_READ_UNALIGNED
5354 // Process the prefix of the input that requires no conversion one
5355 // (machine) word at a time.
5356 while (src <= limit - sizeof(uintptr_t)) {
5357 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5358 if (AsciiRangeMask(w, lo, hi) != 0) {
5359 changed = true;
5360 break;
5361 }
5362 *reinterpret_cast<uintptr_t*>(dst) = w;
5363 src += sizeof(uintptr_t);
5364 dst += sizeof(uintptr_t);
5365 }
5366 // Process the remainder of the input performing conversion when
5367 // required one word at a time.
5368 while (src <= limit - sizeof(uintptr_t)) {
5369 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5370 uintptr_t m = AsciiRangeMask(w, lo, hi);
5371 // The mask has high (7th) bit set in every byte that needs
5372 // conversion and we know that the distance between cases is
5373 // 1 << 5.
5374 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5375 src += sizeof(uintptr_t);
5376 dst += sizeof(uintptr_t);
5377 }
5378#endif
5379 // Process the last few bytes of the input (or the whole input if
5380 // unaligned access is not supported).
5381 while (src < limit) {
5382 char c = *src;
5383 if (lo < c && c < hi) {
5384 c ^= (1 << 5);
5385 changed = true;
5386 }
5387 *dst = c;
5388 ++src;
5389 ++dst;
5390 }
5391#ifdef DEBUG
5392 CheckConvert(saved_dst, saved_src, length, changed);
5393#endif
5394 return changed;
5395 }
5396
5397#ifdef DEBUG
5398 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5399 bool expected_changed = false;
5400 for (int i = 0; i < length; i++) {
5401 if (dst[i] == src[i]) continue;
5402 expected_changed = true;
5403 if (dir == ASCII_TO_LOWER) {
5404 ASSERT('A' <= src[i] && src[i] <= 'Z');
5405 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5406 } else {
5407 ASSERT(dir == ASCII_TO_UPPER);
5408 ASSERT('a' <= src[i] && src[i] <= 'z');
5409 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5410 }
5411 }
5412 ASSERT(expected_changed == changed);
5413 }
5414#endif
5415};
5416
5417
Steve Block6ded16b2010-05-10 14:33:55 +01005418struct ToLowerTraits {
5419 typedef unibrow::ToLowercase UnibrowConverter;
5420
John Reck59135872010-11-02 12:39:01 -07005421 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01005422};
5423
5424
5425struct ToUpperTraits {
5426 typedef unibrow::ToUppercase UnibrowConverter;
5427
John Reck59135872010-11-02 12:39:01 -07005428 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01005429};
5430
5431} // namespace
5432
5433
5434template <typename ConvertTraits>
John Reck59135872010-11-02 12:39:01 -07005435MUST_USE_RESULT static MaybeObject* ConvertCase(
Steve Block6ded16b2010-05-10 14:33:55 +01005436 Arguments args,
Steve Block44f0eee2011-05-26 01:26:41 +01005437 Isolate* isolate,
Steve Block6ded16b2010-05-10 14:33:55 +01005438 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005439 NoHandleAllocation ha;
Steve Blocka7e24c12009-10-30 11:49:00 +00005440 CONVERT_CHECKED(String, s, args[0]);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005441 s = s->TryFlattenGetString();
Steve Blocka7e24c12009-10-30 11:49:00 +00005442
Steve Block6ded16b2010-05-10 14:33:55 +01005443 const int length = s->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00005444 // Assume that the string is not empty; we need this assumption later
Steve Block6ded16b2010-05-10 14:33:55 +01005445 if (length == 0) return s;
5446
5447 // Simpler handling of ascii strings.
5448 //
5449 // NOTE: This assumes that the upper/lower case of an ascii
5450 // character is also ascii. This is currently the case, but it
5451 // might break in the future if we implement more context and locale
5452 // dependent upper/lower conversions.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005453 if (s->IsSeqAsciiString()) {
John Reck59135872010-11-02 12:39:01 -07005454 Object* o;
Steve Block44f0eee2011-05-26 01:26:41 +01005455 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07005456 if (!maybe_o->ToObject(&o)) return maybe_o;
5457 }
Steve Block6ded16b2010-05-10 14:33:55 +01005458 SeqAsciiString* result = SeqAsciiString::cast(o);
John Reck59135872010-11-02 12:39:01 -07005459 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005460 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
Steve Block6ded16b2010-05-10 14:33:55 +01005461 return has_changed_character ? result : s;
5462 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005463
John Reck59135872010-11-02 12:39:01 -07005464 Object* answer;
Steve Block44f0eee2011-05-26 01:26:41 +01005465 { MaybeObject* maybe_answer =
5466 ConvertCaseHelper(isolate, s, length, length, mapping);
John Reck59135872010-11-02 12:39:01 -07005467 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5468 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005469 if (answer->IsSmi()) {
5470 // Retry with correct length.
John Reck59135872010-11-02 12:39:01 -07005471 { MaybeObject* maybe_answer =
Steve Block44f0eee2011-05-26 01:26:41 +01005472 ConvertCaseHelper(isolate,
5473 s, Smi::cast(answer)->value(), length, mapping);
John Reck59135872010-11-02 12:39:01 -07005474 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5475 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005476 }
John Reck59135872010-11-02 12:39:01 -07005477 return answer;
Steve Blocka7e24c12009-10-30 11:49:00 +00005478}
5479
5480
Ben Murdoch8b112d22011-06-08 16:22:53 +01005481RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01005482 return ConvertCase<ToLowerTraits>(
5483 args, isolate, isolate->runtime_state()->to_lower_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00005484}
5485
5486
Ben Murdoch8b112d22011-06-08 16:22:53 +01005487RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
Steve Block44f0eee2011-05-26 01:26:41 +01005488 return ConvertCase<ToUpperTraits>(
5489 args, isolate, isolate->runtime_state()->to_upper_mapping());
Steve Blocka7e24c12009-10-30 11:49:00 +00005490}
5491
Steve Block6ded16b2010-05-10 14:33:55 +01005492
Steve Block3ce2e202009-11-05 08:53:23 +00005493static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5494 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5495}
5496
Steve Block6ded16b2010-05-10 14:33:55 +01005497
Ben Murdoch8b112d22011-06-08 16:22:53 +01005498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
Steve Block3ce2e202009-11-05 08:53:23 +00005499 NoHandleAllocation ha;
5500 ASSERT(args.length() == 3);
5501
5502 CONVERT_CHECKED(String, s, args[0]);
5503 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5504 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5505
Steve Block6ded16b2010-05-10 14:33:55 +01005506 s->TryFlatten();
Steve Block3ce2e202009-11-05 08:53:23 +00005507 int length = s->length();
5508
5509 int left = 0;
5510 if (trimLeft) {
5511 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5512 left++;
5513 }
5514 }
5515
5516 int right = length;
5517 if (trimRight) {
5518 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5519 right--;
5520 }
5521 }
Steve Blockd0582a62009-12-15 09:54:21 +00005522 return s->SubString(left, right);
Steve Block3ce2e202009-11-05 08:53:23 +00005523}
Steve Blocka7e24c12009-10-30 11:49:00 +00005524
Steve Block6ded16b2010-05-10 14:33:55 +01005525
Ben Murdochf87a2032010-10-22 12:50:53 +01005526template <typename SubjectChar, typename PatternChar>
Steve Block44f0eee2011-05-26 01:26:41 +01005527void FindStringIndices(Isolate* isolate,
5528 Vector<const SubjectChar> subject,
Ben Murdochf87a2032010-10-22 12:50:53 +01005529 Vector<const PatternChar> pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01005530 ZoneList<int>* indices,
5531 unsigned int limit) {
5532 ASSERT(limit > 0);
5533 // Collect indices of pattern in subject, and the end-of-string index.
5534 // Stop after finding at most limit values.
Steve Block44f0eee2011-05-26 01:26:41 +01005535 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
Ben Murdochf87a2032010-10-22 12:50:53 +01005536 int pattern_length = pattern.length();
5537 int index = 0;
5538 while (limit > 0) {
5539 index = search.Search(subject, index);
5540 if (index < 0) return;
5541 indices->Add(index);
5542 index += pattern_length;
5543 limit--;
Steve Block6ded16b2010-05-10 14:33:55 +01005544 }
5545}
5546
Steve Block6ded16b2010-05-10 14:33:55 +01005547
Ben Murdoch8b112d22011-06-08 16:22:53 +01005548RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
Steve Block6ded16b2010-05-10 14:33:55 +01005549 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +01005550 HandleScope handle_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01005551 CONVERT_ARG_CHECKED(String, subject, 0);
5552 CONVERT_ARG_CHECKED(String, pattern, 1);
5553 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5554
5555 int subject_length = subject->length();
5556 int pattern_length = pattern->length();
5557 RUNTIME_ASSERT(pattern_length > 0);
5558
5559 // The limit can be very large (0xffffffffu), but since the pattern
5560 // isn't empty, we can never create more parts than ~half the length
5561 // of the subject.
5562
5563 if (!subject->IsFlat()) FlattenString(subject);
5564
5565 static const int kMaxInitialListCapacity = 16;
5566
5567 ZoneScope scope(DELETE_ON_EXIT);
5568
5569 // Find (up to limit) indices of separator and end-of-string in subject
5570 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5571 ZoneList<int> indices(initial_capacity);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005572 if (!pattern->IsFlat()) FlattenString(pattern);
5573
5574 // No allocation block.
5575 {
Steve Block6ded16b2010-05-10 14:33:55 +01005576 AssertNoAllocation nogc;
5577 if (subject->IsAsciiRepresentation()) {
5578 Vector<const char> subject_vector = subject->ToAsciiVector();
5579 if (pattern->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005580 FindStringIndices(isolate,
5581 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01005582 pattern->ToAsciiVector(),
5583 &indices,
5584 limit);
5585 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005586 FindStringIndices(isolate,
5587 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01005588 pattern->ToUC16Vector(),
5589 &indices,
5590 limit);
5591 }
5592 } else {
5593 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5594 if (pattern->IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005595 FindStringIndices(isolate,
5596 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01005597 pattern->ToAsciiVector(),
5598 &indices,
5599 limit);
5600 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005601 FindStringIndices(isolate,
5602 subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01005603 pattern->ToUC16Vector(),
5604 &indices,
5605 limit);
5606 }
5607 }
5608 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005609
Steve Block6ded16b2010-05-10 14:33:55 +01005610 if (static_cast<uint32_t>(indices.length()) < limit) {
5611 indices.Add(subject_length);
5612 }
Steve Block6ded16b2010-05-10 14:33:55 +01005613
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005614 // The list indices now contains the end of each part to create.
Steve Block6ded16b2010-05-10 14:33:55 +01005615
5616 // Create JSArray of substrings separated by separator.
5617 int part_count = indices.length();
5618
Steve Block44f0eee2011-05-26 01:26:41 +01005619 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
Steve Block6ded16b2010-05-10 14:33:55 +01005620 result->set_length(Smi::FromInt(part_count));
5621
5622 ASSERT(result->HasFastElements());
5623
5624 if (part_count == 1 && indices.at(0) == subject_length) {
5625 FixedArray::cast(result->elements())->set(0, *subject);
5626 return *result;
5627 }
5628
5629 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5630 int part_start = 0;
5631 for (int i = 0; i < part_count; i++) {
5632 HandleScope local_loop_handle;
5633 int part_end = indices.at(i);
5634 Handle<String> substring =
Steve Block44f0eee2011-05-26 01:26:41 +01005635 isolate->factory()->NewSubString(subject, part_start, part_end);
Steve Block6ded16b2010-05-10 14:33:55 +01005636 elements->set(i, *substring);
5637 part_start = part_end + pattern_length;
5638 }
5639
5640 return *result;
5641}
5642
5643
5644// Copies ascii characters to the given fixed array looking up
5645// one-char strings in the cache. Gives up on the first char that is
5646// not in the cache and fills the remainder with smi zeros. Returns
5647// the length of the successfully copied prefix.
Steve Block44f0eee2011-05-26 01:26:41 +01005648static int CopyCachedAsciiCharsToArray(Heap* heap,
5649 const char* chars,
Steve Block6ded16b2010-05-10 14:33:55 +01005650 FixedArray* elements,
5651 int length) {
5652 AssertNoAllocation nogc;
Steve Block44f0eee2011-05-26 01:26:41 +01005653 FixedArray* ascii_cache = heap->single_character_string_cache();
5654 Object* undefined = heap->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005655 int i;
5656 for (i = 0; i < length; ++i) {
5657 Object* value = ascii_cache->get(chars[i]);
5658 if (value == undefined) break;
Steve Block44f0eee2011-05-26 01:26:41 +01005659 ASSERT(!heap->InNewSpace(value));
Steve Block6ded16b2010-05-10 14:33:55 +01005660 elements->set(i, value, SKIP_WRITE_BARRIER);
5661 }
5662 if (i < length) {
5663 ASSERT(Smi::FromInt(0) == 0);
5664 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5665 }
5666#ifdef DEBUG
5667 for (int j = 0; j < length; ++j) {
5668 Object* element = elements->get(j);
5669 ASSERT(element == Smi::FromInt(0) ||
5670 (element->IsString() && String::cast(element)->LooksValid()));
5671 }
5672#endif
5673 return i;
5674}
5675
5676
5677// Converts a String to JSArray.
5678// For example, "foo" => ["f", "o", "o"].
Ben Murdoch8b112d22011-06-08 16:22:53 +01005679RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
Steve Block44f0eee2011-05-26 01:26:41 +01005680 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005681 ASSERT(args.length() == 2);
Steve Block6ded16b2010-05-10 14:33:55 +01005682 CONVERT_ARG_CHECKED(String, s, 0);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005683 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Steve Block6ded16b2010-05-10 14:33:55 +01005684
5685 s->TryFlatten();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005686 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
Steve Block6ded16b2010-05-10 14:33:55 +01005687
5688 Handle<FixedArray> elements;
5689 if (s->IsFlat() && s->IsAsciiRepresentation()) {
John Reck59135872010-11-02 12:39:01 -07005690 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01005691 { MaybeObject* maybe_obj =
5692 isolate->heap()->AllocateUninitializedFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07005693 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5694 }
Steve Block44f0eee2011-05-26 01:26:41 +01005695 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01005696
5697 Vector<const char> chars = s->ToAsciiVector();
5698 // Note, this will initialize all elements (not only the prefix)
5699 // to prevent GC from seeing partially initialized array.
Steve Block44f0eee2011-05-26 01:26:41 +01005700 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5701 chars.start(),
Steve Block6ded16b2010-05-10 14:33:55 +01005702 *elements,
5703 length);
5704
5705 for (int i = num_copied_from_cache; i < length; ++i) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005706 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5707 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01005708 }
5709 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005710 elements = isolate->factory()->NewFixedArray(length);
Steve Block6ded16b2010-05-10 14:33:55 +01005711 for (int i = 0; i < length; ++i) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005712 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5713 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01005714 }
5715 }
5716
5717#ifdef DEBUG
5718 for (int i = 0; i < length; ++i) {
5719 ASSERT(String::cast(elements->get(i))->length() == 1);
5720 }
5721#endif
5722
Steve Block44f0eee2011-05-26 01:26:41 +01005723 return *isolate->factory()->NewJSArrayWithElements(elements);
Steve Block6ded16b2010-05-10 14:33:55 +01005724}
5725
5726
Ben Murdoch8b112d22011-06-08 16:22:53 +01005727RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005728 NoHandleAllocation ha;
5729 ASSERT(args.length() == 1);
5730 CONVERT_CHECKED(String, value, args[0]);
5731 return value->ToObject();
5732}
5733
5734
Steve Block44f0eee2011-05-26 01:26:41 +01005735bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005736 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
Steve Block44f0eee2011-05-26 01:26:41 +01005737 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005738 return char_length == 0;
5739}
5740
5741
Ben Murdoch8b112d22011-06-08 16:22:53 +01005742RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005743 NoHandleAllocation ha;
5744 ASSERT(args.length() == 1);
5745
5746 Object* number = args[0];
5747 RUNTIME_ASSERT(number->IsNumber());
5748
Steve Block44f0eee2011-05-26 01:26:41 +01005749 return isolate->heap()->NumberToString(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00005750}
5751
5752
Ben Murdoch8b112d22011-06-08 16:22:53 +01005753RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
Steve Block6ded16b2010-05-10 14:33:55 +01005754 NoHandleAllocation ha;
5755 ASSERT(args.length() == 1);
5756
5757 Object* number = args[0];
5758 RUNTIME_ASSERT(number->IsNumber());
5759
Steve Block44f0eee2011-05-26 01:26:41 +01005760 return isolate->heap()->NumberToString(number, false);
Steve Block6ded16b2010-05-10 14:33:55 +01005761}
5762
5763
Ben Murdoch8b112d22011-06-08 16:22:53 +01005764RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
5767
Steve Block6ded16b2010-05-10 14:33:55 +01005768 CONVERT_DOUBLE_CHECKED(number, args[0]);
5769
5770 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5771 if (number > 0 && number <= Smi::kMaxValue) {
5772 return Smi::FromInt(static_cast<int>(number));
5773 }
Steve Block44f0eee2011-05-26 01:26:41 +01005774 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00005775}
5776
5777
Ben Murdoch8b112d22011-06-08 16:22:53 +01005778RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005779 NoHandleAllocation ha;
5780 ASSERT(args.length() == 1);
5781
5782 CONVERT_DOUBLE_CHECKED(number, args[0]);
5783
5784 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5785 if (number > 0 && number <= Smi::kMaxValue) {
5786 return Smi::FromInt(static_cast<int>(number));
5787 }
5788
5789 double double_value = DoubleToInteger(number);
5790 // Map both -0 and +0 to +0.
5791 if (double_value == 0) double_value = 0;
5792
Steve Block44f0eee2011-05-26 01:26:41 +01005793 return isolate->heap()->NumberFromDouble(double_value);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005794}
5795
5796
Ben Murdoch8b112d22011-06-08 16:22:53 +01005797RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005798 NoHandleAllocation ha;
5799 ASSERT(args.length() == 1);
5800
Steve Block6ded16b2010-05-10 14:33:55 +01005801 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01005802 return isolate->heap()->NumberFromUint32(number);
Steve Blocka7e24c12009-10-30 11:49:00 +00005803}
5804
5805
Ben Murdoch8b112d22011-06-08 16:22:53 +01005806RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005807 NoHandleAllocation ha;
5808 ASSERT(args.length() == 1);
5809
Steve Block6ded16b2010-05-10 14:33:55 +01005810 CONVERT_DOUBLE_CHECKED(number, args[0]);
5811
5812 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5813 if (number > 0 && number <= Smi::kMaxValue) {
5814 return Smi::FromInt(static_cast<int>(number));
5815 }
Steve Block44f0eee2011-05-26 01:26:41 +01005816 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
Steve Blocka7e24c12009-10-30 11:49:00 +00005817}
5818
5819
5820// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5821// a small integer.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005822RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005823 NoHandleAllocation ha;
5824 ASSERT(args.length() == 1);
5825
5826 Object* obj = args[0];
5827 if (obj->IsSmi()) {
5828 return obj;
5829 }
5830 if (obj->IsHeapNumber()) {
5831 double value = HeapNumber::cast(obj)->value();
5832 int int_value = FastD2I(value);
5833 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5834 return Smi::FromInt(int_value);
5835 }
5836 }
Steve Block44f0eee2011-05-26 01:26:41 +01005837 return isolate->heap()->nan_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00005838}
5839
5840
Ben Murdoch8b112d22011-06-08 16:22:53 +01005841RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01005842 NoHandleAllocation ha;
5843 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005844 return isolate->heap()->AllocateHeapNumber(0);
Ben Murdochb0fe1622011-05-05 13:52:32 +01005845}
5846
5847
Ben Murdoch8b112d22011-06-08 16:22:53 +01005848RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005849 NoHandleAllocation ha;
5850 ASSERT(args.length() == 2);
5851
5852 CONVERT_DOUBLE_CHECKED(x, args[0]);
5853 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01005854 return isolate->heap()->NumberFromDouble(x + y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005855}
5856
5857
Ben Murdoch8b112d22011-06-08 16:22:53 +01005858RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005859 NoHandleAllocation ha;
5860 ASSERT(args.length() == 2);
5861
5862 CONVERT_DOUBLE_CHECKED(x, args[0]);
5863 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01005864 return isolate->heap()->NumberFromDouble(x - y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005865}
5866
5867
Ben Murdoch8b112d22011-06-08 16:22:53 +01005868RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005869 NoHandleAllocation ha;
5870 ASSERT(args.length() == 2);
5871
5872 CONVERT_DOUBLE_CHECKED(x, args[0]);
5873 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01005874 return isolate->heap()->NumberFromDouble(x * y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005875}
5876
5877
Ben Murdoch8b112d22011-06-08 16:22:53 +01005878RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005879 NoHandleAllocation ha;
5880 ASSERT(args.length() == 1);
5881
5882 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01005883 return isolate->heap()->NumberFromDouble(-x);
Steve Blocka7e24c12009-10-30 11:49:00 +00005884}
5885
5886
Ben Murdoch8b112d22011-06-08 16:22:53 +01005887RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005888 NoHandleAllocation ha;
5889 ASSERT(args.length() == 0);
5890
Steve Block44f0eee2011-05-26 01:26:41 +01005891 return isolate->heap()->NumberFromDouble(9876543210.0);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005892}
5893
5894
Ben Murdoch8b112d22011-06-08 16:22:53 +01005895RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005896 NoHandleAllocation ha;
5897 ASSERT(args.length() == 2);
5898
5899 CONVERT_DOUBLE_CHECKED(x, args[0]);
5900 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01005901 return isolate->heap()->NumberFromDouble(x / y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005902}
5903
5904
Ben Murdoch8b112d22011-06-08 16:22:53 +01005905RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 2);
5908
5909 CONVERT_DOUBLE_CHECKED(x, args[0]);
5910 CONVERT_DOUBLE_CHECKED(y, args[1]);
5911
Steve Block3ce2e202009-11-05 08:53:23 +00005912 x = modulo(x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01005913 // NumberFromDouble may return a Smi instead of a Number object
Steve Block44f0eee2011-05-26 01:26:41 +01005914 return isolate->heap()->NumberFromDouble(x);
Steve Blocka7e24c12009-10-30 11:49:00 +00005915}
5916
5917
Ben Murdoch8b112d22011-06-08 16:22:53 +01005918RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005919 NoHandleAllocation ha;
5920 ASSERT(args.length() == 2);
5921 CONVERT_CHECKED(String, str1, args[0]);
5922 CONVERT_CHECKED(String, str2, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01005923 isolate->counters()->string_add_runtime()->Increment();
5924 return isolate->heap()->AllocateConsString(str1, str2);
Steve Blocka7e24c12009-10-30 11:49:00 +00005925}
5926
5927
Steve Block6ded16b2010-05-10 14:33:55 +01005928template <typename sinkchar>
Steve Blocka7e24c12009-10-30 11:49:00 +00005929static inline void StringBuilderConcatHelper(String* special,
5930 sinkchar* sink,
5931 FixedArray* fixed_array,
5932 int array_length) {
5933 int position = 0;
5934 for (int i = 0; i < array_length; i++) {
5935 Object* element = fixed_array->get(i);
5936 if (element->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005937 // Smi encoding of position and length.
Steve Blocka7e24c12009-10-30 11:49:00 +00005938 int encoded_slice = Smi::cast(element)->value();
Steve Blockd0582a62009-12-15 09:54:21 +00005939 int pos;
5940 int len;
5941 if (encoded_slice > 0) {
5942 // Position and length encoded in one smi.
5943 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5944 len = StringBuilderSubstringLength::decode(encoded_slice);
5945 } else {
5946 // Position and length encoded in two smis.
5947 Object* obj = fixed_array->get(++i);
5948 ASSERT(obj->IsSmi());
5949 pos = Smi::cast(obj)->value();
5950 len = -encoded_slice;
5951 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005952 String::WriteToFlat(special,
5953 sink + position,
5954 pos,
5955 pos + len);
5956 position += len;
5957 } else {
5958 String* string = String::cast(element);
5959 int element_length = string->length();
5960 String::WriteToFlat(string, sink + position, 0, element_length);
5961 position += element_length;
5962 }
5963 }
5964}
5965
5966
Ben Murdoch8b112d22011-06-08 16:22:53 +01005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005968 NoHandleAllocation ha;
Leon Clarkee46be812010-01-19 14:06:41 +00005969 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00005970 CONVERT_CHECKED(JSArray, array, args[0]);
Leon Clarkee46be812010-01-19 14:06:41 +00005971 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005972 isolate->context()->mark_out_of_memory();
Leon Clarkee46be812010-01-19 14:06:41 +00005973 return Failure::OutOfMemoryException();
5974 }
5975 int array_length = Smi::cast(args[1])->value();
5976 CONVERT_CHECKED(String, special, args[2]);
Steve Blockd0582a62009-12-15 09:54:21 +00005977
5978 // This assumption is used by the slice encoding in one or two smis.
5979 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5980
Steve Blocka7e24c12009-10-30 11:49:00 +00005981 int special_length = special->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00005982 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005983 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00005984 }
5985 FixedArray* fixed_array = FixedArray::cast(array->elements());
5986 if (fixed_array->length() < array_length) {
5987 array_length = fixed_array->length();
5988 }
5989
5990 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01005991 return isolate->heap()->empty_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00005992 } else if (array_length == 1) {
5993 Object* first = fixed_array->get(0);
5994 if (first->IsString()) return first;
5995 }
5996
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005997 bool ascii = special->HasOnlyAsciiChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005998 int position = 0;
5999 for (int i = 0; i < array_length; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01006000 int increment = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006001 Object* elt = fixed_array->get(i);
6002 if (elt->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006003 // Smi encoding of position and length.
Steve Block6ded16b2010-05-10 14:33:55 +01006004 int smi_value = Smi::cast(elt)->value();
6005 int pos;
6006 int len;
6007 if (smi_value > 0) {
Steve Blockd0582a62009-12-15 09:54:21 +00006008 // Position and length encoded in one smi.
Steve Block6ded16b2010-05-10 14:33:55 +01006009 pos = StringBuilderSubstringPosition::decode(smi_value);
6010 len = StringBuilderSubstringLength::decode(smi_value);
Steve Blockd0582a62009-12-15 09:54:21 +00006011 } else {
6012 // Position and length encoded in two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01006013 len = -smi_value;
6014 // Get the position and check that it is a positive smi.
Steve Blockd0582a62009-12-15 09:54:21 +00006015 i++;
6016 if (i >= array_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006017 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006018 }
Steve Block6ded16b2010-05-10 14:33:55 +01006019 Object* next_smi = fixed_array->get(i);
6020 if (!next_smi->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006021 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006022 }
6023 pos = Smi::cast(next_smi)->value();
6024 if (pos < 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006025 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blockd0582a62009-12-15 09:54:21 +00006026 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006027 }
Steve Block6ded16b2010-05-10 14:33:55 +01006028 ASSERT(pos >= 0);
6029 ASSERT(len >= 0);
6030 if (pos > special_length || len > special_length - pos) {
Steve Block44f0eee2011-05-26 01:26:41 +01006031 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Block6ded16b2010-05-10 14:33:55 +01006032 }
6033 increment = len;
Steve Blocka7e24c12009-10-30 11:49:00 +00006034 } else if (elt->IsString()) {
6035 String* element = String::cast(elt);
6036 int element_length = element->length();
Leon Clarkee46be812010-01-19 14:06:41 +00006037 increment = element_length;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006038 if (ascii && !element->HasOnlyAsciiChars()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006039 ascii = false;
6040 }
6041 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006042 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00006043 }
Leon Clarkee46be812010-01-19 14:06:41 +00006044 if (increment > String::kMaxLength - position) {
Steve Block44f0eee2011-05-26 01:26:41 +01006045 isolate->context()->mark_out_of_memory();
Steve Block3ce2e202009-11-05 08:53:23 +00006046 return Failure::OutOfMemoryException();
6047 }
Leon Clarkee46be812010-01-19 14:06:41 +00006048 position += increment;
Steve Blocka7e24c12009-10-30 11:49:00 +00006049 }
6050
6051 int length = position;
6052 Object* object;
6053
6054 if (ascii) {
Steve Block44f0eee2011-05-26 01:26:41 +01006055 { MaybeObject* maybe_object =
6056 isolate->heap()->AllocateRawAsciiString(length);
John Reck59135872010-11-02 12:39:01 -07006057 if (!maybe_object->ToObject(&object)) return maybe_object;
6058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006059 SeqAsciiString* answer = SeqAsciiString::cast(object);
6060 StringBuilderConcatHelper(special,
6061 answer->GetChars(),
6062 fixed_array,
6063 array_length);
6064 return answer;
6065 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006066 { MaybeObject* maybe_object =
6067 isolate->heap()->AllocateRawTwoByteString(length);
John Reck59135872010-11-02 12:39:01 -07006068 if (!maybe_object->ToObject(&object)) return maybe_object;
6069 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006070 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6071 StringBuilderConcatHelper(special,
6072 answer->GetChars(),
6073 fixed_array,
6074 array_length);
6075 return answer;
6076 }
6077}
6078
6079
Ben Murdoch8b112d22011-06-08 16:22:53 +01006080RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006081 NoHandleAllocation ha;
6082 ASSERT(args.length() == 3);
6083 CONVERT_CHECKED(JSArray, array, args[0]);
6084 if (!args[1]->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006085 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006086 return Failure::OutOfMemoryException();
6087 }
6088 int array_length = Smi::cast(args[1])->value();
6089 CONVERT_CHECKED(String, separator, args[2]);
6090
6091 if (!array->HasFastElements()) {
Steve Block44f0eee2011-05-26 01:26:41 +01006092 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006093 }
6094 FixedArray* fixed_array = FixedArray::cast(array->elements());
6095 if (fixed_array->length() < array_length) {
6096 array_length = fixed_array->length();
6097 }
6098
6099 if (array_length == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006100 return isolate->heap()->empty_string();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006101 } else if (array_length == 1) {
6102 Object* first = fixed_array->get(0);
6103 if (first->IsString()) return first;
6104 }
6105
6106 int separator_length = separator->length();
6107 int max_nof_separators =
6108 (String::kMaxLength + separator_length - 1) / separator_length;
6109 if (max_nof_separators < (array_length - 1)) {
Steve Block44f0eee2011-05-26 01:26:41 +01006110 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006111 return Failure::OutOfMemoryException();
6112 }
6113 int length = (array_length - 1) * separator_length;
6114 for (int i = 0; i < array_length; i++) {
6115 Object* element_obj = fixed_array->get(i);
6116 if (!element_obj->IsString()) {
6117 // TODO(1161): handle this case.
Steve Block44f0eee2011-05-26 01:26:41 +01006118 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006119 }
6120 String* element = String::cast(element_obj);
6121 int increment = element->length();
6122 if (increment > String::kMaxLength - length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006123 isolate->context()->mark_out_of_memory();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006124 return Failure::OutOfMemoryException();
6125 }
6126 length += increment;
6127 }
6128
6129 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +01006130 { MaybeObject* maybe_object =
6131 isolate->heap()->AllocateRawTwoByteString(length);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006132 if (!maybe_object->ToObject(&object)) return maybe_object;
6133 }
6134 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6135
6136 uc16* sink = answer->GetChars();
6137#ifdef DEBUG
6138 uc16* end = sink + length;
6139#endif
6140
6141 String* first = String::cast(fixed_array->get(0));
6142 int first_length = first->length();
6143 String::WriteToFlat(first, sink, 0, first_length);
6144 sink += first_length;
6145
6146 for (int i = 1; i < array_length; i++) {
6147 ASSERT(sink + separator_length <= end);
6148 String::WriteToFlat(separator, sink, 0, separator_length);
6149 sink += separator_length;
6150
6151 String* element = String::cast(fixed_array->get(i));
6152 int element_length = element->length();
6153 ASSERT(sink + element_length <= end);
6154 String::WriteToFlat(element, sink, 0, element_length);
6155 sink += element_length;
6156 }
6157 ASSERT(sink == end);
6158
6159 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6160 return answer;
6161}
6162
6163
Ben Murdoch8b112d22011-06-08 16:22:53 +01006164RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006165 NoHandleAllocation ha;
6166 ASSERT(args.length() == 2);
6167
6168 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6169 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006170 return isolate->heap()->NumberFromInt32(x | y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006171}
6172
6173
Ben Murdoch8b112d22011-06-08 16:22:53 +01006174RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006175 NoHandleAllocation ha;
6176 ASSERT(args.length() == 2);
6177
6178 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6179 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006180 return isolate->heap()->NumberFromInt32(x & y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006181}
6182
6183
Ben Murdoch8b112d22011-06-08 16:22:53 +01006184RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006185 NoHandleAllocation ha;
6186 ASSERT(args.length() == 2);
6187
6188 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6189 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006190 return isolate->heap()->NumberFromInt32(x ^ y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006191}
6192
6193
Ben Murdoch8b112d22011-06-08 16:22:53 +01006194RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006195 NoHandleAllocation ha;
6196 ASSERT(args.length() == 1);
6197
6198 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006199 return isolate->heap()->NumberFromInt32(~x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006200}
6201
6202
Ben Murdoch8b112d22011-06-08 16:22:53 +01006203RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006204 NoHandleAllocation ha;
6205 ASSERT(args.length() == 2);
6206
6207 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6208 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006209 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00006210}
6211
6212
Ben Murdoch8b112d22011-06-08 16:22:53 +01006213RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006214 NoHandleAllocation ha;
6215 ASSERT(args.length() == 2);
6216
6217 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6218 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006219 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00006220}
6221
6222
Ben Murdoch8b112d22011-06-08 16:22:53 +01006223RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 2);
6226
6227 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6228 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006229 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
Steve Blocka7e24c12009-10-30 11:49:00 +00006230}
6231
6232
Ben Murdoch8b112d22011-06-08 16:22:53 +01006233RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006234 NoHandleAllocation ha;
6235 ASSERT(args.length() == 2);
6236
6237 CONVERT_DOUBLE_CHECKED(x, args[0]);
6238 CONVERT_DOUBLE_CHECKED(y, args[1]);
6239 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6240 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6241 if (x == y) return Smi::FromInt(EQUAL);
6242 Object* result;
6243 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6244 result = Smi::FromInt(EQUAL);
6245 } else {
6246 result = Smi::FromInt(NOT_EQUAL);
6247 }
6248 return result;
6249}
6250
6251
Ben Murdoch8b112d22011-06-08 16:22:53 +01006252RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006253 NoHandleAllocation ha;
6254 ASSERT(args.length() == 2);
6255
6256 CONVERT_CHECKED(String, x, args[0]);
6257 CONVERT_CHECKED(String, y, args[1]);
6258
6259 bool not_equal = !x->Equals(y);
6260 // This is slightly convoluted because the value that signifies
6261 // equality is 0 and inequality is 1 so we have to negate the result
6262 // from String::Equals.
6263 ASSERT(not_equal == 0 || not_equal == 1);
6264 STATIC_CHECK(EQUAL == 0);
6265 STATIC_CHECK(NOT_EQUAL == 1);
6266 return Smi::FromInt(not_equal);
6267}
6268
6269
Ben Murdoch8b112d22011-06-08 16:22:53 +01006270RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006271 NoHandleAllocation ha;
6272 ASSERT(args.length() == 3);
6273
6274 CONVERT_DOUBLE_CHECKED(x, args[0]);
6275 CONVERT_DOUBLE_CHECKED(y, args[1]);
6276 if (isnan(x) || isnan(y)) return args[2];
6277 if (x == y) return Smi::FromInt(EQUAL);
6278 if (isless(x, y)) return Smi::FromInt(LESS);
6279 return Smi::FromInt(GREATER);
6280}
6281
6282
6283// Compare two Smis as if they were converted to strings and then
6284// compared lexicographically.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006285RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006286 NoHandleAllocation ha;
6287 ASSERT(args.length() == 2);
6288
Steve Blocka7e24c12009-10-30 11:49:00 +00006289 // Extract the integer values from the Smis.
6290 CONVERT_CHECKED(Smi, x, args[0]);
6291 CONVERT_CHECKED(Smi, y, args[1]);
6292 int x_value = x->value();
6293 int y_value = y->value();
6294
6295 // If the integers are equal so are the string representations.
6296 if (x_value == y_value) return Smi::FromInt(EQUAL);
6297
6298 // If one of the integers are zero the normal integer order is the
6299 // same as the lexicographic order of the string representations.
6300 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6301
6302 // If only one of the integers is negative the negative number is
6303 // smallest because the char code of '-' is less than the char code
6304 // of any digit. Otherwise, we make both values positive.
6305 if (x_value < 0 || y_value < 0) {
6306 if (y_value >= 0) return Smi::FromInt(LESS);
6307 if (x_value >= 0) return Smi::FromInt(GREATER);
6308 x_value = -x_value;
6309 y_value = -y_value;
6310 }
6311
Steve Block44f0eee2011-05-26 01:26:41 +01006312 // Arrays for the individual characters of the two Smis. Smis are
6313 // 31 bit integers and 10 decimal digits are therefore enough.
6314 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6315 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6316 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6317
6318
Steve Blocka7e24c12009-10-30 11:49:00 +00006319 // Convert the integers to arrays of their decimal digits.
6320 int x_index = 0;
6321 int y_index = 0;
6322 while (x_value > 0) {
6323 x_elms[x_index++] = x_value % 10;
6324 x_value /= 10;
6325 }
6326 while (y_value > 0) {
6327 y_elms[y_index++] = y_value % 10;
6328 y_value /= 10;
6329 }
6330
6331 // Loop through the arrays of decimal digits finding the first place
6332 // where they differ.
6333 while (--x_index >= 0 && --y_index >= 0) {
6334 int diff = x_elms[x_index] - y_elms[y_index];
6335 if (diff != 0) return Smi::FromInt(diff);
6336 }
6337
6338 // If one array is a suffix of the other array, the longest array is
6339 // the representation of the largest of the Smis in the
6340 // lexicographic ordering.
6341 return Smi::FromInt(x_index - y_index);
6342}
6343
6344
Steve Block44f0eee2011-05-26 01:26:41 +01006345static Object* StringInputBufferCompare(RuntimeState* state,
6346 String* x,
6347 String* y) {
6348 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6349 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
Steve Block6ded16b2010-05-10 14:33:55 +01006350 bufx.Reset(x);
6351 bufy.Reset(y);
6352 while (bufx.has_more() && bufy.has_more()) {
6353 int d = bufx.GetNext() - bufy.GetNext();
6354 if (d < 0) return Smi::FromInt(LESS);
6355 else if (d > 0) return Smi::FromInt(GREATER);
6356 }
6357
6358 // x is (non-trivial) prefix of y:
6359 if (bufy.has_more()) return Smi::FromInt(LESS);
6360 // y is prefix of x:
6361 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6362}
6363
6364
6365static Object* FlatStringCompare(String* x, String* y) {
6366 ASSERT(x->IsFlat());
6367 ASSERT(y->IsFlat());
6368 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6369 int prefix_length = x->length();
6370 if (y->length() < prefix_length) {
6371 prefix_length = y->length();
6372 equal_prefix_result = Smi::FromInt(GREATER);
6373 } else if (y->length() > prefix_length) {
6374 equal_prefix_result = Smi::FromInt(LESS);
6375 }
6376 int r;
6377 if (x->IsAsciiRepresentation()) {
6378 Vector<const char> x_chars = x->ToAsciiVector();
6379 if (y->IsAsciiRepresentation()) {
6380 Vector<const char> y_chars = y->ToAsciiVector();
6381 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6382 } else {
6383 Vector<const uc16> y_chars = y->ToUC16Vector();
6384 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6385 }
6386 } else {
6387 Vector<const uc16> x_chars = x->ToUC16Vector();
6388 if (y->IsAsciiRepresentation()) {
6389 Vector<const char> y_chars = y->ToAsciiVector();
6390 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6391 } else {
6392 Vector<const uc16> y_chars = y->ToUC16Vector();
6393 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6394 }
6395 }
6396 Object* result;
6397 if (r == 0) {
6398 result = equal_prefix_result;
6399 } else {
6400 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6401 }
Steve Block44f0eee2011-05-26 01:26:41 +01006402 ASSERT(result ==
6403 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
Steve Block6ded16b2010-05-10 14:33:55 +01006404 return result;
6405}
6406
6407
Ben Murdoch8b112d22011-06-08 16:22:53 +01006408RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006409 NoHandleAllocation ha;
6410 ASSERT(args.length() == 2);
6411
6412 CONVERT_CHECKED(String, x, args[0]);
6413 CONVERT_CHECKED(String, y, args[1]);
6414
Steve Block44f0eee2011-05-26 01:26:41 +01006415 isolate->counters()->string_compare_runtime()->Increment();
Leon Clarkee46be812010-01-19 14:06:41 +00006416
Steve Blocka7e24c12009-10-30 11:49:00 +00006417 // A few fast case tests before we flatten.
6418 if (x == y) return Smi::FromInt(EQUAL);
6419 if (y->length() == 0) {
6420 if (x->length() == 0) return Smi::FromInt(EQUAL);
6421 return Smi::FromInt(GREATER);
6422 } else if (x->length() == 0) {
6423 return Smi::FromInt(LESS);
6424 }
6425
6426 int d = x->Get(0) - y->Get(0);
6427 if (d < 0) return Smi::FromInt(LESS);
6428 else if (d > 0) return Smi::FromInt(GREATER);
6429
John Reck59135872010-11-02 12:39:01 -07006430 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006431 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
John Reck59135872010-11-02 12:39:01 -07006432 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6433 }
Steve Block44f0eee2011-05-26 01:26:41 +01006434 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
John Reck59135872010-11-02 12:39:01 -07006435 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6436 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006437
Steve Block6ded16b2010-05-10 14:33:55 +01006438 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
Steve Block44f0eee2011-05-26 01:26:41 +01006439 : StringInputBufferCompare(isolate->runtime_state(), x, y);
Steve Blocka7e24c12009-10-30 11:49:00 +00006440}
6441
6442
Ben Murdoch8b112d22011-06-08 16:22:53 +01006443RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006444 NoHandleAllocation ha;
6445 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006446 isolate->counters()->math_acos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006447
6448 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006449 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006450}
6451
6452
Ben Murdoch8b112d22011-06-08 16:22:53 +01006453RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006454 NoHandleAllocation ha;
6455 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006456 isolate->counters()->math_asin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006457
6458 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006459 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006460}
6461
6462
Ben Murdoch8b112d22011-06-08 16:22:53 +01006463RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006466 isolate->counters()->math_atan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006467
6468 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006469 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006470}
6471
6472
Steve Block44f0eee2011-05-26 01:26:41 +01006473static const double kPiDividedBy4 = 0.78539816339744830962;
6474
6475
Ben Murdoch8b112d22011-06-08 16:22:53 +01006476RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01006479 isolate->counters()->math_atan2()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006480
6481 CONVERT_DOUBLE_CHECKED(x, args[0]);
6482 CONVERT_DOUBLE_CHECKED(y, args[1]);
6483 double result;
6484 if (isinf(x) && isinf(y)) {
6485 // Make sure that the result in case of two infinite arguments
6486 // is a multiple of Pi / 4. The sign of the result is determined
6487 // by the first argument (x) and the sign of the second argument
6488 // determines the multiplier: one or three.
Steve Blocka7e24c12009-10-30 11:49:00 +00006489 int multiplier = (x < 0) ? -1 : 1;
6490 if (y < 0) multiplier *= 3;
6491 result = multiplier * kPiDividedBy4;
6492 } else {
6493 result = atan2(x, y);
6494 }
Steve Block44f0eee2011-05-26 01:26:41 +01006495 return isolate->heap()->AllocateHeapNumber(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00006496}
6497
6498
Ben Murdoch8b112d22011-06-08 16:22:53 +01006499RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006500 NoHandleAllocation ha;
6501 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006502 isolate->counters()->math_ceil()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006503
6504 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006505 return isolate->heap()->NumberFromDouble(ceiling(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00006506}
6507
6508
Ben Murdoch8b112d22011-06-08 16:22:53 +01006509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006510 NoHandleAllocation ha;
6511 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006512 isolate->counters()->math_cos()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006513
6514 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006515 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006516}
6517
6518
Ben Murdoch8b112d22011-06-08 16:22:53 +01006519RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006520 NoHandleAllocation ha;
6521 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006522 isolate->counters()->math_exp()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006523
6524 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006525 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006526}
6527
6528
Ben Murdoch8b112d22011-06-08 16:22:53 +01006529RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006530 NoHandleAllocation ha;
6531 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006532 isolate->counters()->math_floor()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006533
6534 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006535 return isolate->heap()->NumberFromDouble(floor(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00006536}
6537
6538
Ben Murdoch8b112d22011-06-08 16:22:53 +01006539RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006540 NoHandleAllocation ha;
6541 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006542 isolate->counters()->math_log()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006543
6544 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006545 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006546}
6547
6548
Ben Murdoch8b112d22011-06-08 16:22:53 +01006549RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006550 NoHandleAllocation ha;
6551 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01006552 isolate->counters()->math_pow()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006553
6554 CONVERT_DOUBLE_CHECKED(x, args[0]);
6555
6556 // If the second argument is a smi, it is much faster to call the
6557 // custom powi() function than the generic pow().
6558 if (args[1]->IsSmi()) {
6559 int y = Smi::cast(args[1])->value();
Steve Block44f0eee2011-05-26 01:26:41 +01006560 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00006561 }
6562
6563 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01006564 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00006565}
6566
Steve Block6ded16b2010-05-10 14:33:55 +01006567// Fast version of Math.pow if we know that y is not an integer and
6568// y is not -0.5 or 0.5. Used as slowcase from codegen.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006569RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
Steve Block6ded16b2010-05-10 14:33:55 +01006570 NoHandleAllocation ha;
6571 ASSERT(args.length() == 2);
6572 CONVERT_DOUBLE_CHECKED(x, args[0]);
6573 CONVERT_DOUBLE_CHECKED(y, args[1]);
6574 if (y == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006575 return Smi::FromInt(1);
Steve Block6ded16b2010-05-10 14:33:55 +01006576 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
Steve Block44f0eee2011-05-26 01:26:41 +01006577 return isolate->heap()->nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01006578 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006579 return isolate->heap()->AllocateHeapNumber(pow(x, y));
Steve Block6ded16b2010-05-10 14:33:55 +01006580 }
6581}
Steve Blocka7e24c12009-10-30 11:49:00 +00006582
Steve Block6ded16b2010-05-10 14:33:55 +01006583
Ben Murdoch8b112d22011-06-08 16:22:53 +01006584RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006585 NoHandleAllocation ha;
6586 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006587 isolate->counters()->math_round()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006588
Steve Block6ded16b2010-05-10 14:33:55 +01006589 if (!args[0]->IsHeapNumber()) {
6590 // Must be smi. Return the argument unchanged for all the other types
6591 // to make fuzz-natives test happy.
6592 return args[0];
6593 }
6594
6595 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6596
6597 double value = number->value();
6598 int exponent = number->get_exponent();
6599 int sign = number->get_sign();
6600
Steve Block053d10c2011-06-13 19:13:29 +01006601 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6602 // should be rounded to 2^30, which is not smi.
6603 if (!sign && exponent <= kSmiValueSize - 3) {
Steve Block6ded16b2010-05-10 14:33:55 +01006604 return Smi::FromInt(static_cast<int>(value + 0.5));
6605 }
6606
6607 // If the magnitude is big enough, there's no place for fraction part. If we
6608 // try to add 0.5 to this number, 1.0 will be added instead.
6609 if (exponent >= 52) {
6610 return number;
6611 }
6612
Steve Block44f0eee2011-05-26 01:26:41 +01006613 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
Steve Block6ded16b2010-05-10 14:33:55 +01006614
6615 // Do not call NumberFromDouble() to avoid extra checks.
Steve Block44f0eee2011-05-26 01:26:41 +01006616 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
Steve Blocka7e24c12009-10-30 11:49:00 +00006617}
6618
6619
Ben Murdoch8b112d22011-06-08 16:22:53 +01006620RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006621 NoHandleAllocation ha;
6622 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006623 isolate->counters()->math_sin()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006624
6625 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006626 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006627}
6628
6629
Ben Murdoch8b112d22011-06-08 16:22:53 +01006630RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006631 NoHandleAllocation ha;
6632 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006633 isolate->counters()->math_sqrt()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006634
6635 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006636 return isolate->heap()->AllocateHeapNumber(sqrt(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00006637}
6638
6639
Ben Murdoch8b112d22011-06-08 16:22:53 +01006640RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006641 NoHandleAllocation ha;
6642 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01006643 isolate->counters()->math_tan()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006644
6645 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01006646 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
Steve Blocka7e24c12009-10-30 11:49:00 +00006647}
6648
6649
Steve Block6ded16b2010-05-10 14:33:55 +01006650static int MakeDay(int year, int month, int day) {
6651 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6652 181, 212, 243, 273, 304, 334};
6653 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6654 182, 213, 244, 274, 305, 335};
6655
6656 year += month / 12;
6657 month %= 12;
6658 if (month < 0) {
6659 year--;
6660 month += 12;
6661 }
6662
6663 ASSERT(month >= 0);
6664 ASSERT(month < 12);
6665
6666 // year_delta is an arbitrary number such that:
6667 // a) year_delta = -1 (mod 400)
6668 // b) year + year_delta > 0 for years in the range defined by
6669 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6670 // Jan 1 1970. This is required so that we don't run into integer
6671 // division of negative numbers.
6672 // c) there shouldn't be an overflow for 32-bit integers in the following
6673 // operations.
6674 static const int year_delta = 399999;
6675 static const int base_day = 365 * (1970 + year_delta) +
6676 (1970 + year_delta) / 4 -
6677 (1970 + year_delta) / 100 +
6678 (1970 + year_delta) / 400;
6679
6680 int year1 = year + year_delta;
6681 int day_from_year = 365 * year1 +
6682 year1 / 4 -
6683 year1 / 100 +
6684 year1 / 400 -
6685 base_day;
6686
6687 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
6688 return day_from_year + day_from_month[month] + day - 1;
6689 }
6690
6691 return day_from_year + day_from_month_leap[month] + day - 1;
6692}
6693
6694
Ben Murdoch8b112d22011-06-08 16:22:53 +01006695RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
Steve Block6ded16b2010-05-10 14:33:55 +01006696 NoHandleAllocation ha;
6697 ASSERT(args.length() == 3);
6698
6699 CONVERT_SMI_CHECKED(year, args[0]);
6700 CONVERT_SMI_CHECKED(month, args[1]);
6701 CONVERT_SMI_CHECKED(date, args[2]);
6702
6703 return Smi::FromInt(MakeDay(year, month, date));
6704}
6705
6706
6707static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6708static const int kDaysIn4Years = 4 * 365 + 1;
6709static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6710static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6711static const int kDays1970to2000 = 30 * 365 + 7;
6712static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6713 kDays1970to2000;
6714static const int kYearsOffset = 400000;
6715
6716static const char kDayInYear[] = {
6717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6718 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6720 22, 23, 24, 25, 26, 27, 28,
6721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6722 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6724 22, 23, 24, 25, 26, 27, 28, 29, 30,
6725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6726 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6728 22, 23, 24, 25, 26, 27, 28, 29, 30,
6729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6730 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6732 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6734 22, 23, 24, 25, 26, 27, 28, 29, 30,
6735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6736 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6738 22, 23, 24, 25, 26, 27, 28, 29, 30,
6739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6740 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6741
6742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6743 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6745 22, 23, 24, 25, 26, 27, 28,
6746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6747 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6749 22, 23, 24, 25, 26, 27, 28, 29, 30,
6750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6751 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6753 22, 23, 24, 25, 26, 27, 28, 29, 30,
6754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6755 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6757 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6759 22, 23, 24, 25, 26, 27, 28, 29, 30,
6760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6761 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6763 22, 23, 24, 25, 26, 27, 28, 29, 30,
6764 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6765 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6766
6767 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6768 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6769 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6770 22, 23, 24, 25, 26, 27, 28, 29,
6771 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6772 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6773 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6774 22, 23, 24, 25, 26, 27, 28, 29, 30,
6775 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6776 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6777 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6778 22, 23, 24, 25, 26, 27, 28, 29, 30,
6779 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6780 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6781 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6782 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6783 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6784 22, 23, 24, 25, 26, 27, 28, 29, 30,
6785 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6786 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6787 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6788 22, 23, 24, 25, 26, 27, 28, 29, 30,
6789 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6790 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6791
6792 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6793 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6794 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6795 22, 23, 24, 25, 26, 27, 28,
6796 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6797 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6798 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6799 22, 23, 24, 25, 26, 27, 28, 29, 30,
6800 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6801 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6802 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6803 22, 23, 24, 25, 26, 27, 28, 29, 30,
6804 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6805 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6806 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6807 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6808 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6809 22, 23, 24, 25, 26, 27, 28, 29, 30,
6810 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6811 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6812 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6813 22, 23, 24, 25, 26, 27, 28, 29, 30,
6814 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6815 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6816
6817static const char kMonthInYear[] = {
6818 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,
6819 0, 0, 0, 0, 0, 0,
6820 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,
6821 1, 1, 1,
6822 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,
6823 2, 2, 2, 2, 2, 2,
6824 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,
6825 3, 3, 3, 3, 3,
6826 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,
6827 4, 4, 4, 4, 4, 4,
6828 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,
6829 5, 5, 5, 5, 5,
6830 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,
6831 6, 6, 6, 6, 6, 6,
6832 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,
6833 7, 7, 7, 7, 7, 7,
6834 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,
6835 8, 8, 8, 8, 8,
6836 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,
6837 9, 9, 9, 9, 9, 9,
6838 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6839 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6840 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6841 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6842
6843 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,
6844 0, 0, 0, 0, 0, 0,
6845 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,
6846 1, 1, 1,
6847 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,
6848 2, 2, 2, 2, 2, 2,
6849 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,
6850 3, 3, 3, 3, 3,
6851 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,
6852 4, 4, 4, 4, 4, 4,
6853 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,
6854 5, 5, 5, 5, 5,
6855 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,
6856 6, 6, 6, 6, 6, 6,
6857 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,
6858 7, 7, 7, 7, 7, 7,
6859 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,
6860 8, 8, 8, 8, 8,
6861 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,
6862 9, 9, 9, 9, 9, 9,
6863 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6864 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6865 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6866 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6867
6868 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,
6869 0, 0, 0, 0, 0, 0,
6870 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,
6871 1, 1, 1, 1,
6872 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,
6873 2, 2, 2, 2, 2, 2,
6874 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,
6875 3, 3, 3, 3, 3,
6876 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,
6877 4, 4, 4, 4, 4, 4,
6878 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,
6879 5, 5, 5, 5, 5,
6880 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,
6881 6, 6, 6, 6, 6, 6,
6882 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,
6883 7, 7, 7, 7, 7, 7,
6884 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,
6885 8, 8, 8, 8, 8,
6886 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,
6887 9, 9, 9, 9, 9, 9,
6888 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6889 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6890 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6891 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6892
6893 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,
6894 0, 0, 0, 0, 0, 0,
6895 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,
6896 1, 1, 1,
6897 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,
6898 2, 2, 2, 2, 2, 2,
6899 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,
6900 3, 3, 3, 3, 3,
6901 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,
6902 4, 4, 4, 4, 4, 4,
6903 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,
6904 5, 5, 5, 5, 5,
6905 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,
6906 6, 6, 6, 6, 6, 6,
6907 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,
6908 7, 7, 7, 7, 7, 7,
6909 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,
6910 8, 8, 8, 8, 8,
6911 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,
6912 9, 9, 9, 9, 9, 9,
6913 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6914 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6915 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6916 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6917
6918
6919// This function works for dates from 1970 to 2099.
6920static inline void DateYMDFromTimeAfter1970(int date,
6921 int& year, int& month, int& day) {
6922#ifdef DEBUG
6923 int save_date = date; // Need this for ASSERT in the end.
6924#endif
6925
6926 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6927 date %= kDaysIn4Years;
6928
6929 month = kMonthInYear[date];
6930 day = kDayInYear[date];
6931
6932 ASSERT(MakeDay(year, month, day) == save_date);
6933}
6934
6935
6936static inline void DateYMDFromTimeSlow(int date,
6937 int& year, int& month, int& day) {
6938#ifdef DEBUG
6939 int save_date = date; // Need this for ASSERT in the end.
6940#endif
6941
6942 date += kDaysOffset;
6943 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6944 date %= kDaysIn400Years;
6945
6946 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6947
6948 date--;
6949 int yd1 = date / kDaysIn100Years;
6950 date %= kDaysIn100Years;
6951 year += 100 * yd1;
6952
6953 date++;
6954 int yd2 = date / kDaysIn4Years;
6955 date %= kDaysIn4Years;
6956 year += 4 * yd2;
6957
6958 date--;
6959 int yd3 = date / 365;
6960 date %= 365;
6961 year += yd3;
6962
6963 bool is_leap = (!yd1 || yd2) && !yd3;
6964
6965 ASSERT(date >= -1);
6966 ASSERT(is_leap || (date >= 0));
6967 ASSERT((date < 365) || (is_leap && (date < 366)));
6968 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6969 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6970 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
6971
6972 if (is_leap) {
6973 day = kDayInYear[2*365 + 1 + date];
6974 month = kMonthInYear[2*365 + 1 + date];
6975 } else {
6976 day = kDayInYear[date];
6977 month = kMonthInYear[date];
6978 }
6979
6980 ASSERT(MakeDay(year, month, day) == save_date);
6981}
6982
6983
6984static inline void DateYMDFromTime(int date,
6985 int& year, int& month, int& day) {
6986 if (date >= 0 && date < 32 * kDaysIn4Years) {
6987 DateYMDFromTimeAfter1970(date, year, month, day);
6988 } else {
6989 DateYMDFromTimeSlow(date, year, month, day);
6990 }
6991}
6992
6993
Ben Murdoch8b112d22011-06-08 16:22:53 +01006994RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
Steve Block6ded16b2010-05-10 14:33:55 +01006995 NoHandleAllocation ha;
6996 ASSERT(args.length() == 2);
6997
6998 CONVERT_DOUBLE_CHECKED(t, args[0]);
6999 CONVERT_CHECKED(JSArray, res_array, args[1]);
7000
7001 int year, month, day;
7002 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7003
Steve Block44f0eee2011-05-26 01:26:41 +01007004 RUNTIME_ASSERT(res_array->elements()->map() ==
7005 isolate->heap()->fixed_array_map());
Iain Merrick75681382010-08-19 15:07:18 +01007006 FixedArray* elms = FixedArray::cast(res_array->elements());
7007 RUNTIME_ASSERT(elms->length() == 3);
7008
7009 elms->set(0, Smi::FromInt(year));
7010 elms->set(1, Smi::FromInt(month));
7011 elms->set(2, Smi::FromInt(day));
Steve Block6ded16b2010-05-10 14:33:55 +01007012
Steve Block44f0eee2011-05-26 01:26:41 +01007013 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007014}
7015
7016
Ben Murdoch8b112d22011-06-08 16:22:53 +01007017RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007018 NoHandleAllocation ha;
7019 ASSERT(args.length() == 3);
7020
7021 JSFunction* callee = JSFunction::cast(args[0]);
7022 Object** parameters = reinterpret_cast<Object**>(args[1]);
7023 const int length = Smi::cast(args[2])->value();
7024
John Reck59135872010-11-02 12:39:01 -07007025 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01007026 { MaybeObject* maybe_result =
7027 isolate->heap()->AllocateArgumentsObject(callee, length);
John Reck59135872010-11-02 12:39:01 -07007028 if (!maybe_result->ToObject(&result)) return maybe_result;
7029 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007030 // Allocate the elements if needed.
7031 if (length > 0) {
7032 // Allocate the fixed array.
John Reck59135872010-11-02 12:39:01 -07007033 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007034 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07007035 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7036 }
Leon Clarke4515c472010-02-03 11:58:03 +00007037
7038 AssertNoAllocation no_gc;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007039 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007040 array->set_map(isolate->heap()->fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00007041 array->set_length(length);
Leon Clarke4515c472010-02-03 11:58:03 +00007042
7043 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007044 for (int i = 0; i < length; i++) {
7045 array->set(i, *--parameters, mode);
7046 }
Steve Blockd0582a62009-12-15 09:54:21 +00007047 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00007048 }
7049 return result;
7050}
7051
7052
Ben Murdoch8b112d22011-06-08 16:22:53 +01007053RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
Steve Block44f0eee2011-05-26 01:26:41 +01007054 HandleScope scope(isolate);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007055 ASSERT(args.length() == 3);
Steve Block3ce2e202009-11-05 08:53:23 +00007056 CONVERT_ARG_CHECKED(Context, context, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01007057 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007058 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
Steve Blocka7e24c12009-10-30 11:49:00 +00007059
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007060 // Allocate global closures in old space and allocate local closures
7061 // in new space. Additionally pretenure closures that are assigned
7062 // directly to properties.
7063 pretenure = pretenure || (context->global_context() == *context);
7064 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +00007065 Handle<JSFunction> result =
Steve Block44f0eee2011-05-26 01:26:41 +01007066 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7067 context,
7068 pretenure_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00007069 return *result;
7070}
7071
Ben Murdoch8b112d22011-06-08 16:22:53 +01007072
7073static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7074 int* total_argc) {
7075 // Find frame containing arguments passed to the caller.
7076 JavaScriptFrameIterator it;
7077 JavaScriptFrame* frame = it.frame();
7078 List<JSFunction*> functions(2);
7079 frame->GetFunctions(&functions);
7080 if (functions.length() > 1) {
7081 int inlined_frame_index = functions.length() - 1;
7082 JSFunction* inlined_function = functions[inlined_frame_index];
7083 int args_count = inlined_function->shared()->formal_parameter_count();
7084 ScopedVector<SlotRef> args_slots(args_count);
7085 SlotRef::ComputeSlotMappingForArguments(frame,
7086 inlined_frame_index,
7087 &args_slots);
7088
7089 *total_argc = bound_argc + args_count;
7090 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7091 for (int i = 0; i < args_count; i++) {
7092 Handle<Object> val = args_slots[i].GetValue();
7093 param_data[bound_argc + i] = val.location();
7094 }
7095 return param_data;
7096 } else {
7097 it.AdvanceToArgumentsFrame();
7098 frame = it.frame();
7099 int args_count = frame->ComputeParametersCount();
7100
7101 *total_argc = bound_argc + args_count;
7102 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7103 for (int i = 0; i < args_count; i++) {
7104 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7105 param_data[bound_argc + i] = val.location();
7106 }
7107 return param_data;
7108 }
7109}
7110
7111
7112RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
Steve Block44f0eee2011-05-26 01:26:41 +01007113 HandleScope scope(isolate);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007114 ASSERT(args.length() == 2);
Steve Block1e0659c2011-05-24 12:43:12 +01007115 // First argument is a function to use as a constructor.
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007116 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007117
Steve Block1e0659c2011-05-24 12:43:12 +01007118 // Second argument is either null or an array of bound arguments.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007119 Handle<FixedArray> bound_args;
Steve Block1e0659c2011-05-24 12:43:12 +01007120 int bound_argc = 0;
7121 if (!args[1]->IsNull()) {
7122 CONVERT_ARG_CHECKED(JSArray, params, 1);
7123 RUNTIME_ASSERT(params->HasFastElements());
Ben Murdoch8b112d22011-06-08 16:22:53 +01007124 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
Steve Block1e0659c2011-05-24 12:43:12 +01007125 bound_argc = Smi::cast(params->length())->value();
7126 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007127
Ben Murdoch8b112d22011-06-08 16:22:53 +01007128 int total_argc = 0;
7129 SmartPointer<Object**> param_data =
7130 GetNonBoundArguments(bound_argc, &total_argc);
Steve Block1e0659c2011-05-24 12:43:12 +01007131 for (int i = 0; i < bound_argc; i++) {
7132 Handle<Object> val = Handle<Object>(bound_args->get(i));
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007133 param_data[i] = val.location();
7134 }
7135
Ben Murdochbb769b22010-08-11 14:56:33 +01007136 bool exception = false;
Steve Block1e0659c2011-05-24 12:43:12 +01007137 Handle<Object> result =
7138 Execution::New(function, total_argc, *param_data, &exception);
Ben Murdochbb769b22010-08-11 14:56:33 +01007139 if (exception) {
7140 return Failure::Exception();
7141 }
Steve Block1e0659c2011-05-24 12:43:12 +01007142
Ben Murdochbb769b22010-08-11 14:56:33 +01007143 ASSERT(!result.is_null());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01007144 return *result;
7145}
7146
Steve Blocka7e24c12009-10-30 11:49:00 +00007147
Steve Block44f0eee2011-05-26 01:26:41 +01007148static void TrySettingInlineConstructStub(Isolate* isolate,
7149 Handle<JSFunction> function) {
7150 Handle<Object> prototype = isolate->factory()->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00007151 if (function->has_instance_prototype()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007152 prototype = Handle<Object>(function->instance_prototype(), isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00007153 }
7154 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007155 ConstructStubCompiler compiler;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007156 MaybeObject* code = compiler.CompileConstructStub(*function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007157 if (!code->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07007158 function->shared()->set_construct_stub(
7159 Code::cast(code->ToObjectUnchecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007160 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007161 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007162}
7163
7164
Ben Murdoch8b112d22011-06-08 16:22:53 +01007165RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
Steve Block44f0eee2011-05-26 01:26:41 +01007166 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007167 ASSERT(args.length() == 1);
7168
7169 Handle<Object> constructor = args.at<Object>(0);
7170
7171 // If the constructor isn't a proper function we throw a type error.
7172 if (!constructor->IsJSFunction()) {
7173 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7174 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007175 isolate->factory()->NewTypeError("not_constructor", arguments);
7176 return isolate->Throw(*type_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00007177 }
7178
7179 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
Steve Block6ded16b2010-05-10 14:33:55 +01007180
7181 // If function should not have prototype, construction is not allowed. In this
7182 // case generated code bailouts here, since function has no initial_map.
7183 if (!function->should_have_prototype()) {
7184 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7185 Handle<Object> type_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007186 isolate->factory()->NewTypeError("not_constructor", arguments);
7187 return isolate->Throw(*type_error);
Steve Block6ded16b2010-05-10 14:33:55 +01007188 }
7189
Steve Blocka7e24c12009-10-30 11:49:00 +00007190#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01007191 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00007192 // Handle stepping into constructors if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01007193 if (debug->StepInActive()) {
7194 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007195 }
7196#endif
7197
7198 if (function->has_initial_map()) {
7199 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
7200 // The 'Function' function ignores the receiver object when
7201 // called using 'new' and creates a new JSFunction object that
7202 // is returned. The receiver object is only used for error
7203 // reporting if an error occurs when constructing the new
Steve Block44f0eee2011-05-26 01:26:41 +01007204 // JSFunction. FACTORY->NewJSObject() should not be used to
Steve Blocka7e24c12009-10-30 11:49:00 +00007205 // allocate JSFunctions since it does not properly initialize
7206 // the shared part of the function. Since the receiver is
7207 // ignored anyway, we use the global object as the receiver
7208 // instead of a new JSFunction object. This way, errors are
7209 // reported the same way whether or not 'Function' is called
7210 // using 'new'.
Steve Block44f0eee2011-05-26 01:26:41 +01007211 return isolate->context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00007212 }
7213 }
7214
Ben Murdochb0fe1622011-05-05 13:52:32 +01007215 // The function should be compiled for the optimization hints to be
7216 // available. We cannot use EnsureCompiled because that forces a
7217 // compilation through the shared function info which makes it
7218 // impossible for us to optimize.
Steve Block44f0eee2011-05-26 01:26:41 +01007219 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007220 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +00007221
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007222 if (!function->has_initial_map() &&
7223 shared->IsInobjectSlackTrackingInProgress()) {
7224 // The tracking is already in progress for another function. We can only
7225 // track one initial_map at a time, so we force the completion before the
7226 // function is called as a constructor for the first time.
7227 shared->CompleteInobjectSlackTracking();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007228 }
7229
7230 bool first_allocation = !shared->live_objects_may_exist();
Steve Block44f0eee2011-05-26 01:26:41 +01007231 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7232 RETURN_IF_EMPTY_HANDLE(isolate, result);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007233 // Delay setting the stub if inobject slack tracking is in progress.
7234 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007235 TrySettingInlineConstructStub(isolate, function);
Steve Blocka7e24c12009-10-30 11:49:00 +00007236 }
7237
Steve Block44f0eee2011-05-26 01:26:41 +01007238 isolate->counters()->constructed_objects()->Increment();
7239 isolate->counters()->constructed_objects_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00007240
7241 return *result;
7242}
7243
7244
Ben Murdoch8b112d22011-06-08 16:22:53 +01007245RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
Steve Block44f0eee2011-05-26 01:26:41 +01007246 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007247 ASSERT(args.length() == 1);
7248
7249 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7250 function->shared()->CompleteInobjectSlackTracking();
Steve Block44f0eee2011-05-26 01:26:41 +01007251 TrySettingInlineConstructStub(isolate, function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007252
Steve Block44f0eee2011-05-26 01:26:41 +01007253 return isolate->heap()->undefined_value();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007254}
7255
7256
Ben Murdoch8b112d22011-06-08 16:22:53 +01007257RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01007258 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007259 ASSERT(args.length() == 1);
7260
7261 Handle<JSFunction> function = args.at<JSFunction>(0);
7262#ifdef DEBUG
Iain Merrick75681382010-08-19 15:07:18 +01007263 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007264 PrintF("[lazy: ");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007265 function->PrintName();
Steve Blocka7e24c12009-10-30 11:49:00 +00007266 PrintF("]\n");
7267 }
7268#endif
7269
7270 // Compile the target function. Here we compile using CompileLazyInLoop in
7271 // order to get the optimized version. This helps code like delta-blue
7272 // that calls performance-critical routines through constructors. A
7273 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7274 // direct call. Since the in-loop tracking takes place through CallICs
7275 // this means that things called through constructors are never known to
7276 // be in loops. We compile them as if they are in loops here just in case.
7277 ASSERT(!function->is_compiled());
Ben Murdochf87a2032010-10-22 12:50:53 +01007278 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007279 return Failure::Exception();
7280 }
7281
Ben Murdochb0fe1622011-05-05 13:52:32 +01007282 // All done. Return the compiled code.
7283 ASSERT(function->is_compiled());
Steve Blocka7e24c12009-10-30 11:49:00 +00007284 return function->code();
7285}
7286
7287
Ben Murdoch8b112d22011-06-08 16:22:53 +01007288RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
Steve Block44f0eee2011-05-26 01:26:41 +01007289 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007290 ASSERT(args.length() == 1);
7291 Handle<JSFunction> function = args.at<JSFunction>(0);
7292 // If the function is not optimizable or debugger is active continue using the
7293 // code from the full compiler.
7294 if (!function->shared()->code()->optimizable() ||
Steve Block44f0eee2011-05-26 01:26:41 +01007295 isolate->debug()->has_break_points()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +01007296 if (FLAG_trace_opt) {
7297 PrintF("[failed to optimize ");
7298 function->PrintName();
7299 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7300 function->shared()->code()->optimizable() ? "T" : "F",
Steve Block44f0eee2011-05-26 01:26:41 +01007301 isolate->debug()->has_break_points() ? "T" : "F");
Ben Murdochb8e0da22011-05-16 14:20:40 +01007302 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007303 function->ReplaceCode(function->shared()->code());
7304 return function->code();
7305 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007306 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007307 return function->code();
7308 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01007309 if (FLAG_trace_opt) {
7310 PrintF("[failed to optimize ");
7311 function->PrintName();
7312 PrintF(": optimized compilation failed]\n");
7313 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007314 function->ReplaceCode(function->shared()->code());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007315 return function->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007316}
7317
7318
Ben Murdoch8b112d22011-06-08 16:22:53 +01007319RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
Steve Block44f0eee2011-05-26 01:26:41 +01007320 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007321 ASSERT(args.length() == 1);
7322 RUNTIME_ASSERT(args[0]->IsSmi());
7323 Deoptimizer::BailoutType type =
7324 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
Steve Block44f0eee2011-05-26 01:26:41 +01007325 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7326 ASSERT(isolate->heap()->IsAllocationAllowed());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007327 int frames = deoptimizer->output_count();
7328
Ben Murdoch8b112d22011-06-08 16:22:53 +01007329 deoptimizer->MaterializeHeapNumbers();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007330 delete deoptimizer;
7331
Ben Murdoch8b112d22011-06-08 16:22:53 +01007332 JavaScriptFrameIterator it(isolate);
7333 JavaScriptFrame* frame = NULL;
7334 for (int i = 0; i < frames - 1; i++) it.Advance();
7335 frame = it.frame();
7336
Ben Murdochb0fe1622011-05-05 13:52:32 +01007337 RUNTIME_ASSERT(frame->function()->IsJSFunction());
Steve Block44f0eee2011-05-26 01:26:41 +01007338 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007339 Handle<Object> arguments;
7340 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
Steve Block44f0eee2011-05-26 01:26:41 +01007341 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007342 if (arguments.is_null()) {
7343 // FunctionGetArguments can't throw an exception, so cast away the
7344 // doubt with an assert.
7345 arguments = Handle<Object>(
7346 Accessors::FunctionGetArguments(*function,
7347 NULL)->ToObjectUnchecked());
Steve Block44f0eee2011-05-26 01:26:41 +01007348 ASSERT(*arguments != isolate->heap()->null_value());
7349 ASSERT(*arguments != isolate->heap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007350 }
7351 frame->SetExpression(i, *arguments);
7352 }
7353 }
7354
Steve Block44f0eee2011-05-26 01:26:41 +01007355 isolate->compilation_cache()->MarkForLazyOptimizing(function);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007356 if (type == Deoptimizer::EAGER) {
7357 RUNTIME_ASSERT(function->IsOptimized());
7358 } else {
7359 RUNTIME_ASSERT(!function->IsOptimized());
7360 }
7361
7362 // Avoid doing too much work when running with --always-opt and keep
7363 // the optimized code around.
7364 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
Steve Block44f0eee2011-05-26 01:26:41 +01007365 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007366 }
7367
7368 // Count the number of optimized activations of the function.
7369 int activations = 0;
7370 while (!it.done()) {
7371 JavaScriptFrame* frame = it.frame();
7372 if (frame->is_optimized() && frame->function() == *function) {
7373 activations++;
7374 }
7375 it.Advance();
7376 }
7377
7378 // TODO(kasperl): For now, we cannot support removing the optimized
7379 // code when we have recursive invocations of the same function.
7380 if (activations == 0) {
7381 if (FLAG_trace_deopt) {
7382 PrintF("[removing optimized code for: ");
7383 function->PrintName();
7384 PrintF("]\n");
7385 }
7386 function->ReplaceCode(function->shared()->code());
7387 }
Steve Block44f0eee2011-05-26 01:26:41 +01007388 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007389}
7390
7391
Ben Murdoch8b112d22011-06-08 16:22:53 +01007392RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
Steve Block44f0eee2011-05-26 01:26:41 +01007393 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007394 delete deoptimizer;
Steve Block44f0eee2011-05-26 01:26:41 +01007395 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007396}
7397
7398
Ben Murdoch8b112d22011-06-08 16:22:53 +01007399RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01007400 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007401 ASSERT(args.length() == 1);
7402 CONVERT_ARG_CHECKED(JSFunction, function, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007403 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007404
7405 Deoptimizer::DeoptimizeFunction(*function);
7406
Steve Block44f0eee2011-05-26 01:26:41 +01007407 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007408}
7409
7410
Ben Murdoch8b112d22011-06-08 16:22:53 +01007411RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7412 HandleScope scope(isolate);
7413 ASSERT(args.length() == 1);
7414 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7415 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7416 function->MarkForLazyRecompilation();
7417 return isolate->heap()->undefined_value();
7418}
7419
7420
7421RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
Steve Block44f0eee2011-05-26 01:26:41 +01007422 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007423 ASSERT(args.length() == 1);
7424 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7425
7426 // We're not prepared to handle a function with arguments object.
7427 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7428
7429 // We have hit a back edge in an unoptimized frame for a function that was
7430 // selected for on-stack replacement. Find the unoptimized code object.
Steve Block44f0eee2011-05-26 01:26:41 +01007431 Handle<Code> unoptimized(function->shared()->code(), isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007432 // Keep track of whether we've succeeded in optimizing.
7433 bool succeeded = unoptimized->optimizable();
7434 if (succeeded) {
7435 // If we are trying to do OSR when there are already optimized
7436 // activations of the function, it means (a) the function is directly or
7437 // indirectly recursive and (b) an optimized invocation has been
7438 // deoptimized so that we are currently in an unoptimized activation.
7439 // Check for optimized activations of this function.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007440 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007441 while (succeeded && !it.done()) {
7442 JavaScriptFrame* frame = it.frame();
7443 succeeded = !frame->is_optimized() || frame->function() != *function;
7444 it.Advance();
7445 }
7446 }
7447
7448 int ast_id = AstNode::kNoNumber;
7449 if (succeeded) {
7450 // The top JS function is this one, the PC is somewhere in the
7451 // unoptimized code.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007452 JavaScriptFrameIterator it(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007453 JavaScriptFrame* frame = it.frame();
7454 ASSERT(frame->function() == *function);
Ben Murdoch8b112d22011-06-08 16:22:53 +01007455 ASSERT(frame->LookupCode() == *unoptimized);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007456 ASSERT(unoptimized->contains(frame->pc()));
7457
7458 // Use linear search of the unoptimized code's stack check table to find
7459 // the AST id matching the PC.
7460 Address start = unoptimized->instruction_start();
7461 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
Steve Block1e0659c2011-05-24 12:43:12 +01007462 Address table_cursor = start + unoptimized->stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007463 uint32_t table_length = Memory::uint32_at(table_cursor);
7464 table_cursor += kIntSize;
7465 for (unsigned i = 0; i < table_length; ++i) {
7466 // Table entries are (AST id, pc offset) pairs.
7467 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7468 if (pc_offset == target_pc_offset) {
7469 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7470 break;
7471 }
7472 table_cursor += 2 * kIntSize;
7473 }
7474 ASSERT(ast_id != AstNode::kNoNumber);
7475 if (FLAG_trace_osr) {
7476 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7477 function->PrintName();
7478 PrintF("]\n");
7479 }
7480
7481 // Try to compile the optimized code. A true return value from
7482 // CompileOptimized means that compilation succeeded, not necessarily
7483 // that optimization succeeded.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007484 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7485 function->IsOptimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007486 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7487 function->code()->deoptimization_data());
7488 if (data->OsrPcOffset()->value() >= 0) {
7489 if (FLAG_trace_osr) {
7490 PrintF("[on-stack replacement offset %d in optimized code]\n",
7491 data->OsrPcOffset()->value());
7492 }
7493 ASSERT(data->OsrAstId()->value() == ast_id);
7494 } else {
7495 // We may never generate the desired OSR entry if we emit an
7496 // early deoptimize.
7497 succeeded = false;
7498 }
7499 } else {
7500 succeeded = false;
7501 }
7502 }
7503
7504 // Revert to the original stack checks in the original unoptimized code.
7505 if (FLAG_trace_osr) {
7506 PrintF("[restoring original stack checks in ");
7507 function->PrintName();
7508 PrintF("]\n");
7509 }
7510 StackCheckStub check_stub;
7511 Handle<Code> check_code = check_stub.GetCode();
Steve Block44f0eee2011-05-26 01:26:41 +01007512 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
Steve Block1e0659c2011-05-24 12:43:12 +01007513 Deoptimizer::RevertStackCheckCode(*unoptimized,
7514 *check_code,
7515 *replacement_code);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007516
7517 // Allow OSR only at nesting level zero again.
7518 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7519
7520 // If the optimization attempt succeeded, return the AST id tagged as a
7521 // smi. This tells the builtin that we need to translate the unoptimized
7522 // frame to an optimized one.
7523 if (succeeded) {
7524 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7525 return Smi::FromInt(ast_id);
7526 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007527 if (function->IsMarkedForLazyRecompilation()) {
7528 function->ReplaceCode(function->shared()->code());
7529 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007530 return Smi::FromInt(-1);
7531 }
7532}
7533
7534
Ben Murdoch8b112d22011-06-08 16:22:53 +01007535RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01007536 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007537 ASSERT(args.length() == 1);
7538 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7539 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7540}
7541
7542
Ben Murdoch8b112d22011-06-08 16:22:53 +01007543RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
Steve Block44f0eee2011-05-26 01:26:41 +01007544 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007545 ASSERT(args.length() == 1);
7546 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7547 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7548}
7549
7550
Ben Murdoch8b112d22011-06-08 16:22:53 +01007551RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007552 NoHandleAllocation ha;
7553 ASSERT(args.length() == 1);
7554
7555 CONVERT_CHECKED(JSFunction, function, args[0]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01007556 int length = function->shared()->scope_info()->NumberOfContextSlots();
John Reck59135872010-11-02 12:39:01 -07007557 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01007558 { MaybeObject* maybe_result =
7559 isolate->heap()->AllocateFunctionContext(length, function);
John Reck59135872010-11-02 12:39:01 -07007560 if (!maybe_result->ToObject(&result)) return maybe_result;
7561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007562
Steve Block44f0eee2011-05-26 01:26:41 +01007563 isolate->set_context(Context::cast(result));
Steve Blocka7e24c12009-10-30 11:49:00 +00007564
7565 return result; // non-failure
7566}
7567
John Reck59135872010-11-02 12:39:01 -07007568
Steve Block44f0eee2011-05-26 01:26:41 +01007569MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7570 Object* object,
John Reck59135872010-11-02 12:39:01 -07007571 bool is_catch_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007572 // Convert the object to a proper JavaScript object.
7573 Object* js_object = object;
7574 if (!js_object->IsJSObject()) {
John Reck59135872010-11-02 12:39:01 -07007575 MaybeObject* maybe_js_object = js_object->ToObject();
7576 if (!maybe_js_object->ToObject(&js_object)) {
7577 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7578 return maybe_js_object;
7579 }
Steve Block44f0eee2011-05-26 01:26:41 +01007580 HandleScope scope(isolate);
7581 Handle<Object> handle(object, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007582 Handle<Object> result =
Steve Block44f0eee2011-05-26 01:26:41 +01007583 isolate->factory()->NewTypeError("with_expression",
7584 HandleVector(&handle, 1));
7585 return isolate->Throw(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00007586 }
7587 }
7588
John Reck59135872010-11-02 12:39:01 -07007589 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01007590 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7591 isolate->context(), JSObject::cast(js_object), is_catch_context);
John Reck59135872010-11-02 12:39:01 -07007592 if (!maybe_result->ToObject(&result)) return maybe_result;
7593 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007594
7595 Context* context = Context::cast(result);
Steve Block44f0eee2011-05-26 01:26:41 +01007596 isolate->set_context(context);
Steve Blocka7e24c12009-10-30 11:49:00 +00007597
7598 return result;
7599}
7600
7601
Ben Murdoch8b112d22011-06-08 16:22:53 +01007602RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007603 NoHandleAllocation ha;
7604 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007605 return PushContextHelper(isolate, args[0], false);
Steve Blocka7e24c12009-10-30 11:49:00 +00007606}
7607
7608
Ben Murdoch8b112d22011-06-08 16:22:53 +01007609RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007610 NoHandleAllocation ha;
7611 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01007612 return PushContextHelper(isolate, args[0], true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007613}
7614
7615
Ben Murdoch8b112d22011-06-08 16:22:53 +01007616RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01007617 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007618 ASSERT(args.length() == 2);
7619
7620 CONVERT_ARG_CHECKED(Context, context, 0);
7621 CONVERT_ARG_CHECKED(String, name, 1);
7622
7623 int index;
7624 PropertyAttributes attributes;
7625 ContextLookupFlags flags = FOLLOW_CHAINS;
Steve Block1e0659c2011-05-24 12:43:12 +01007626 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00007627
Steve Block1e0659c2011-05-24 12:43:12 +01007628 // If the slot was not found the result is true.
7629 if (holder.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007630 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007631 }
7632
Steve Block1e0659c2011-05-24 12:43:12 +01007633 // If the slot was found in a context, it should be DONT_DELETE.
7634 if (holder->IsContext()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007635 return isolate->heap()->false_value();
Steve Block1e0659c2011-05-24 12:43:12 +01007636 }
7637
7638 // The slot was found in a JSObject, either a context extension object,
7639 // the global object, or an arguments object. Try to delete it
7640 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7641 // which allows deleting all parameters in functions that mention
7642 // 'arguments', we do this even for the case of slots found on an
7643 // arguments object. The slot was found on an arguments object if the
7644 // index is non-negative.
7645 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7646 if (index >= 0) {
7647 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7648 } else {
7649 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7650 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007651}
7652
7653
7654// A mechanism to return a pair of Object pointers in registers (if possible).
7655// How this is achieved is calling convention-dependent.
7656// All currently supported x86 compiles uses calling conventions that are cdecl
7657// variants where a 64-bit value is returned in two 32-bit registers
7658// (edx:eax on ia32, r1:r0 on ARM).
7659// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7660// In Win64 calling convention, a struct of two pointers is returned in memory,
7661// allocated by the caller, and passed as a pointer in a hidden first parameter.
7662#ifdef V8_HOST_ARCH_64_BIT
7663struct ObjectPair {
John Reck59135872010-11-02 12:39:01 -07007664 MaybeObject* x;
7665 MaybeObject* y;
Steve Blocka7e24c12009-10-30 11:49:00 +00007666};
7667
John Reck59135872010-11-02 12:39:01 -07007668static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007669 ObjectPair result = {x, y};
7670 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7671 // In Win64 they are assigned to a hidden first argument.
7672 return result;
7673}
7674#else
7675typedef uint64_t ObjectPair;
John Reck59135872010-11-02 12:39:01 -07007676static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007677 return reinterpret_cast<uint32_t>(x) |
7678 (reinterpret_cast<ObjectPair>(y) << 32);
7679}
7680#endif
7681
7682
Steve Block44f0eee2011-05-26 01:26:41 +01007683static inline MaybeObject* Unhole(Heap* heap,
7684 MaybeObject* x,
John Reck59135872010-11-02 12:39:01 -07007685 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007686 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7687 USE(attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01007688 return x->IsTheHole() ? heap->undefined_value() : x;
Steve Blocka7e24c12009-10-30 11:49:00 +00007689}
7690
7691
Steve Block44f0eee2011-05-26 01:26:41 +01007692static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7693 JSObject* holder) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007694 ASSERT(!holder->IsGlobalObject());
Steve Block44f0eee2011-05-26 01:26:41 +01007695 Context* top = isolate->context();
Steve Blocka7e24c12009-10-30 11:49:00 +00007696 // Get the context extension function.
7697 JSFunction* context_extension_function =
7698 top->global_context()->context_extension_function();
7699 // If the holder isn't a context extension object, we just return it
7700 // as the receiver. This allows arguments objects to be used as
7701 // receivers, but only if they are put in the context scope chain
7702 // explicitly via a with-statement.
7703 Object* constructor = holder->map()->constructor();
7704 if (constructor != context_extension_function) return holder;
7705 // Fall back to using the global object as the receiver if the
7706 // property turns out to be a local variable allocated in a context
7707 // extension object - introduced via eval.
7708 return top->global()->global_receiver();
7709}
7710
7711
Steve Block44f0eee2011-05-26 01:26:41 +01007712static ObjectPair LoadContextSlotHelper(Arguments args,
7713 Isolate* isolate,
7714 bool throw_error) {
7715 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007716 ASSERT_EQ(2, args.length());
7717
7718 if (!args[0]->IsContext() || !args[1]->IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007719 return MakePair(isolate->ThrowIllegalOperation(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007720 }
7721 Handle<Context> context = args.at<Context>(0);
7722 Handle<String> name = args.at<String>(1);
7723
7724 int index;
7725 PropertyAttributes attributes;
7726 ContextLookupFlags flags = FOLLOW_CHAINS;
Steve Block1e0659c2011-05-24 12:43:12 +01007727 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00007728
7729 // If the index is non-negative, the slot has been found in a local
7730 // variable or a parameter. Read it from the context object or the
7731 // arguments object.
7732 if (index >= 0) {
7733 // If the "property" we were looking for is a local variable or an
7734 // argument in a context, the receiver is the global object; see
7735 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
Steve Block44f0eee2011-05-26 01:26:41 +01007736 JSObject* receiver =
7737 isolate->context()->global()->global_receiver();
John Reck59135872010-11-02 12:39:01 -07007738 MaybeObject* value = (holder->IsContext())
Steve Blocka7e24c12009-10-30 11:49:00 +00007739 ? Context::cast(*holder)->get(index)
7740 : JSObject::cast(*holder)->GetElement(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007741 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007742 }
7743
7744 // If the holder is found, we read the property from it.
7745 if (!holder.is_null() && holder->IsJSObject()) {
7746 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
7747 JSObject* object = JSObject::cast(*holder);
7748 JSObject* receiver;
7749 if (object->IsGlobalObject()) {
7750 receiver = GlobalObject::cast(object)->global_receiver();
7751 } else if (context->is_exception_holder(*holder)) {
Steve Block44f0eee2011-05-26 01:26:41 +01007752 receiver = isolate->context()->global()->global_receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00007753 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007754 receiver = ComputeReceiverForNonGlobal(isolate, object);
Steve Blocka7e24c12009-10-30 11:49:00 +00007755 }
7756 // No need to unhole the value here. This is taken care of by the
7757 // GetProperty function.
John Reck59135872010-11-02 12:39:01 -07007758 MaybeObject* value = object->GetProperty(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +00007759 return MakePair(value, receiver);
7760 }
7761
7762 if (throw_error) {
7763 // The property doesn't exist - throw exception.
7764 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007765 isolate->factory()->NewReferenceError("not_defined",
7766 HandleVector(&name, 1));
7767 return MakePair(isolate->Throw(*reference_error), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007768 } else {
7769 // The property doesn't exist - return undefined
Steve Block44f0eee2011-05-26 01:26:41 +01007770 return MakePair(isolate->heap()->undefined_value(),
7771 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007772 }
7773}
7774
7775
Ben Murdoch8b112d22011-06-08 16:22:53 +01007776RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01007777 return LoadContextSlotHelper(args, isolate, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007778}
7779
7780
Ben Murdoch8b112d22011-06-08 16:22:53 +01007781RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01007782 return LoadContextSlotHelper(args, isolate, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00007783}
7784
7785
Ben Murdoch8b112d22011-06-08 16:22:53 +01007786RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
Steve Block44f0eee2011-05-26 01:26:41 +01007787 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007788 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00007789
Steve Block44f0eee2011-05-26 01:26:41 +01007790 Handle<Object> value(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007791 CONVERT_ARG_CHECKED(Context, context, 1);
7792 CONVERT_ARG_CHECKED(String, name, 2);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007793 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7794 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7795 strict_unchecked == kNonStrictMode);
7796 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
Steve Blocka7e24c12009-10-30 11:49:00 +00007797
7798 int index;
7799 PropertyAttributes attributes;
7800 ContextLookupFlags flags = FOLLOW_CHAINS;
Steve Block1e0659c2011-05-24 12:43:12 +01007801 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00007802
7803 if (index >= 0) {
7804 if (holder->IsContext()) {
7805 // Ignore if read_only variable.
7806 if ((attributes & READ_ONLY) == 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01007807 // Context is a fixed array and set cannot fail.
7808 Context::cast(*holder)->set(index, *value);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007809 } else if (strict_mode == kStrictMode) {
7810 // Setting read only property in strict mode.
7811 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01007812 isolate->factory()->NewTypeError("strict_cannot_assign",
7813 HandleVector(&name, 1));
7814 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00007815 }
7816 } else {
7817 ASSERT((attributes & READ_ONLY) == 0);
Steve Block1e0659c2011-05-24 12:43:12 +01007818 Handle<Object> result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007819 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01007820 if (result.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007821 ASSERT(isolate->has_pending_exception());
Steve Block1e0659c2011-05-24 12:43:12 +01007822 return Failure::Exception();
7823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007824 }
7825 return *value;
7826 }
7827
7828 // Slow case: The property is not in a FixedArray context.
7829 // It is either in an JSObject extension context or it was not found.
7830 Handle<JSObject> context_ext;
7831
7832 if (!holder.is_null()) {
7833 // The property exists in the extension context.
7834 context_ext = Handle<JSObject>::cast(holder);
7835 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007836 // The property was not found.
Steve Blocka7e24c12009-10-30 11:49:00 +00007837 ASSERT(attributes == ABSENT);
Ben Murdoch8b112d22011-06-08 16:22:53 +01007838
7839 if (strict_mode == kStrictMode) {
7840 // Throw in strict mode (assignment to undefined variable).
7841 Handle<Object> error =
7842 isolate->factory()->NewReferenceError(
7843 "not_defined", HandleVector(&name, 1));
7844 return isolate->Throw(*error);
7845 }
7846 // In non-strict mode, the property is stored in the global context.
Steve Blocka7e24c12009-10-30 11:49:00 +00007847 attributes = NONE;
Steve Block44f0eee2011-05-26 01:26:41 +01007848 context_ext = Handle<JSObject>(isolate->context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00007849 }
7850
7851 // Set the property, but ignore if read_only variable on the context
7852 // extension object itself.
7853 if ((attributes & READ_ONLY) == 0 ||
7854 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007855 RETURN_IF_EMPTY_HANDLE(
Steve Block44f0eee2011-05-26 01:26:41 +01007856 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007857 SetProperty(context_ext, name, value, NONE, strict_mode));
7858 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
7859 // Setting read only property in strict mode.
7860 Handle<Object> error =
Steve Block44f0eee2011-05-26 01:26:41 +01007861 isolate->factory()->NewTypeError(
7862 "strict_cannot_assign", HandleVector(&name, 1));
7863 return isolate->Throw(*error);
Steve Blocka7e24c12009-10-30 11:49:00 +00007864 }
7865 return *value;
7866}
7867
7868
Ben Murdoch8b112d22011-06-08 16:22:53 +01007869RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
Steve Block44f0eee2011-05-26 01:26:41 +01007870 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007871 ASSERT(args.length() == 1);
7872
Steve Block44f0eee2011-05-26 01:26:41 +01007873 return isolate->Throw(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00007874}
7875
7876
Ben Murdoch8b112d22011-06-08 16:22:53 +01007877RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
Steve Block44f0eee2011-05-26 01:26:41 +01007878 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007879 ASSERT(args.length() == 1);
7880
Steve Block44f0eee2011-05-26 01:26:41 +01007881 return isolate->ReThrow(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00007882}
7883
7884
Ben Murdoch8b112d22011-06-08 16:22:53 +01007885RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
Steve Blockd0582a62009-12-15 09:54:21 +00007886 ASSERT_EQ(0, args.length());
Steve Block44f0eee2011-05-26 01:26:41 +01007887 return isolate->PromoteScheduledException();
Steve Blockd0582a62009-12-15 09:54:21 +00007888}
7889
7890
Ben Murdoch8b112d22011-06-08 16:22:53 +01007891RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
Steve Block44f0eee2011-05-26 01:26:41 +01007892 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007893 ASSERT(args.length() == 1);
7894
Steve Block44f0eee2011-05-26 01:26:41 +01007895 Handle<Object> name(args[0], isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007896 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01007897 isolate->factory()->NewReferenceError("not_defined",
7898 HandleVector(&name, 1));
7899 return isolate->Throw(*reference_error);
Steve Blocka7e24c12009-10-30 11:49:00 +00007900}
7901
7902
Ben Murdoch8b112d22011-06-08 16:22:53 +01007903RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
Ben Murdochf87a2032010-10-22 12:50:53 +01007904 ASSERT(args.length() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00007905
7906 // First check if this is a real stack overflow.
Steve Block44f0eee2011-05-26 01:26:41 +01007907 if (isolate->stack_guard()->IsStackOverflow()) {
7908 NoHandleAllocation na;
7909 return isolate->StackOverflow();
Steve Blocka7e24c12009-10-30 11:49:00 +00007910 }
7911
7912 return Execution::HandleStackGuardInterrupt();
7913}
7914
7915
7916// NOTE: These PrintXXX functions are defined for all builds (not just
7917// DEBUG builds) because we may want to be able to trace function
7918// calls in all modes.
7919static void PrintString(String* str) {
7920 // not uncommon to have empty strings
7921 if (str->length() > 0) {
7922 SmartPointer<char> s =
7923 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7924 PrintF("%s", *s);
7925 }
7926}
7927
7928
7929static void PrintObject(Object* obj) {
7930 if (obj->IsSmi()) {
7931 PrintF("%d", Smi::cast(obj)->value());
7932 } else if (obj->IsString() || obj->IsSymbol()) {
7933 PrintString(String::cast(obj));
7934 } else if (obj->IsNumber()) {
7935 PrintF("%g", obj->Number());
7936 } else if (obj->IsFailure()) {
7937 PrintF("<failure>");
7938 } else if (obj->IsUndefined()) {
7939 PrintF("<undefined>");
7940 } else if (obj->IsNull()) {
7941 PrintF("<null>");
7942 } else if (obj->IsTrue()) {
7943 PrintF("<true>");
7944 } else if (obj->IsFalse()) {
7945 PrintF("<false>");
7946 } else {
Ben Murdochf87a2032010-10-22 12:50:53 +01007947 PrintF("%p", reinterpret_cast<void*>(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00007948 }
7949}
7950
7951
7952static int StackSize() {
7953 int n = 0;
7954 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7955 return n;
7956}
7957
7958
7959static void PrintTransition(Object* result) {
7960 // indentation
7961 { const int nmax = 80;
7962 int n = StackSize();
7963 if (n <= nmax)
7964 PrintF("%4d:%*s", n, n, "");
7965 else
7966 PrintF("%4d:%*s", n, nmax, "...");
7967 }
7968
7969 if (result == NULL) {
7970 // constructor calls
7971 JavaScriptFrameIterator it;
7972 JavaScriptFrame* frame = it.frame();
7973 if (frame->IsConstructor()) PrintF("new ");
7974 // function name
7975 Object* fun = frame->function();
7976 if (fun->IsJSFunction()) {
7977 PrintObject(JSFunction::cast(fun)->shared()->name());
7978 } else {
7979 PrintObject(fun);
7980 }
7981 // function arguments
7982 // (we are intentionally only printing the actually
7983 // supplied parameters, not all parameters required)
7984 PrintF("(this=");
7985 PrintObject(frame->receiver());
Steve Block44f0eee2011-05-26 01:26:41 +01007986 const int length = frame->ComputeParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00007987 for (int i = 0; i < length; i++) {
7988 PrintF(", ");
7989 PrintObject(frame->GetParameter(i));
7990 }
7991 PrintF(") {\n");
7992
7993 } else {
7994 // function result
7995 PrintF("} -> ");
7996 PrintObject(result);
7997 PrintF("\n");
7998 }
7999}
8000
8001
Ben Murdoch8b112d22011-06-08 16:22:53 +01008002RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008003 ASSERT(args.length() == 0);
8004 NoHandleAllocation ha;
8005 PrintTransition(NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01008006 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008007}
8008
8009
Ben Murdoch8b112d22011-06-08 16:22:53 +01008010RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008011 NoHandleAllocation ha;
8012 PrintTransition(args[0]);
8013 return args[0]; // return TOS
8014}
8015
8016
Ben Murdoch8b112d22011-06-08 16:22:53 +01008017RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008018 NoHandleAllocation ha;
8019 ASSERT(args.length() == 1);
8020
8021#ifdef DEBUG
8022 if (args[0]->IsString()) {
8023 // If we have a string, assume it's a code "marker"
8024 // and print some interesting cpu debugging info.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008025 JavaScriptFrameIterator it(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008026 JavaScriptFrame* frame = it.frame();
8027 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8028 frame->fp(), frame->sp(), frame->caller_sp());
8029 } else {
8030 PrintF("DebugPrint: ");
8031 }
8032 args[0]->Print();
Steve Blockd0582a62009-12-15 09:54:21 +00008033 if (args[0]->IsHeapObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01008034 PrintF("\n");
Steve Blockd0582a62009-12-15 09:54:21 +00008035 HeapObject::cast(args[0])->map()->Print();
8036 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008037#else
8038 // ShortPrint is available in release mode. Print is not.
8039 args[0]->ShortPrint();
8040#endif
8041 PrintF("\n");
8042 Flush();
8043
8044 return args[0]; // return TOS
8045}
8046
8047
Ben Murdoch8b112d22011-06-08 16:22:53 +01008048RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008049 ASSERT(args.length() == 0);
8050 NoHandleAllocation ha;
Steve Block44f0eee2011-05-26 01:26:41 +01008051 isolate->PrintStack();
8052 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008053}
8054
8055
Ben Murdoch8b112d22011-06-08 16:22:53 +01008056RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008057 NoHandleAllocation ha;
8058 ASSERT(args.length() == 0);
8059
8060 // According to ECMA-262, section 15.9.1, page 117, the precision of
8061 // the number in a Date object representing a particular instant in
8062 // time is milliseconds. Therefore, we floor the result of getting
8063 // the OS time.
8064 double millis = floor(OS::TimeCurrentMillis());
Steve Block44f0eee2011-05-26 01:26:41 +01008065 return isolate->heap()->NumberFromDouble(millis);
Steve Blocka7e24c12009-10-30 11:49:00 +00008066}
8067
8068
Ben Murdoch8b112d22011-06-08 16:22:53 +01008069RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
Steve Block44f0eee2011-05-26 01:26:41 +01008070 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008071 ASSERT(args.length() == 2);
8072
8073 CONVERT_ARG_CHECKED(String, str, 0);
8074 FlattenString(str);
8075
8076 CONVERT_ARG_CHECKED(JSArray, output, 1);
8077 RUNTIME_ASSERT(output->HasFastElements());
8078
8079 AssertNoAllocation no_allocation;
8080
8081 FixedArray* output_array = FixedArray::cast(output->elements());
8082 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8083 bool result;
8084 if (str->IsAsciiRepresentation()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008085 result = DateParser::Parse(str->ToAsciiVector(),
8086 output_array,
8087 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00008088 } else {
8089 ASSERT(str->IsTwoByteRepresentation());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008090 result = DateParser::Parse(str->ToUC16Vector(),
8091 output_array,
8092 isolate->unicode_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00008093 }
8094
8095 if (result) {
8096 return *output;
8097 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01008098 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008099 }
8100}
8101
8102
Ben Murdoch8b112d22011-06-08 16:22:53 +01008103RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008104 NoHandleAllocation ha;
8105 ASSERT(args.length() == 1);
8106
8107 CONVERT_DOUBLE_CHECKED(x, args[0]);
8108 const char* zone = OS::LocalTimezone(x);
Steve Block44f0eee2011-05-26 01:26:41 +01008109 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
Steve Blocka7e24c12009-10-30 11:49:00 +00008110}
8111
8112
Ben Murdoch8b112d22011-06-08 16:22:53 +01008113RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008114 NoHandleAllocation ha;
8115 ASSERT(args.length() == 0);
8116
Steve Block44f0eee2011-05-26 01:26:41 +01008117 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
Steve Blocka7e24c12009-10-30 11:49:00 +00008118}
8119
8120
Ben Murdoch8b112d22011-06-08 16:22:53 +01008121RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008122 NoHandleAllocation ha;
8123 ASSERT(args.length() == 1);
8124
8125 CONVERT_DOUBLE_CHECKED(x, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +01008126 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
Steve Blocka7e24c12009-10-30 11:49:00 +00008127}
8128
8129
Ben Murdoch8b112d22011-06-08 16:22:53 +01008130RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008131 ASSERT(args.length() == 1);
8132 Object* global = args[0];
Steve Block44f0eee2011-05-26 01:26:41 +01008133 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008134 return JSGlobalObject::cast(global)->global_receiver();
8135}
8136
8137
Ben Murdoch8b112d22011-06-08 16:22:53 +01008138RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
Steve Block44f0eee2011-05-26 01:26:41 +01008139 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08008140 ASSERT_EQ(1, args.length());
8141 CONVERT_ARG_CHECKED(String, source, 0);
8142
8143 Handle<Object> result = JsonParser::Parse(source);
8144 if (result.is_null()) {
8145 // Syntax error or stack overflow in scanner.
Steve Block44f0eee2011-05-26 01:26:41 +01008146 ASSERT(isolate->has_pending_exception());
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08008147 return Failure::Exception();
8148 }
8149 return *result;
8150}
8151
8152
Ben Murdoch8b112d22011-06-08 16:22:53 +01008153RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
Steve Block44f0eee2011-05-26 01:26:41 +01008154 HandleScope scope(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08008155 ASSERT_EQ(1, args.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008156 CONVERT_ARG_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008157
8158 // Compile source string in the global context.
Steve Block44f0eee2011-05-26 01:26:41 +01008159 Handle<Context> context(isolate->context()->global_context());
Steve Block6ded16b2010-05-10 14:33:55 +01008160 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8161 context,
Steve Block1e0659c2011-05-24 12:43:12 +01008162 true,
8163 kNonStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +01008164 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00008165 Handle<JSFunction> fun =
Steve Block44f0eee2011-05-26 01:26:41 +01008166 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8167 context,
8168 NOT_TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00008169 return *fun;
8170}
8171
8172
Steve Block44f0eee2011-05-26 01:26:41 +01008173static ObjectPair CompileGlobalEval(Isolate* isolate,
8174 Handle<String> source,
Steve Block1e0659c2011-05-24 12:43:12 +01008175 Handle<Object> receiver,
Steve Block44f0eee2011-05-26 01:26:41 +01008176 StrictModeFlag strict_mode) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008177 // Deal with a normal eval call with a string argument. Compile it
8178 // and return the compiled function bound in the local context.
8179 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8180 source,
Steve Block44f0eee2011-05-26 01:26:41 +01008181 Handle<Context>(isolate->context()),
8182 isolate->context()->IsGlobalContext(),
8183 strict_mode);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008184 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Steve Block44f0eee2011-05-26 01:26:41 +01008185 Handle<JSFunction> compiled =
8186 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8187 shared, Handle<Context>(isolate->context()), NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008188 return MakePair(*compiled, *receiver);
8189}
8190
8191
Ben Murdoch8b112d22011-06-08 16:22:53 +01008192RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
Steve Block1e0659c2011-05-24 12:43:12 +01008193 ASSERT(args.length() == 4);
Steve Blocka7e24c12009-10-30 11:49:00 +00008194
Steve Block44f0eee2011-05-26 01:26:41 +01008195 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008196 Handle<Object> callee = args.at<Object>(0);
Leon Clarkee46be812010-01-19 14:06:41 +00008197 Handle<Object> receiver; // Will be overwritten.
8198
8199 // Compute the calling context.
Steve Block44f0eee2011-05-26 01:26:41 +01008200 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00008201#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +01008202 // Make sure Isolate::context() agrees with the old code that traversed
Leon Clarkee46be812010-01-19 14:06:41 +00008203 // the stack frames to compute the context.
Steve Blocka7e24c12009-10-30 11:49:00 +00008204 StackFrameLocator locator;
8205 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Leon Clarkee46be812010-01-19 14:06:41 +00008206 ASSERT(Context::cast(frame->context()) == *context);
8207#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00008208
8209 // Find where the 'eval' symbol is bound. It is unaliased only if
8210 // it is bound in the global context.
Leon Clarkee46be812010-01-19 14:06:41 +00008211 int index = -1;
8212 PropertyAttributes attributes = ABSENT;
8213 while (true) {
Steve Block44f0eee2011-05-26 01:26:41 +01008214 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8215 FOLLOW_PROTOTYPE_CHAIN,
Steve Blocka7e24c12009-10-30 11:49:00 +00008216 &index, &attributes);
8217 // Stop search when eval is found or when the global context is
8218 // reached.
8219 if (attributes != ABSENT || context->IsGlobalContext()) break;
8220 if (context->is_function_context()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008221 context = Handle<Context>(Context::cast(context->closure()->context()),
8222 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008223 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01008224 context = Handle<Context>(context->previous(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008225 }
8226 }
8227
8228 // If eval could not be resolved, it has been deleted and we need to
8229 // throw a reference error.
8230 if (attributes == ABSENT) {
Steve Block44f0eee2011-05-26 01:26:41 +01008231 Handle<Object> name = isolate->factory()->eval_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00008232 Handle<Object> reference_error =
Steve Block44f0eee2011-05-26 01:26:41 +01008233 isolate->factory()->NewReferenceError("not_defined",
8234 HandleVector(&name, 1));
8235 return MakePair(isolate->Throw(*reference_error), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008236 }
8237
Leon Clarkee46be812010-01-19 14:06:41 +00008238 if (!context->IsGlobalContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008239 // 'eval' is not bound in the global context. Just call the function
8240 // with the given arguments. This is not necessarily the global eval.
8241 if (receiver->IsContext()) {
8242 context = Handle<Context>::cast(receiver);
Steve Block44f0eee2011-05-26 01:26:41 +01008243 receiver = Handle<Object>(context->get(index), isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00008244 } else if (receiver->IsJSContextExtensionObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008245 receiver = Handle<JSObject>(
8246 isolate->context()->global()->global_receiver(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008247 }
Leon Clarkee46be812010-01-19 14:06:41 +00008248 return MakePair(*callee, *receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008249 }
8250
Leon Clarkee46be812010-01-19 14:06:41 +00008251 // 'eval' is bound in the global context, but it may have been overwritten.
8252 // Compare it to the builtin 'GlobalEval' function to make sure.
Steve Block44f0eee2011-05-26 01:26:41 +01008253 if (*callee != isolate->global_context()->global_eval_fun() ||
Leon Clarkee46be812010-01-19 14:06:41 +00008254 !args[1]->IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008255 return MakePair(*callee,
8256 isolate->context()->global()->global_receiver());
Leon Clarkee46be812010-01-19 14:06:41 +00008257 }
8258
Steve Block1e0659c2011-05-24 12:43:12 +01008259 ASSERT(args[3]->IsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +01008260 return CompileGlobalEval(isolate,
8261 args.at<String>(1),
Steve Block1e0659c2011-05-24 12:43:12 +01008262 args.at<Object>(2),
8263 static_cast<StrictModeFlag>(
8264 Smi::cast(args[3])->value()));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008265}
8266
8267
Ben Murdoch8b112d22011-06-08 16:22:53 +01008268RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
Steve Block1e0659c2011-05-24 12:43:12 +01008269 ASSERT(args.length() == 4);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008270
Steve Block44f0eee2011-05-26 01:26:41 +01008271 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008272 Handle<Object> callee = args.at<Object>(0);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008273
8274 // 'eval' is bound in the global context, but it may have been overwritten.
8275 // Compare it to the builtin 'GlobalEval' function to make sure.
Steve Block44f0eee2011-05-26 01:26:41 +01008276 if (*callee != isolate->global_context()->global_eval_fun() ||
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008277 !args[1]->IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008278 return MakePair(*callee,
8279 isolate->context()->global()->global_receiver());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008280 }
8281
Steve Block1e0659c2011-05-24 12:43:12 +01008282 ASSERT(args[3]->IsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +01008283 return CompileGlobalEval(isolate,
8284 args.at<String>(1),
Steve Block1e0659c2011-05-24 12:43:12 +01008285 args.at<Object>(2),
8286 static_cast<StrictModeFlag>(
8287 Smi::cast(args[3])->value()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008288}
8289
8290
Ben Murdoch8b112d22011-06-08 16:22:53 +01008291RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008292 // This utility adjusts the property attributes for newly created Function
8293 // object ("new Function(...)") by changing the map.
8294 // All it does is changing the prototype property to enumerable
8295 // as specified in ECMA262, 15.3.5.2.
Steve Block44f0eee2011-05-26 01:26:41 +01008296 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008297 ASSERT(args.length() == 1);
8298 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Steve Block44f0eee2011-05-26 01:26:41 +01008299
8300 Handle<Map> map = func->shared()->strict_mode()
8301 ? isolate->strict_mode_function_instance_map()
8302 : isolate->function_instance_map();
8303
8304 ASSERT(func->map()->instance_type() == map->instance_type());
8305 ASSERT(func->map()->instance_size() == map->instance_size());
8306 func->set_map(*map);
Steve Blocka7e24c12009-10-30 11:49:00 +00008307 return *func;
8308}
8309
8310
Ben Murdoch8b112d22011-06-08 16:22:53 +01008311RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
Ben Murdochbb769b22010-08-11 14:56:33 +01008312 // Allocate a block of memory in NewSpace (filled with a filler).
8313 // Use as fallback for allocation in generated code when NewSpace
8314 // is full.
8315 ASSERT(args.length() == 1);
8316 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8317 int size = size_smi->value();
8318 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8319 RUNTIME_ASSERT(size > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01008320 Heap* heap = isolate->heap();
8321 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
Ben Murdochbb769b22010-08-11 14:56:33 +01008322 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
John Reck59135872010-11-02 12:39:01 -07008323 Object* allocation;
Steve Block44f0eee2011-05-26 01:26:41 +01008324 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
John Reck59135872010-11-02 12:39:01 -07008325 if (maybe_allocation->ToObject(&allocation)) {
Steve Block44f0eee2011-05-26 01:26:41 +01008326 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
John Reck59135872010-11-02 12:39:01 -07008327 }
8328 return maybe_allocation;
Ben Murdochbb769b22010-08-11 14:56:33 +01008329 }
Ben Murdochbb769b22010-08-11 14:56:33 +01008330}
8331
8332
Ben Murdochb0fe1622011-05-05 13:52:32 +01008333// Push an object unto an array of objects if it is not already in the
Steve Blocka7e24c12009-10-30 11:49:00 +00008334// array. Returns true if the element was pushed on the stack and
8335// false otherwise.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008336RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008337 ASSERT(args.length() == 2);
8338 CONVERT_CHECKED(JSArray, array, args[0]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008339 CONVERT_CHECKED(JSObject, element, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00008340 RUNTIME_ASSERT(array->HasFastElements());
8341 int length = Smi::cast(array->length())->value();
8342 FixedArray* elements = FixedArray::cast(array->elements());
8343 for (int i = 0; i < length; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +01008344 if (elements->get(i) == element) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008345 }
John Reck59135872010-11-02 12:39:01 -07008346 Object* obj;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008347 // Strict not needed. Used for cycle detection in Array join implementation.
8348 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8349 kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -07008350 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8351 }
Steve Block44f0eee2011-05-26 01:26:41 +01008352 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008353}
8354
8355
8356/**
8357 * A simple visitor visits every element of Array's.
8358 * The backend storage can be a fixed array for fast elements case,
8359 * or a dictionary for sparse array. Since Dictionary is a subtype
8360 * of FixedArray, the class can be used by both fast and slow cases.
8361 * The second parameter of the constructor, fast_elements, specifies
8362 * whether the storage is a FixedArray or Dictionary.
8363 *
8364 * An index limit is used to deal with the situation that a result array
8365 * length overflows 32-bit non-negative integer.
8366 */
8367class ArrayConcatVisitor {
8368 public:
Steve Block44f0eee2011-05-26 01:26:41 +01008369 ArrayConcatVisitor(Isolate* isolate,
8370 Handle<FixedArray> storage,
Steve Blocka7e24c12009-10-30 11:49:00 +00008371 bool fast_elements) :
Steve Block44f0eee2011-05-26 01:26:41 +01008372 isolate_(isolate),
8373 storage_(Handle<FixedArray>::cast(
8374 isolate->global_handles()->Create(*storage))),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008375 index_offset_(0u),
8376 fast_elements_(fast_elements) { }
8377
8378 ~ArrayConcatVisitor() {
8379 clear_storage();
8380 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008381
8382 void visit(uint32_t i, Handle<Object> elm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008383 if (i >= JSObject::kMaxElementCount - index_offset_) return;
Leon Clarkee46be812010-01-19 14:06:41 +00008384 uint32_t index = index_offset_ + i;
Steve Blocka7e24c12009-10-30 11:49:00 +00008385
8386 if (fast_elements_) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008387 if (index < static_cast<uint32_t>(storage_->length())) {
8388 storage_->set(index, *elm);
8389 return;
8390 }
8391 // Our initial estimate of length was foiled, possibly by
8392 // getters on the arrays increasing the length of later arrays
8393 // during iteration.
8394 // This shouldn't happen in anything but pathological cases.
8395 SetDictionaryMode(index);
8396 // Fall-through to dictionary mode.
Steve Blocka7e24c12009-10-30 11:49:00 +00008397 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008398 ASSERT(!fast_elements_);
8399 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
8400 Handle<NumberDictionary> result =
Steve Block44f0eee2011-05-26 01:26:41 +01008401 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008402 if (!result.is_identical_to(dict)) {
8403 // Dictionary needed to grow.
8404 clear_storage();
8405 set_storage(*result);
8406 }
8407}
Steve Blocka7e24c12009-10-30 11:49:00 +00008408
8409 void increase_index_offset(uint32_t delta) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008410 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8411 index_offset_ = JSObject::kMaxElementCount;
Leon Clarkee46be812010-01-19 14:06:41 +00008412 } else {
8413 index_offset_ += delta;
8414 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008415 }
8416
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008417 Handle<JSArray> ToArray() {
Steve Block44f0eee2011-05-26 01:26:41 +01008418 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008419 Handle<Object> length =
Steve Block44f0eee2011-05-26 01:26:41 +01008420 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008421 Handle<Map> map;
8422 if (fast_elements_) {
Steve Block44f0eee2011-05-26 01:26:41 +01008423 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008424 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01008425 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008426 }
8427 array->set_map(*map);
8428 array->set_length(*length);
8429 array->set_elements(*storage_);
8430 return array;
8431 }
Leon Clarkee46be812010-01-19 14:06:41 +00008432
Steve Blocka7e24c12009-10-30 11:49:00 +00008433 private:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008434 // Convert storage to dictionary mode.
8435 void SetDictionaryMode(uint32_t index) {
8436 ASSERT(fast_elements_);
8437 Handle<FixedArray> current_storage(*storage_);
8438 Handle<NumberDictionary> slow_storage(
Steve Block44f0eee2011-05-26 01:26:41 +01008439 isolate_->factory()->NewNumberDictionary(current_storage->length()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008440 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8441 for (uint32_t i = 0; i < current_length; i++) {
8442 HandleScope loop_scope;
8443 Handle<Object> element(current_storage->get(i));
8444 if (!element->IsTheHole()) {
8445 Handle<NumberDictionary> new_storage =
Steve Block44f0eee2011-05-26 01:26:41 +01008446 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008447 if (!new_storage.is_identical_to(slow_storage)) {
8448 slow_storage = loop_scope.CloseAndEscape(new_storage);
8449 }
8450 }
8451 }
8452 clear_storage();
8453 set_storage(*slow_storage);
8454 fast_elements_ = false;
8455 }
8456
8457 inline void clear_storage() {
Steve Block44f0eee2011-05-26 01:26:41 +01008458 isolate_->global_handles()->Destroy(
8459 Handle<Object>::cast(storage_).location());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008460 }
8461
8462 inline void set_storage(FixedArray* storage) {
Steve Block44f0eee2011-05-26 01:26:41 +01008463 storage_ = Handle<FixedArray>::cast(
8464 isolate_->global_handles()->Create(storage));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008465 }
8466
Steve Block44f0eee2011-05-26 01:26:41 +01008467 Isolate* isolate_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008468 Handle<FixedArray> storage_; // Always a global handle.
8469 // Index after last seen index. Always less than or equal to
8470 // JSObject::kMaxElementCount.
Steve Blocka7e24c12009-10-30 11:49:00 +00008471 uint32_t index_offset_;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008472 bool fast_elements_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008473};
8474
8475
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008476static uint32_t EstimateElementCount(Handle<JSArray> array) {
8477 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8478 int element_count = 0;
8479 switch (array->GetElementsKind()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008480 case JSObject::FAST_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008481 // Fast elements can't have lengths that are not representable by
8482 // a 32-bit signed integer.
8483 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8484 int fast_length = static_cast<int>(length);
8485 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8486 for (int i = 0; i < fast_length; i++) {
8487 if (!elements->get(i)->IsTheHole()) element_count++;
Steve Blocka7e24c12009-10-30 11:49:00 +00008488 }
Steve Block3ce2e202009-11-05 08:53:23 +00008489 break;
8490 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008491 case JSObject::DICTIONARY_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008492 Handle<NumberDictionary> dictionary(
8493 NumberDictionary::cast(array->elements()));
8494 int capacity = dictionary->Capacity();
8495 for (int i = 0; i < capacity; i++) {
8496 Handle<Object> key(dictionary->KeyAt(i));
8497 if (dictionary->IsKey(*key)) {
8498 element_count++;
8499 }
8500 }
8501 break;
8502 }
8503 default:
8504 // External arrays are always dense.
8505 return length;
8506 }
8507 // As an estimate, we assume that the prototype doesn't contain any
8508 // inherited elements.
8509 return element_count;
8510}
8511
8512
8513
8514template<class ExternalArrayClass, class ElementType>
Steve Block44f0eee2011-05-26 01:26:41 +01008515static void IterateExternalArrayElements(Isolate* isolate,
8516 Handle<JSObject> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008517 bool elements_are_ints,
8518 bool elements_are_guaranteed_smis,
8519 ArrayConcatVisitor* visitor) {
8520 Handle<ExternalArrayClass> array(
8521 ExternalArrayClass::cast(receiver->elements()));
8522 uint32_t len = static_cast<uint32_t>(array->length());
8523
8524 ASSERT(visitor != NULL);
8525 if (elements_are_ints) {
8526 if (elements_are_guaranteed_smis) {
8527 for (uint32_t j = 0; j < len; j++) {
8528 HandleScope loop_scope;
8529 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8530 visitor->visit(j, e);
8531 }
8532 } else {
8533 for (uint32_t j = 0; j < len; j++) {
8534 HandleScope loop_scope;
8535 int64_t val = static_cast<int64_t>(array->get(j));
8536 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8537 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8538 visitor->visit(j, e);
8539 } else {
8540 Handle<Object> e =
Steve Block44f0eee2011-05-26 01:26:41 +01008541 isolate->factory()->NewNumber(static_cast<ElementType>(val));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008542 visitor->visit(j, e);
8543 }
8544 }
8545 }
8546 } else {
8547 for (uint32_t j = 0; j < len; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01008548 HandleScope loop_scope(isolate);
8549 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008550 visitor->visit(j, e);
8551 }
8552 }
8553}
8554
8555
8556// Used for sorting indices in a List<uint32_t>.
8557static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8558 uint32_t a = *ap;
8559 uint32_t b = *bp;
8560 return (a == b) ? 0 : (a < b) ? -1 : 1;
8561}
8562
8563
8564static void CollectElementIndices(Handle<JSObject> object,
8565 uint32_t range,
8566 List<uint32_t>* indices) {
8567 JSObject::ElementsKind kind = object->GetElementsKind();
8568 switch (kind) {
8569 case JSObject::FAST_ELEMENTS: {
8570 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8571 uint32_t length = static_cast<uint32_t>(elements->length());
8572 if (range < length) length = range;
8573 for (uint32_t i = 0; i < length; i++) {
8574 if (!elements->get(i)->IsTheHole()) {
8575 indices->Add(i);
8576 }
8577 }
8578 break;
8579 }
8580 case JSObject::DICTIONARY_ELEMENTS: {
8581 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008582 uint32_t capacity = dict->Capacity();
8583 for (uint32_t j = 0; j < capacity; j++) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008584 HandleScope loop_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +00008585 Handle<Object> k(dict->KeyAt(j));
8586 if (dict->IsKey(*k)) {
8587 ASSERT(k->IsNumber());
8588 uint32_t index = static_cast<uint32_t>(k->Number());
8589 if (index < range) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008590 indices->Add(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008591 }
8592 }
8593 }
8594 break;
8595 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008596 default: {
8597 int dense_elements_length;
8598 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01008599 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008600 dense_elements_length =
Steve Block44f0eee2011-05-26 01:26:41 +01008601 ExternalPixelArray::cast(object->elements())->length();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008602 break;
8603 }
8604 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8605 dense_elements_length =
8606 ExternalByteArray::cast(object->elements())->length();
8607 break;
8608 }
8609 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8610 dense_elements_length =
8611 ExternalUnsignedByteArray::cast(object->elements())->length();
8612 break;
8613 }
8614 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8615 dense_elements_length =
8616 ExternalShortArray::cast(object->elements())->length();
8617 break;
8618 }
8619 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8620 dense_elements_length =
8621 ExternalUnsignedShortArray::cast(object->elements())->length();
8622 break;
8623 }
8624 case JSObject::EXTERNAL_INT_ELEMENTS: {
8625 dense_elements_length =
8626 ExternalIntArray::cast(object->elements())->length();
8627 break;
8628 }
8629 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8630 dense_elements_length =
8631 ExternalUnsignedIntArray::cast(object->elements())->length();
8632 break;
8633 }
8634 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8635 dense_elements_length =
8636 ExternalFloatArray::cast(object->elements())->length();
8637 break;
8638 }
8639 default:
8640 UNREACHABLE();
8641 dense_elements_length = 0;
8642 break;
8643 }
8644 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8645 if (range <= length) {
8646 length = range;
8647 // We will add all indices, so we might as well clear it first
8648 // and avoid duplicates.
8649 indices->Clear();
8650 }
8651 for (uint32_t i = 0; i < length; i++) {
8652 indices->Add(i);
8653 }
8654 if (length == range) return; // All indices accounted for already.
8655 break;
8656 }
8657 }
8658
8659 Handle<Object> prototype(object->GetPrototype());
8660 if (prototype->IsJSObject()) {
8661 // The prototype will usually have no inherited element indices,
8662 // but we have to check.
8663 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8664 }
8665}
8666
8667
8668/**
8669 * A helper function that visits elements of a JSArray in numerical
8670 * order.
8671 *
8672 * The visitor argument called for each existing element in the array
8673 * with the element index and the element's value.
8674 * Afterwards it increments the base-index of the visitor by the array
8675 * length.
8676 * Returns false if any access threw an exception, otherwise true.
8677 */
Steve Block44f0eee2011-05-26 01:26:41 +01008678static bool IterateElements(Isolate* isolate,
8679 Handle<JSArray> receiver,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008680 ArrayConcatVisitor* visitor) {
8681 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8682 switch (receiver->GetElementsKind()) {
8683 case JSObject::FAST_ELEMENTS: {
8684 // Run through the elements FixedArray and use HasElement and GetElement
8685 // to check the prototype for missing elements.
8686 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8687 int fast_length = static_cast<int>(length);
8688 ASSERT(fast_length <= elements->length());
8689 for (int j = 0; j < fast_length; j++) {
Steve Block44f0eee2011-05-26 01:26:41 +01008690 HandleScope loop_scope(isolate);
8691 Handle<Object> element_value(elements->get(j), isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008692 if (!element_value->IsTheHole()) {
8693 visitor->visit(j, element_value);
8694 } else if (receiver->HasElement(j)) {
8695 // Call GetElement on receiver, not its prototype, or getters won't
8696 // have the correct receiver.
8697 element_value = GetElement(receiver, j);
8698 if (element_value.is_null()) return false;
8699 visitor->visit(j, element_value);
8700 }
8701 }
8702 break;
8703 }
8704 case JSObject::DICTIONARY_ELEMENTS: {
8705 Handle<NumberDictionary> dict(receiver->element_dictionary());
8706 List<uint32_t> indices(dict->Capacity() / 2);
8707 // Collect all indices in the object and the prototypes less
8708 // than length. This might introduce duplicates in the indices list.
8709 CollectElementIndices(receiver, length, &indices);
8710 indices.Sort(&compareUInt32);
8711 int j = 0;
8712 int n = indices.length();
8713 while (j < n) {
8714 HandleScope loop_scope;
8715 uint32_t index = indices[j];
8716 Handle<Object> element = GetElement(receiver, index);
8717 if (element.is_null()) return false;
8718 visitor->visit(index, element);
8719 // Skip to next different index (i.e., omit duplicates).
8720 do {
8721 j++;
8722 } while (j < n && indices[j] == index);
8723 }
8724 break;
8725 }
Steve Block44f0eee2011-05-26 01:26:41 +01008726 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8727 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8728 receiver->elements()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008729 for (uint32_t j = 0; j < length; j++) {
8730 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8731 visitor->visit(j, e);
8732 }
8733 break;
8734 }
8735 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8736 IterateExternalArrayElements<ExternalByteArray, int8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008737 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008738 break;
8739 }
8740 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8741 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008742 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008743 break;
8744 }
8745 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8746 IterateExternalArrayElements<ExternalShortArray, int16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008747 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008748 break;
8749 }
8750 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8751 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008752 isolate, receiver, true, true, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008753 break;
8754 }
8755 case JSObject::EXTERNAL_INT_ELEMENTS: {
8756 IterateExternalArrayElements<ExternalIntArray, int32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008757 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008758 break;
8759 }
8760 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8761 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
Steve Block44f0eee2011-05-26 01:26:41 +01008762 isolate, receiver, true, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008763 break;
8764 }
8765 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8766 IterateExternalArrayElements<ExternalFloatArray, float>(
Steve Block44f0eee2011-05-26 01:26:41 +01008767 isolate, receiver, false, false, visitor);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008768 break;
8769 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008770 default:
8771 UNREACHABLE();
8772 break;
8773 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008774 visitor->increase_index_offset(length);
8775 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008776}
8777
8778
8779/**
8780 * Array::concat implementation.
8781 * See ECMAScript 262, 15.4.4.4.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008782 * TODO(581): Fix non-compliance for very large concatenations and update to
Leon Clarkee46be812010-01-19 14:06:41 +00008783 * following the ECMAScript 5 specification.
Steve Blocka7e24c12009-10-30 11:49:00 +00008784 */
Ben Murdoch8b112d22011-06-08 16:22:53 +01008785RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008786 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +01008787 HandleScope handle_scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008788
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008789 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8790 int argument_count = static_cast<int>(arguments->length()->Number());
8791 RUNTIME_ASSERT(arguments->HasFastElements());
8792 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008793
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008794 // Pass 1: estimate the length and number of elements of the result.
8795 // The actual length can be larger if any of the arguments have getters
8796 // that mutate other arguments (but will otherwise be precise).
8797 // The number of elements is precise if there are no inherited elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00008798
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008799 uint32_t estimate_result_length = 0;
8800 uint32_t estimate_nof_elements = 0;
8801 {
8802 for (int i = 0; i < argument_count; i++) {
8803 HandleScope loop_scope;
8804 Handle<Object> obj(elements->get(i));
8805 uint32_t length_estimate;
8806 uint32_t element_estimate;
8807 if (obj->IsJSArray()) {
8808 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8809 length_estimate =
8810 static_cast<uint32_t>(array->length()->Number());
8811 element_estimate =
8812 EstimateElementCount(array);
8813 } else {
8814 length_estimate = 1;
8815 element_estimate = 1;
8816 }
8817 // Avoid overflows by capping at kMaxElementCount.
8818 if (JSObject::kMaxElementCount - estimate_result_length <
8819 length_estimate) {
8820 estimate_result_length = JSObject::kMaxElementCount;
8821 } else {
8822 estimate_result_length += length_estimate;
8823 }
8824 if (JSObject::kMaxElementCount - estimate_nof_elements <
8825 element_estimate) {
8826 estimate_nof_elements = JSObject::kMaxElementCount;
8827 } else {
8828 estimate_nof_elements += element_estimate;
Steve Blocka7e24c12009-10-30 11:49:00 +00008829 }
8830 }
8831 }
8832
Steve Blocka7e24c12009-10-30 11:49:00 +00008833 // If estimated number of elements is more than half of length, a
8834 // fixed array (fast case) is more time and space-efficient than a
8835 // dictionary.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008836 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00008837
8838 Handle<FixedArray> storage;
8839 if (fast_case) {
8840 // The backing storage array must have non-existing elements to
8841 // preserve holes across concat operations.
Steve Block44f0eee2011-05-26 01:26:41 +01008842 storage = isolate->factory()->NewFixedArrayWithHoles(
8843 estimate_result_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00008844 } else {
8845 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8846 uint32_t at_least_space_for = estimate_nof_elements +
8847 (estimate_nof_elements >> 2);
8848 storage = Handle<FixedArray>::cast(
Steve Block44f0eee2011-05-26 01:26:41 +01008849 isolate->factory()->NewNumberDictionary(at_least_space_for));
Steve Blocka7e24c12009-10-30 11:49:00 +00008850 }
8851
Steve Block44f0eee2011-05-26 01:26:41 +01008852 ArrayConcatVisitor visitor(isolate, storage, fast_case);
Steve Blocka7e24c12009-10-30 11:49:00 +00008853
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008854 for (int i = 0; i < argument_count; i++) {
8855 Handle<Object> obj(elements->get(i));
8856 if (obj->IsJSArray()) {
8857 Handle<JSArray> array = Handle<JSArray>::cast(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008858 if (!IterateElements(isolate, array, &visitor)) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008859 return Failure::Exception();
8860 }
8861 } else {
8862 visitor.visit(0, obj);
8863 visitor.increase_index_offset(1);
8864 }
8865 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008866
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008867 return *visitor.ToArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00008868}
8869
8870
8871// This will not allocate (flatten the string), but it may run
8872// very slowly for very deeply nested ConsStrings. For debugging use only.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008873RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008874 NoHandleAllocation ha;
8875 ASSERT(args.length() == 1);
8876
8877 CONVERT_CHECKED(String, string, args[0]);
8878 StringInputBuffer buffer(string);
8879 while (buffer.has_more()) {
8880 uint16_t character = buffer.GetNext();
8881 PrintF("%c", character);
8882 }
8883 return string;
8884}
8885
8886// Moves all own elements of an object, that are below a limit, to positions
8887// starting at zero. All undefined values are placed after non-undefined values,
8888// and are followed by non-existing element. Does not change the length
8889// property.
8890// Returns the number of non-undefined elements collected.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008891RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008892 ASSERT(args.length() == 2);
8893 CONVERT_CHECKED(JSObject, object, args[0]);
8894 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8895 return object->PrepareElementsForSort(limit);
8896}
8897
8898
8899// Move contents of argument 0 (an array) to argument 1 (an array)
Ben Murdoch8b112d22011-06-08 16:22:53 +01008900RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008901 ASSERT(args.length() == 2);
8902 CONVERT_CHECKED(JSArray, from, args[0]);
8903 CONVERT_CHECKED(JSArray, to, args[1]);
Steve Block8defd9f2010-07-08 12:39:36 +01008904 HeapObject* new_elements = from->elements();
John Reck59135872010-11-02 12:39:01 -07008905 MaybeObject* maybe_new_map;
Steve Block44f0eee2011-05-26 01:26:41 +01008906 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8907 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
John Reck59135872010-11-02 12:39:01 -07008908 maybe_new_map = to->map()->GetFastElementsMap();
Steve Block8defd9f2010-07-08 12:39:36 +01008909 } else {
John Reck59135872010-11-02 12:39:01 -07008910 maybe_new_map = to->map()->GetSlowElementsMap();
Steve Block8defd9f2010-07-08 12:39:36 +01008911 }
John Reck59135872010-11-02 12:39:01 -07008912 Object* new_map;
8913 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
Steve Block8defd9f2010-07-08 12:39:36 +01008914 to->set_map(Map::cast(new_map));
8915 to->set_elements(new_elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00008916 to->set_length(from->length());
John Reck59135872010-11-02 12:39:01 -07008917 Object* obj;
8918 { MaybeObject* maybe_obj = from->ResetElements();
8919 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8920 }
Leon Clarke4515c472010-02-03 11:58:03 +00008921 from->set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00008922 return to;
8923}
8924
8925
Steve Block59151502010-09-22 15:07:15 +01008926// How many elements does this object/array have?
Ben Murdoch8b112d22011-06-08 16:22:53 +01008927RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008928 ASSERT(args.length() == 1);
Steve Block59151502010-09-22 15:07:15 +01008929 CONVERT_CHECKED(JSObject, object, args[0]);
8930 HeapObject* elements = object->elements();
Steve Blocka7e24c12009-10-30 11:49:00 +00008931 if (elements->IsDictionary()) {
8932 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
Steve Block59151502010-09-22 15:07:15 +01008933 } else if (object->IsJSArray()) {
8934 return JSArray::cast(object)->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008935 } else {
Steve Block59151502010-09-22 15:07:15 +01008936 return Smi::FromInt(FixedArray::cast(elements)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008937 }
8938}
8939
8940
Ben Murdoch8b112d22011-06-08 16:22:53 +01008941RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
Steve Block44f0eee2011-05-26 01:26:41 +01008942 HandleScope handle_scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +01008943
8944 ASSERT_EQ(3, args.length());
8945
8946 CONVERT_ARG_CHECKED(JSObject, object, 0);
8947 Handle<Object> key1 = args.at<Object>(1);
8948 Handle<Object> key2 = args.at<Object>(2);
8949
8950 uint32_t index1, index2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008951 if (!key1->ToArrayIndex(&index1)
8952 || !key2->ToArrayIndex(&index2)) {
Steve Block44f0eee2011-05-26 01:26:41 +01008953 return isolate->ThrowIllegalOperation();
Steve Block6ded16b2010-05-10 14:33:55 +01008954 }
8955
8956 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8957 Handle<Object> tmp1 = GetElement(jsobject, index1);
Steve Block44f0eee2011-05-26 01:26:41 +01008958 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
Steve Block6ded16b2010-05-10 14:33:55 +01008959 Handle<Object> tmp2 = GetElement(jsobject, index2);
Steve Block44f0eee2011-05-26 01:26:41 +01008960 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
Steve Block6ded16b2010-05-10 14:33:55 +01008961
Steve Block44f0eee2011-05-26 01:26:41 +01008962 RETURN_IF_EMPTY_HANDLE(isolate,
8963 SetElement(jsobject, index1, tmp2, kStrictMode));
8964 RETURN_IF_EMPTY_HANDLE(isolate,
8965 SetElement(jsobject, index2, tmp1, kStrictMode));
Steve Block6ded16b2010-05-10 14:33:55 +01008966
Steve Block44f0eee2011-05-26 01:26:41 +01008967 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01008968}
8969
8970
Steve Blocka7e24c12009-10-30 11:49:00 +00008971// Returns an array that tells you where in the [0, length) interval an array
Steve Block59151502010-09-22 15:07:15 +01008972// might have elements. Can either return keys (positive integers) or
8973// intervals (pair of a negative integer (-start-1) followed by a
8974// positive (length)) or undefined values.
8975// Intervals can span over some keys that are not in the object.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008977 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +01008978 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008979 CONVERT_ARG_CHECKED(JSObject, array, 0);
8980 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
8981 if (array->elements()->IsDictionary()) {
8982 // Create an array and get all the keys into it, then remove all the
8983 // keys that are not integers in the range 0 to length-1.
8984 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
8985 int keys_length = keys->length();
8986 for (int i = 0; i < keys_length; i++) {
8987 Object* key = keys->get(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008988 uint32_t index = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008989 if (!key->ToArrayIndex(&index) || index >= length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008990 // Zap invalid keys.
8991 keys->set_undefined(i);
8992 }
8993 }
Steve Block44f0eee2011-05-26 01:26:41 +01008994 return *isolate->factory()->NewJSArrayWithElements(keys);
Steve Blocka7e24c12009-10-30 11:49:00 +00008995 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008996 ASSERT(array->HasFastElements());
Steve Block44f0eee2011-05-26 01:26:41 +01008997 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +00008998 // -1 means start of array.
Leon Clarke4515c472010-02-03 11:58:03 +00008999 single_interval->set(0, Smi::FromInt(-1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009000 uint32_t actual_length =
9001 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009002 uint32_t min_length = actual_length < length ? actual_length : length;
9003 Handle<Object> length_object =
Steve Block44f0eee2011-05-26 01:26:41 +01009004 isolate->factory()->NewNumber(static_cast<double>(min_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009005 single_interval->set(1, *length_object);
Steve Block44f0eee2011-05-26 01:26:41 +01009006 return *isolate->factory()->NewJSArrayWithElements(single_interval);
Steve Blocka7e24c12009-10-30 11:49:00 +00009007 }
9008}
9009
9010
9011// DefineAccessor takes an optional final argument which is the
9012// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9013// to the way accessors are implemented, it is set for both the getter
9014// and setter on the first call to DefineAccessor and ignored on
9015// subsequent calls.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009016RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009017 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9018 // Compute attributes.
9019 PropertyAttributes attributes = NONE;
9020 if (args.length() == 5) {
9021 CONVERT_CHECKED(Smi, attrs, args[4]);
9022 int value = attrs->value();
9023 // Only attribute bits should be set.
9024 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9025 attributes = static_cast<PropertyAttributes>(value);
9026 }
9027
9028 CONVERT_CHECKED(JSObject, obj, args[0]);
9029 CONVERT_CHECKED(String, name, args[1]);
9030 CONVERT_CHECKED(Smi, flag, args[2]);
9031 CONVERT_CHECKED(JSFunction, fun, args[3]);
9032 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9033}
9034
9035
Ben Murdoch8b112d22011-06-08 16:22:53 +01009036RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009037 ASSERT(args.length() == 3);
9038 CONVERT_CHECKED(JSObject, obj, args[0]);
9039 CONVERT_CHECKED(String, name, args[1]);
9040 CONVERT_CHECKED(Smi, flag, args[2]);
9041 return obj->LookupAccessor(name, flag->value() == 0);
9042}
9043
9044
9045#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch8b112d22011-06-08 16:22:53 +01009046RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009047 ASSERT(args.length() == 0);
9048 return Execution::DebugBreakHelper();
9049}
9050
9051
9052// Helper functions for wrapping and unwrapping stack frame ids.
9053static Smi* WrapFrameId(StackFrame::Id id) {
9054 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
9055 return Smi::FromInt(id >> 2);
9056}
9057
9058
9059static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9060 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9061}
9062
9063
9064// Adds a JavaScript function as a debug event listener.
9065// args[0]: debug event listener function to set or null or undefined for
9066// clearing the event listener function
9067// args[1]: object supplied during callback
Ben Murdoch8b112d22011-06-08 16:22:53 +01009068RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009069 ASSERT(args.length() == 2);
9070 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9071 args[0]->IsUndefined() ||
9072 args[0]->IsNull());
9073 Handle<Object> callback = args.at<Object>(0);
9074 Handle<Object> data = args.at<Object>(1);
Steve Block44f0eee2011-05-26 01:26:41 +01009075 isolate->debugger()->SetEventListener(callback, data);
Steve Blocka7e24c12009-10-30 11:49:00 +00009076
Steve Block44f0eee2011-05-26 01:26:41 +01009077 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009078}
9079
9080
Ben Murdoch8b112d22011-06-08 16:22:53 +01009081RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009082 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009083 isolate->stack_guard()->DebugBreak();
9084 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009085}
9086
9087
Steve Block44f0eee2011-05-26 01:26:41 +01009088static MaybeObject* DebugLookupResultValue(Heap* heap,
9089 Object* receiver,
9090 String* name,
John Reck59135872010-11-02 12:39:01 -07009091 LookupResult* result,
9092 bool* caught_exception) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009093 Object* value;
9094 switch (result->type()) {
9095 case NORMAL:
9096 value = result->holder()->GetNormalizedProperty(result);
9097 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +01009098 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009099 }
9100 return value;
9101 case FIELD:
9102 value =
9103 JSObject::cast(
9104 result->holder())->FastPropertyAt(result->GetFieldIndex());
9105 if (value->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +01009106 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009107 }
9108 return value;
9109 case CONSTANT_FUNCTION:
9110 return result->GetConstantFunction();
9111 case CALLBACKS: {
9112 Object* structure = result->GetCallbackObject();
9113 if (structure->IsProxy() || structure->IsAccessorInfo()) {
John Reck59135872010-11-02 12:39:01 -07009114 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
Steve Blocka7e24c12009-10-30 11:49:00 +00009115 receiver, structure, name, result->holder());
John Reck59135872010-11-02 12:39:01 -07009116 if (!maybe_value->ToObject(&value)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009117 if (maybe_value->IsRetryAfterGC()) return maybe_value;
John Reck59135872010-11-02 12:39:01 -07009118 ASSERT(maybe_value->IsException());
Steve Block44f0eee2011-05-26 01:26:41 +01009119 maybe_value = heap->isolate()->pending_exception();
9120 heap->isolate()->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00009121 if (caught_exception != NULL) {
9122 *caught_exception = true;
9123 }
John Reck59135872010-11-02 12:39:01 -07009124 return maybe_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009125 }
9126 return value;
9127 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009128 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009129 }
9130 }
9131 case INTERCEPTOR:
9132 case MAP_TRANSITION:
Steve Block44f0eee2011-05-26 01:26:41 +01009133 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00009134 case CONSTANT_TRANSITION:
9135 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01009136 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009137 default:
9138 UNREACHABLE();
9139 }
9140 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01009141 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009142}
9143
9144
9145// Get debugger related details for an object property.
9146// args[0]: object holding property
9147// args[1]: name of the property
9148//
9149// The array returned contains the following information:
9150// 0: Property value
9151// 1: Property details
9152// 2: Property value is exception
9153// 3: Getter function if defined
9154// 4: Setter function if defined
9155// Items 2-4 are only filled if the property has either a getter or a setter
9156// defined through __defineGetter__ and/or __defineSetter__.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009157RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +01009158 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009159
9160 ASSERT(args.length() == 2);
9161
9162 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9163 CONVERT_ARG_CHECKED(String, name, 1);
9164
9165 // Make sure to set the current context to the context before the debugger was
9166 // entered (if the debugger is entered). The reason for switching context here
9167 // is that for some property lookups (accessors and interceptors) callbacks
9168 // into the embedding application can occour, and the embedding application
9169 // could have the assumption that its own global context is the current
9170 // context and not some internal debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +01009171 SaveContext save(isolate);
9172 if (isolate->debug()->InDebugger()) {
9173 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
Steve Blocka7e24c12009-10-30 11:49:00 +00009174 }
9175
9176 // Skip the global proxy as it has no properties and always delegates to the
9177 // real global object.
9178 if (obj->IsJSGlobalProxy()) {
9179 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9180 }
9181
9182
9183 // Check if the name is trivially convertible to an index and get the element
9184 // if so.
9185 uint32_t index;
9186 if (name->AsArrayIndex(&index)) {
Steve Block44f0eee2011-05-26 01:26:41 +01009187 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07009188 Object* element_or_char;
9189 { MaybeObject* maybe_element_or_char =
Steve Block44f0eee2011-05-26 01:26:41 +01009190 Runtime::GetElementOrCharAt(isolate, obj, index);
John Reck59135872010-11-02 12:39:01 -07009191 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9192 return maybe_element_or_char;
9193 }
9194 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009195 details->set(0, element_or_char);
Steve Blocka7e24c12009-10-30 11:49:00 +00009196 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
Steve Block44f0eee2011-05-26 01:26:41 +01009197 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009198 }
9199
9200 // Find the number of objects making up this.
9201 int length = LocalPrototypeChainLength(*obj);
9202
9203 // Try local lookup on each of the objects.
9204 Handle<JSObject> jsproto = obj;
9205 for (int i = 0; i < length; i++) {
9206 LookupResult result;
9207 jsproto->LocalLookup(*name, &result);
9208 if (result.IsProperty()) {
9209 // LookupResult is not GC safe as it holds raw object pointers.
9210 // GC can happen later in this code so put the required fields into
9211 // local variables using handles when required for later use.
9212 PropertyType result_type = result.type();
9213 Handle<Object> result_callback_obj;
9214 if (result_type == CALLBACKS) {
Steve Block44f0eee2011-05-26 01:26:41 +01009215 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9216 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009217 }
9218 Smi* property_details = result.GetPropertyDetails().AsSmi();
9219 // DebugLookupResultValue can cause GC so details from LookupResult needs
9220 // to be copied to handles before this.
9221 bool caught_exception = false;
John Reck59135872010-11-02 12:39:01 -07009222 Object* raw_value;
9223 { MaybeObject* maybe_raw_value =
Steve Block44f0eee2011-05-26 01:26:41 +01009224 DebugLookupResultValue(isolate->heap(), *obj, *name,
9225 &result, &caught_exception);
John Reck59135872010-11-02 12:39:01 -07009226 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9227 }
Steve Block44f0eee2011-05-26 01:26:41 +01009228 Handle<Object> value(raw_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009229
9230 // If the callback object is a fixed array then it contains JavaScript
9231 // getter and/or setter.
9232 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9233 result_callback_obj->IsFixedArray();
9234 Handle<FixedArray> details =
Steve Block44f0eee2011-05-26 01:26:41 +01009235 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009236 details->set(0, *value);
9237 details->set(1, property_details);
9238 if (hasJavaScriptAccessors) {
9239 details->set(2,
Steve Block44f0eee2011-05-26 01:26:41 +01009240 caught_exception ? isolate->heap()->true_value()
9241 : isolate->heap()->false_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009242 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9243 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9244 }
9245
Steve Block44f0eee2011-05-26 01:26:41 +01009246 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009247 }
9248 if (i < length - 1) {
9249 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9250 }
9251 }
9252
Steve Block44f0eee2011-05-26 01:26:41 +01009253 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009254}
9255
9256
Ben Murdoch8b112d22011-06-08 16:22:53 +01009257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
Steve Block44f0eee2011-05-26 01:26:41 +01009258 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009259
9260 ASSERT(args.length() == 2);
9261
9262 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9263 CONVERT_ARG_CHECKED(String, name, 1);
9264
9265 LookupResult result;
9266 obj->Lookup(*name, &result);
9267 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01009268 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009269 }
Steve Block44f0eee2011-05-26 01:26:41 +01009270 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009271}
9272
9273
Steve Blocka7e24c12009-10-30 11:49:00 +00009274// Return the property type calculated from the property details.
9275// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009276RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009277 ASSERT(args.length() == 1);
9278 CONVERT_CHECKED(Smi, details, args[0]);
9279 PropertyType type = PropertyDetails(details).type();
9280 return Smi::FromInt(static_cast<int>(type));
9281}
9282
9283
9284// Return the property attribute calculated from the property details.
9285// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009286RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009287 ASSERT(args.length() == 1);
9288 CONVERT_CHECKED(Smi, details, args[0]);
9289 PropertyAttributes attributes = PropertyDetails(details).attributes();
9290 return Smi::FromInt(static_cast<int>(attributes));
9291}
9292
9293
9294// Return the property insertion index calculated from the property details.
9295// args[0]: smi with property details.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009296RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009297 ASSERT(args.length() == 1);
9298 CONVERT_CHECKED(Smi, details, args[0]);
9299 int index = PropertyDetails(details).index();
9300 return Smi::FromInt(index);
9301}
9302
9303
Steve Blocka7e24c12009-10-30 11:49:00 +00009304// Return property value from named interceptor.
9305// args[0]: object
9306// args[1]: property name
Ben Murdoch8b112d22011-06-08 16:22:53 +01009307RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
Steve Block44f0eee2011-05-26 01:26:41 +01009308 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009309 ASSERT(args.length() == 2);
9310 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9311 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9312 CONVERT_ARG_CHECKED(String, name, 1);
9313
9314 PropertyAttributes attributes;
9315 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
9316}
9317
9318
9319// Return element value from indexed interceptor.
9320// args[0]: object
9321// args[1]: index
Ben Murdoch8b112d22011-06-08 16:22:53 +01009322RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
Steve Block44f0eee2011-05-26 01:26:41 +01009323 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009324 ASSERT(args.length() == 2);
9325 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9326 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9327 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9328
9329 return obj->GetElementWithInterceptor(*obj, index);
9330}
9331
9332
Ben Murdoch8b112d22011-06-08 16:22:53 +01009333RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009334 ASSERT(args.length() >= 1);
9335 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
9336 // Check that the break id is valid.
Steve Block44f0eee2011-05-26 01:26:41 +01009337 if (isolate->debug()->break_id() == 0 ||
9338 break_id != isolate->debug()->break_id()) {
9339 return isolate->Throw(
9340 isolate->heap()->illegal_execution_state_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00009341 }
9342
Steve Block44f0eee2011-05-26 01:26:41 +01009343 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009344}
9345
9346
Ben Murdoch8b112d22011-06-08 16:22:53 +01009347RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
Steve Block44f0eee2011-05-26 01:26:41 +01009348 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009349 ASSERT(args.length() == 1);
9350
9351 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009352 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009353 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9354 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -07009355 if (!maybe_result->ToObject(&result)) return maybe_result;
9356 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009357
9358 // Count all frames which are relevant to debugging stack trace.
9359 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009360 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +00009361 if (id == StackFrame::NO_ID) {
9362 // If there is no JavaScript stack frame count is 0.
9363 return Smi::FromInt(0);
9364 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009365 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
Steve Blocka7e24c12009-10-30 11:49:00 +00009366 return Smi::FromInt(n);
9367}
9368
9369
9370static const int kFrameDetailsFrameIdIndex = 0;
9371static const int kFrameDetailsReceiverIndex = 1;
9372static const int kFrameDetailsFunctionIndex = 2;
9373static const int kFrameDetailsArgumentCountIndex = 3;
9374static const int kFrameDetailsLocalCountIndex = 4;
9375static const int kFrameDetailsSourcePositionIndex = 5;
9376static const int kFrameDetailsConstructCallIndex = 6;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009377static const int kFrameDetailsAtReturnIndex = 7;
9378static const int kFrameDetailsDebuggerFrameIndex = 8;
9379static const int kFrameDetailsFirstDynamicIndex = 9;
Steve Blocka7e24c12009-10-30 11:49:00 +00009380
9381// Return an array with frame details
9382// args[0]: number: break id
9383// args[1]: number: frame index
9384//
9385// The array returned contains the following information:
9386// 0: Frame id
9387// 1: Receiver
9388// 2: Function
9389// 3: Argument count
9390// 4: Local count
9391// 5: Source position
9392// 6: Constructor call
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009393// 7: Is at return
9394// 8: Debugger frame
Steve Blocka7e24c12009-10-30 11:49:00 +00009395// Arguments name, value
9396// Locals name, value
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009397// Return value if any
Ben Murdoch8b112d22011-06-08 16:22:53 +01009398RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +01009399 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009400 ASSERT(args.length() == 2);
9401
9402 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009403 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009404 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9405 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -07009406 if (!maybe_check->ToObject(&check)) return maybe_check;
9407 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009408 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
Steve Block44f0eee2011-05-26 01:26:41 +01009409 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009410
9411 // Find the relevant frame with the requested index.
Steve Block44f0eee2011-05-26 01:26:41 +01009412 StackFrame::Id id = isolate->debug()->break_frame_id();
Steve Blocka7e24c12009-10-30 11:49:00 +00009413 if (id == StackFrame::NO_ID) {
9414 // If there are no JavaScript stack frames return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +01009415 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009416 }
9417 int count = 0;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009418 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +00009419 for (; !it.done(); it.Advance()) {
9420 if (count == index) break;
9421 count++;
9422 }
Steve Block44f0eee2011-05-26 01:26:41 +01009423 if (it.done()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009424
Ben Murdochb0fe1622011-05-05 13:52:32 +01009425 bool is_optimized_frame =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009426 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009427
Steve Blocka7e24c12009-10-30 11:49:00 +00009428 // Traverse the saved contexts chain to find the active context for the
9429 // selected frame.
Steve Block44f0eee2011-05-26 01:26:41 +01009430 SaveContext* save = isolate->save_context();
Steve Blocka7e24c12009-10-30 11:49:00 +00009431 while (save != NULL && !save->below(it.frame())) {
9432 save = save->prev();
9433 }
9434 ASSERT(save != NULL);
9435
9436 // Get the frame id.
Steve Block44f0eee2011-05-26 01:26:41 +01009437 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009438
9439 // Find source position.
Steve Block44f0eee2011-05-26 01:26:41 +01009440 int position =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009441 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
Steve Blocka7e24c12009-10-30 11:49:00 +00009442
9443 // Check for constructor frame.
9444 bool constructor = it.frame()->IsConstructor();
9445
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009446 // Get scope info and read from it for local variable information.
9447 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
9448 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
9449 ScopeInfo<> info(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00009450
9451 // Get the context.
9452 Handle<Context> context(Context::cast(it.frame()->context()));
9453
9454 // Get the locals names and values into a temporary array.
9455 //
9456 // TODO(1240907): Hide compiler-introduced stack variables
9457 // (e.g. .result)? For users of the debugger, they will probably be
9458 // confusing.
Steve Block44f0eee2011-05-26 01:26:41 +01009459 Handle<FixedArray> locals =
9460 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00009461
Ben Murdochb0fe1622011-05-05 13:52:32 +01009462 // Fill in the names of the locals.
9463 for (int i = 0; i < info.NumberOfLocals(); i++) {
9464 locals->set(i * 2, *info.LocalName(i));
9465 }
9466
9467 // Fill in the values of the locals.
9468 for (int i = 0; i < info.NumberOfLocals(); i++) {
9469 if (is_optimized_frame) {
9470 // If we are inspecting an optimized frame use undefined as the
9471 // value for all locals.
9472 //
Steve Block1e0659c2011-05-24 12:43:12 +01009473 // TODO(1140): We should be able to get the correct values
Ben Murdochb0fe1622011-05-05 13:52:32 +01009474 // for locals in optimized frames.
Steve Block44f0eee2011-05-26 01:26:41 +01009475 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009476 } else if (i < info.number_of_stack_slots()) {
9477 // Get the value from the stack.
Steve Blocka7e24c12009-10-30 11:49:00 +00009478 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9479 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00009480 // Traverse the context chain to the function context as all local
9481 // variables stored in the context will be on the function context.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009482 Handle<String> name = info.LocalName(i);
Steve Blocka7e24c12009-10-30 11:49:00 +00009483 while (!context->is_function_context()) {
9484 context = Handle<Context>(context->previous());
9485 }
9486 ASSERT(context->is_function_context());
9487 locals->set(i * 2 + 1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009488 context->get(scope_info->ContextSlotIndex(*name, NULL)));
Steve Blocka7e24c12009-10-30 11:49:00 +00009489 }
9490 }
9491
Ben Murdochb0fe1622011-05-05 13:52:32 +01009492 // Check whether this frame is positioned at return. If not top
9493 // frame or if the frame is optimized it cannot be at a return.
9494 bool at_return = false;
9495 if (!is_optimized_frame && index == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01009496 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009497 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009498
9499 // If positioned just before return find the value to be returned and add it
9500 // to the frame information.
Steve Block44f0eee2011-05-26 01:26:41 +01009501 Handle<Object> return_value = isolate->factory()->undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009502 if (at_return) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009503 StackFrameIterator it2(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009504 Address internal_frame_sp = NULL;
9505 while (!it2.done()) {
9506 if (it2.frame()->is_internal()) {
9507 internal_frame_sp = it2.frame()->sp();
9508 } else {
9509 if (it2.frame()->is_java_script()) {
9510 if (it2.frame()->id() == it.frame()->id()) {
9511 // The internal frame just before the JavaScript frame contains the
9512 // value to return on top. A debug break at return will create an
9513 // internal frame to store the return value (eax/rax/r0) before
9514 // entering the debug break exit frame.
9515 if (internal_frame_sp != NULL) {
9516 return_value =
Steve Block44f0eee2011-05-26 01:26:41 +01009517 Handle<Object>(Memory::Object_at(internal_frame_sp),
9518 isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009519 break;
9520 }
9521 }
9522 }
9523
9524 // Indicate that the previous frame was not an internal frame.
9525 internal_frame_sp = NULL;
9526 }
9527 it2.Advance();
9528 }
9529 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009530
9531 // Now advance to the arguments adapter frame (if any). It contains all
9532 // the provided parameters whereas the function frame always have the number
9533 // of arguments matching the functions parameters. The rest of the
9534 // information (except for what is collected above) is the same.
9535 it.AdvanceToArgumentsFrame();
9536
9537 // Find the number of arguments to fill. At least fill the number of
9538 // parameters for the function and fill more if more parameters are provided.
9539 int argument_count = info.number_of_parameters();
Steve Block44f0eee2011-05-26 01:26:41 +01009540 if (argument_count < it.frame()->ComputeParametersCount()) {
9541 argument_count = it.frame()->ComputeParametersCount();
Steve Blocka7e24c12009-10-30 11:49:00 +00009542 }
9543
9544 // Calculate the size of the result.
9545 int details_size = kFrameDetailsFirstDynamicIndex +
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009546 2 * (argument_count + info.NumberOfLocals()) +
9547 (at_return ? 1 : 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009548 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00009549
9550 // Add the frame id.
9551 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9552
9553 // Add the function (same as in function frame).
9554 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9555
9556 // Add the arguments count.
9557 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9558
9559 // Add the locals count
9560 details->set(kFrameDetailsLocalCountIndex,
9561 Smi::FromInt(info.NumberOfLocals()));
9562
9563 // Add the source position.
9564 if (position != RelocInfo::kNoPosition) {
9565 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9566 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009567 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009568 }
9569
9570 // Add the constructor information.
Steve Block44f0eee2011-05-26 01:26:41 +01009571 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
Steve Blocka7e24c12009-10-30 11:49:00 +00009572
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009573 // Add the at return information.
Steve Block44f0eee2011-05-26 01:26:41 +01009574 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009575
Steve Blocka7e24c12009-10-30 11:49:00 +00009576 // Add information on whether this frame is invoked in the debugger context.
9577 details->set(kFrameDetailsDebuggerFrameIndex,
Steve Block44f0eee2011-05-26 01:26:41 +01009578 heap->ToBoolean(*save->context() ==
9579 *isolate->debug()->debug_context()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009580
9581 // Fill the dynamic part.
9582 int details_index = kFrameDetailsFirstDynamicIndex;
9583
9584 // Add arguments name and value.
9585 for (int i = 0; i < argument_count; i++) {
9586 // Name of the argument.
9587 if (i < info.number_of_parameters()) {
9588 details->set(details_index++, *info.parameter_name(i));
9589 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009590 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009591 }
9592
Ben Murdochb0fe1622011-05-05 13:52:32 +01009593 // Parameter value. If we are inspecting an optimized frame, use
9594 // undefined as the value.
9595 //
9596 // TODO(3141533): We should be able to get the actual parameter
9597 // value for optimized frames.
9598 if (!is_optimized_frame &&
Steve Block44f0eee2011-05-26 01:26:41 +01009599 (i < it.frame()->ComputeParametersCount())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009600 details->set(details_index++, it.frame()->GetParameter(i));
9601 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01009602 details->set(details_index++, heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009603 }
9604 }
9605
9606 // Add locals name and value from the temporary copy from the function frame.
9607 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9608 details->set(details_index++, locals->get(i));
9609 }
9610
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009611 // Add the value being returned.
9612 if (at_return) {
9613 details->set(details_index++, *return_value);
9614 }
9615
Steve Blocka7e24c12009-10-30 11:49:00 +00009616 // Add the receiver (same as in function frame).
9617 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9618 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
Steve Block44f0eee2011-05-26 01:26:41 +01009619 Handle<Object> receiver(it.frame()->receiver(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009620 if (!receiver->IsJSObject()) {
9621 // If the receiver is NOT a JSObject we have hit an optimization
9622 // where a value object is not converted into a wrapped JS objects.
9623 // To hide this optimization from the debugger, we wrap the receiver
9624 // by creating correct wrapper object based on the calling frame's
9625 // global context.
9626 it.Advance();
9627 Handle<Context> calling_frames_global_context(
9628 Context::cast(Context::cast(it.frame()->context())->global_context()));
Steve Block44f0eee2011-05-26 01:26:41 +01009629 receiver =
9630 isolate->factory()->ToObject(receiver, calling_frames_global_context);
Steve Blocka7e24c12009-10-30 11:49:00 +00009631 }
9632 details->set(kFrameDetailsReceiverIndex, *receiver);
9633
9634 ASSERT_EQ(details_size, details_index);
Steve Block44f0eee2011-05-26 01:26:41 +01009635 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009636}
9637
9638
9639// Copy all the context locals into an object used to materialize a scope.
Steve Block1e0659c2011-05-24 12:43:12 +01009640static bool CopyContextLocalsToScopeObject(
Steve Block44f0eee2011-05-26 01:26:41 +01009641 Isolate* isolate,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009642 Handle<SerializedScopeInfo> serialized_scope_info,
9643 ScopeInfo<>& scope_info,
9644 Handle<Context> context,
9645 Handle<JSObject> scope_object) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009646 // Fill all context locals to the context extension.
9647 for (int i = Context::MIN_CONTEXT_SLOTS;
9648 i < scope_info.number_of_context_slots();
9649 i++) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009650 int context_index = serialized_scope_info->ContextSlotIndex(
9651 *scope_info.context_slot_name(i), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009652
9653 // Don't include the arguments shadow (.arguments) context variable.
Steve Block44f0eee2011-05-26 01:26:41 +01009654 if (*scope_info.context_slot_name(i) !=
9655 isolate->heap()->arguments_shadow_symbol()) {
Steve Block1e0659c2011-05-24 12:43:12 +01009656 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +01009657 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +01009658 SetProperty(scope_object,
9659 scope_info.context_slot_name(i),
Steve Block44f0eee2011-05-26 01:26:41 +01009660 Handle<Object>(context->get(context_index), isolate),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009661 NONE,
9662 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009663 false);
Steve Blocka7e24c12009-10-30 11:49:00 +00009664 }
9665 }
Steve Block1e0659c2011-05-24 12:43:12 +01009666
9667 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009668}
9669
9670
9671// Create a plain JSObject which materializes the local scope for the specified
9672// frame.
Steve Block44f0eee2011-05-26 01:26:41 +01009673static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9674 JavaScriptFrame* frame) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009675 Handle<JSFunction> function(JSFunction::cast(frame->function()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009676 Handle<SharedFunctionInfo> shared(function->shared());
9677 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9678 ScopeInfo<> scope_info(*serialized_scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00009679
9680 // Allocate and initialize a JSObject with all the arguments, stack locals
9681 // heap locals and extension properties of the debugged function.
Steve Block44f0eee2011-05-26 01:26:41 +01009682 Handle<JSObject> local_scope =
9683 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +00009684
9685 // First fill all parameters.
9686 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
Steve Block1e0659c2011-05-24 12:43:12 +01009687 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +01009688 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +01009689 SetProperty(local_scope,
9690 scope_info.parameter_name(i),
Steve Block44f0eee2011-05-26 01:26:41 +01009691 Handle<Object>(frame->GetParameter(i), isolate),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009692 NONE,
9693 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009694 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +00009695 }
9696
9697 // Second fill all stack locals.
9698 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
Steve Block1e0659c2011-05-24 12:43:12 +01009699 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +01009700 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +01009701 SetProperty(local_scope,
9702 scope_info.stack_slot_name(i),
Steve Block44f0eee2011-05-26 01:26:41 +01009703 Handle<Object>(frame->GetExpression(i), isolate),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009704 NONE,
9705 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009706 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +00009707 }
9708
9709 // Third fill all context locals.
9710 Handle<Context> frame_context(Context::cast(frame->context()));
9711 Handle<Context> function_context(frame_context->fcontext());
Steve Block44f0eee2011-05-26 01:26:41 +01009712 if (!CopyContextLocalsToScopeObject(isolate,
9713 serialized_scope_info, scope_info,
Steve Block1e0659c2011-05-24 12:43:12 +01009714 function_context, local_scope)) {
9715 return Handle<JSObject>();
9716 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009717
9718 // Finally copy any properties from the function context extension. This will
9719 // be variables introduced by eval.
9720 if (function_context->closure() == *function) {
9721 if (function_context->has_extension() &&
9722 !function_context->IsGlobalContext()) {
9723 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
9724 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
9725 for (int i = 0; i < keys->length(); i++) {
9726 // Names of variables introduced by eval are strings.
9727 ASSERT(keys->get(i)->IsString());
9728 Handle<String> key(String::cast(keys->get(i)));
Steve Block1e0659c2011-05-24 12:43:12 +01009729 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +01009730 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009731 SetProperty(local_scope,
9732 key,
9733 GetProperty(ext, key),
9734 NONE,
9735 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009736 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +00009737 }
9738 }
9739 }
9740 return local_scope;
9741}
9742
9743
9744// Create a plain JSObject which materializes the closure content for the
9745// context.
Steve Block44f0eee2011-05-26 01:26:41 +01009746static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9747 Handle<Context> context) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009748 ASSERT(context->is_function_context());
9749
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009750 Handle<SharedFunctionInfo> shared(context->closure()->shared());
9751 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9752 ScopeInfo<> scope_info(*serialized_scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00009753
9754 // Allocate and initialize a JSObject with all the content of theis function
9755 // closure.
Steve Block44f0eee2011-05-26 01:26:41 +01009756 Handle<JSObject> closure_scope =
9757 isolate->factory()->NewJSObject(isolate->object_function());
Steve Blocka7e24c12009-10-30 11:49:00 +00009758
9759 // Check whether the arguments shadow object exists.
9760 int arguments_shadow_index =
Steve Block44f0eee2011-05-26 01:26:41 +01009761 shared->scope_info()->ContextSlotIndex(
9762 isolate->heap()->arguments_shadow_symbol(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009763 if (arguments_shadow_index >= 0) {
9764 // In this case all the arguments are available in the arguments shadow
9765 // object.
9766 Handle<JSObject> arguments_shadow(
9767 JSObject::cast(context->get(arguments_shadow_index)));
9768 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
John Reck59135872010-11-02 12:39:01 -07009769 // We don't expect exception-throwing getters on the arguments shadow.
9770 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
Steve Block1e0659c2011-05-24 12:43:12 +01009771 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +01009772 isolate,
Steve Block1e0659c2011-05-24 12:43:12 +01009773 SetProperty(closure_scope,
9774 scope_info.parameter_name(i),
Steve Block44f0eee2011-05-26 01:26:41 +01009775 Handle<Object>(element, isolate),
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009776 NONE,
9777 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009778 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +00009779 }
9780 }
9781
9782 // Fill all context locals to the context extension.
Steve Block44f0eee2011-05-26 01:26:41 +01009783 if (!CopyContextLocalsToScopeObject(isolate,
9784 serialized_scope_info, scope_info,
Steve Block1e0659c2011-05-24 12:43:12 +01009785 context, closure_scope)) {
9786 return Handle<JSObject>();
9787 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009788
9789 // Finally copy any properties from the function context extension. This will
9790 // be variables introduced by eval.
9791 if (context->has_extension()) {
9792 Handle<JSObject> ext(JSObject::cast(context->extension()));
9793 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
9794 for (int i = 0; i < keys->length(); i++) {
9795 // Names of variables introduced by eval are strings.
9796 ASSERT(keys->get(i)->IsString());
9797 Handle<String> key(String::cast(keys->get(i)));
Steve Block44f0eee2011-05-26 01:26:41 +01009798 RETURN_IF_EMPTY_HANDLE_VALUE(
9799 isolate,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009800 SetProperty(closure_scope,
9801 key,
9802 GetProperty(ext, key),
9803 NONE,
9804 kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +01009805 Handle<JSObject>());
Steve Blocka7e24c12009-10-30 11:49:00 +00009806 }
9807 }
9808
9809 return closure_scope;
9810}
9811
9812
9813// Iterate over the actual scopes visible from a stack frame. All scopes are
9814// backed by an actual context except the local scope, which is inserted
9815// "artifically" in the context chain.
9816class ScopeIterator {
9817 public:
9818 enum ScopeType {
9819 ScopeTypeGlobal = 0,
9820 ScopeTypeLocal,
9821 ScopeTypeWith,
9822 ScopeTypeClosure,
9823 // Every catch block contains an implicit with block (its parameter is
9824 // a JSContextExtensionObject) that extends current scope with a variable
9825 // holding exception object. Such with blocks are treated as scopes of their
9826 // own type.
9827 ScopeTypeCatch
9828 };
9829
Steve Block44f0eee2011-05-26 01:26:41 +01009830 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9831 : isolate_(isolate),
9832 frame_(frame),
Steve Blocka7e24c12009-10-30 11:49:00 +00009833 function_(JSFunction::cast(frame->function())),
9834 context_(Context::cast(frame->context())),
9835 local_done_(false),
9836 at_local_(false) {
9837
9838 // Check whether the first scope is actually a local scope.
9839 if (context_->IsGlobalContext()) {
9840 // If there is a stack slot for .result then this local scope has been
9841 // created for evaluating top level code and it is not a real local scope.
9842 // Checking for the existence of .result seems fragile, but the scope info
9843 // saved with the code object does not otherwise have that information.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009844 int index = function_->shared()->scope_info()->
Steve Block44f0eee2011-05-26 01:26:41 +01009845 StackSlotIndex(isolate_->heap()->result_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00009846 at_local_ = index < 0;
9847 } else if (context_->is_function_context()) {
9848 at_local_ = true;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009849 } else if (context_->closure() != *function_) {
9850 // The context_ is a with block from the outer function.
9851 ASSERT(context_->has_extension());
9852 at_local_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009853 }
9854 }
9855
9856 // More scopes?
9857 bool Done() { return context_.is_null(); }
9858
9859 // Move to the next scope.
9860 void Next() {
9861 // If at a local scope mark the local scope as passed.
9862 if (at_local_) {
9863 at_local_ = false;
9864 local_done_ = true;
9865
9866 // If the current context is not associated with the local scope the
9867 // current context is the next real scope, so don't move to the next
9868 // context in this case.
9869 if (context_->closure() != *function_) {
9870 return;
9871 }
9872 }
9873
9874 // The global scope is always the last in the chain.
9875 if (context_->IsGlobalContext()) {
9876 context_ = Handle<Context>();
9877 return;
9878 }
9879
9880 // Move to the next context.
9881 if (context_->is_function_context()) {
9882 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9883 } else {
9884 context_ = Handle<Context>(context_->previous());
9885 }
9886
9887 // If passing the local scope indicate that the current scope is now the
9888 // local scope.
9889 if (!local_done_ &&
9890 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9891 at_local_ = true;
9892 }
9893 }
9894
9895 // Return the type of the current scope.
9896 int Type() {
9897 if (at_local_) {
9898 return ScopeTypeLocal;
9899 }
9900 if (context_->IsGlobalContext()) {
9901 ASSERT(context_->global()->IsGlobalObject());
9902 return ScopeTypeGlobal;
9903 }
9904 if (context_->is_function_context()) {
9905 return ScopeTypeClosure;
9906 }
9907 ASSERT(context_->has_extension());
9908 // Current scope is either an explicit with statement or a with statement
9909 // implicitely generated for a catch block.
9910 // If the extension object here is a JSContextExtensionObject then
9911 // current with statement is one frome a catch block otherwise it's a
9912 // regular with statement.
9913 if (context_->extension()->IsJSContextExtensionObject()) {
9914 return ScopeTypeCatch;
9915 }
9916 return ScopeTypeWith;
9917 }
9918
9919 // Return the JavaScript object with the content of the current scope.
9920 Handle<JSObject> ScopeObject() {
9921 switch (Type()) {
9922 case ScopeIterator::ScopeTypeGlobal:
9923 return Handle<JSObject>(CurrentContext()->global());
9924 break;
9925 case ScopeIterator::ScopeTypeLocal:
9926 // Materialize the content of the local scope into a JSObject.
Steve Block44f0eee2011-05-26 01:26:41 +01009927 return MaterializeLocalScope(isolate_, frame_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009928 break;
9929 case ScopeIterator::ScopeTypeWith:
9930 case ScopeIterator::ScopeTypeCatch:
9931 // Return the with object.
9932 return Handle<JSObject>(CurrentContext()->extension());
9933 break;
9934 case ScopeIterator::ScopeTypeClosure:
9935 // Materialize the content of the closure scope into a JSObject.
Steve Block44f0eee2011-05-26 01:26:41 +01009936 return MaterializeClosure(isolate_, CurrentContext());
Steve Blocka7e24c12009-10-30 11:49:00 +00009937 break;
9938 }
9939 UNREACHABLE();
9940 return Handle<JSObject>();
9941 }
9942
9943 // Return the context for this scope. For the local context there might not
9944 // be an actual context.
9945 Handle<Context> CurrentContext() {
9946 if (at_local_ && context_->closure() != *function_) {
9947 return Handle<Context>();
9948 }
9949 return context_;
9950 }
9951
9952#ifdef DEBUG
9953 // Debug print of the content of the current scope.
9954 void DebugPrint() {
9955 switch (Type()) {
9956 case ScopeIterator::ScopeTypeGlobal:
9957 PrintF("Global:\n");
9958 CurrentContext()->Print();
9959 break;
9960
9961 case ScopeIterator::ScopeTypeLocal: {
9962 PrintF("Local:\n");
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009963 ScopeInfo<> scope_info(function_->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +00009964 scope_info.Print();
9965 if (!CurrentContext().is_null()) {
9966 CurrentContext()->Print();
9967 if (CurrentContext()->has_extension()) {
9968 Handle<JSObject> extension =
9969 Handle<JSObject>(CurrentContext()->extension());
9970 if (extension->IsJSContextExtensionObject()) {
9971 extension->Print();
9972 }
9973 }
9974 }
9975 break;
9976 }
9977
9978 case ScopeIterator::ScopeTypeWith: {
9979 PrintF("With:\n");
9980 Handle<JSObject> extension =
9981 Handle<JSObject>(CurrentContext()->extension());
9982 extension->Print();
9983 break;
9984 }
9985
9986 case ScopeIterator::ScopeTypeCatch: {
9987 PrintF("Catch:\n");
9988 Handle<JSObject> extension =
9989 Handle<JSObject>(CurrentContext()->extension());
9990 extension->Print();
9991 break;
9992 }
9993
9994 case ScopeIterator::ScopeTypeClosure: {
9995 PrintF("Closure:\n");
9996 CurrentContext()->Print();
9997 if (CurrentContext()->has_extension()) {
9998 Handle<JSObject> extension =
9999 Handle<JSObject>(CurrentContext()->extension());
10000 if (extension->IsJSContextExtensionObject()) {
10001 extension->Print();
10002 }
10003 }
10004 break;
10005 }
10006
10007 default:
10008 UNREACHABLE();
10009 }
10010 PrintF("\n");
10011 }
10012#endif
10013
10014 private:
Steve Block44f0eee2011-05-26 01:26:41 +010010015 Isolate* isolate_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010016 JavaScriptFrame* frame_;
10017 Handle<JSFunction> function_;
10018 Handle<Context> context_;
10019 bool local_done_;
10020 bool at_local_;
10021
10022 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10023};
10024
10025
Ben Murdoch8b112d22011-06-08 16:22:53 +010010026RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010010027 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010028 ASSERT(args.length() == 2);
10029
10030 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010031 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010032 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10033 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010034 if (!maybe_check->ToObject(&check)) return maybe_check;
10035 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010036 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10037
10038 // Get the frame where the debugging is performed.
10039 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010040 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000010041 JavaScriptFrame* frame = it.frame();
10042
10043 // Count the visible scopes.
10044 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010045 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010046 n++;
10047 }
10048
10049 return Smi::FromInt(n);
10050}
10051
10052
10053static const int kScopeDetailsTypeIndex = 0;
10054static const int kScopeDetailsObjectIndex = 1;
10055static const int kScopeDetailsSize = 2;
10056
10057// Return an array with scope details
10058// args[0]: number: break id
10059// args[1]: number: frame index
10060// args[2]: number: scope index
10061//
10062// The array returned contains the following information:
10063// 0: Scope type
10064// 1: Scope object
Ben Murdoch8b112d22011-06-08 16:22:53 +010010065RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010066 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010067 ASSERT(args.length() == 3);
10068
10069 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010070 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010071 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10072 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010073 if (!maybe_check->ToObject(&check)) return maybe_check;
10074 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010075 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10076 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10077
10078 // Get the frame where the debugging is performed.
10079 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010080 JavaScriptFrameIterator frame_it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000010081 JavaScriptFrame* frame = frame_it.frame();
10082
10083 // Find the requested scope.
10084 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010085 ScopeIterator it(isolate, frame);
Steve Blocka7e24c12009-10-30 11:49:00 +000010086 for (; !it.Done() && n < index; it.Next()) {
10087 n++;
10088 }
10089 if (it.Done()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010090 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010091 }
10092
10093 // Calculate the size of the result.
10094 int details_size = kScopeDetailsSize;
Steve Block44f0eee2011-05-26 01:26:41 +010010095 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
Steve Blocka7e24c12009-10-30 11:49:00 +000010096
10097 // Fill in scope details.
10098 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010099 Handle<JSObject> scope_object = it.ScopeObject();
Steve Block44f0eee2011-05-26 01:26:41 +010010100 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010101 details->set(kScopeDetailsObjectIndex, *scope_object);
Steve Blocka7e24c12009-10-30 11:49:00 +000010102
Steve Block44f0eee2011-05-26 01:26:41 +010010103 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010104}
10105
10106
Ben Murdoch8b112d22011-06-08 16:22:53 +010010107RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
Steve Block44f0eee2011-05-26 01:26:41 +010010108 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010109 ASSERT(args.length() == 0);
10110
10111#ifdef DEBUG
10112 // Print the scopes for the top frame.
10113 StackFrameLocator locator;
10114 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Steve Block44f0eee2011-05-26 01:26:41 +010010115 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010116 it.DebugPrint();
10117 }
10118#endif
Steve Block44f0eee2011-05-26 01:26:41 +010010119 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010120}
10121
10122
Ben Murdoch8b112d22011-06-08 16:22:53 +010010123RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
Steve Block44f0eee2011-05-26 01:26:41 +010010124 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010125 ASSERT(args.length() == 1);
10126
10127 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010128 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010129 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10130 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010131 if (!maybe_result->ToObject(&result)) return maybe_result;
10132 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010133
10134 // Count all archived V8 threads.
10135 int n = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010136 for (ThreadState* thread =
10137 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000010138 thread != NULL;
10139 thread = thread->Next()) {
10140 n++;
10141 }
10142
10143 // Total number of threads is current thread and archived threads.
10144 return Smi::FromInt(n + 1);
10145}
10146
10147
10148static const int kThreadDetailsCurrentThreadIndex = 0;
10149static const int kThreadDetailsThreadIdIndex = 1;
10150static const int kThreadDetailsSize = 2;
10151
10152// Return an array with thread details
10153// args[0]: number: break id
10154// args[1]: number: thread index
10155//
10156// The array returned contains the following information:
10157// 0: Is current thread?
10158// 1: Thread id
Ben Murdoch8b112d22011-06-08 16:22:53 +010010159RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
Steve Block44f0eee2011-05-26 01:26:41 +010010160 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010161 ASSERT(args.length() == 2);
10162
10163 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010164 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010165 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10166 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010167 if (!maybe_check->ToObject(&check)) return maybe_check;
10168 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010169 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10170
10171 // Allocate array for result.
Steve Block44f0eee2011-05-26 01:26:41 +010010172 Handle<FixedArray> details =
10173 isolate->factory()->NewFixedArray(kThreadDetailsSize);
Steve Blocka7e24c12009-10-30 11:49:00 +000010174
10175 // Thread index 0 is current thread.
10176 if (index == 0) {
10177 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010010178 details->set(kThreadDetailsCurrentThreadIndex,
10179 isolate->heap()->true_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010180 details->set(kThreadDetailsThreadIdIndex,
Ben Murdoch8b112d22011-06-08 16:22:53 +010010181 Smi::FromInt(ThreadId::Current().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010182 } else {
10183 // Find the thread with the requested index.
10184 int n = 1;
Steve Block44f0eee2011-05-26 01:26:41 +010010185 ThreadState* thread =
10186 isolate->thread_manager()->FirstThreadStateInUse();
Steve Blocka7e24c12009-10-30 11:49:00 +000010187 while (index != n && thread != NULL) {
10188 thread = thread->Next();
10189 n++;
10190 }
10191 if (thread == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010010192 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010193 }
10194
10195 // Fill the details.
Steve Block44f0eee2011-05-26 01:26:41 +010010196 details->set(kThreadDetailsCurrentThreadIndex,
10197 isolate->heap()->false_value());
Ben Murdoch8b112d22011-06-08 16:22:53 +010010198 details->set(kThreadDetailsThreadIdIndex,
10199 Smi::FromInt(thread->id().ToInteger()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010200 }
10201
10202 // Convert to JS array and return.
Steve Block44f0eee2011-05-26 01:26:41 +010010203 return *isolate->factory()->NewJSArrayWithElements(details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010204}
10205
10206
Ben Murdochbb769b22010-08-11 14:56:33 +010010207// Sets the disable break state
10208// args[0]: disable break state
Ben Murdoch8b112d22011-06-08 16:22:53 +010010209RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
Steve Block44f0eee2011-05-26 01:26:41 +010010210 HandleScope scope(isolate);
Ben Murdochbb769b22010-08-11 14:56:33 +010010211 ASSERT(args.length() == 1);
10212 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
Steve Block44f0eee2011-05-26 01:26:41 +010010213 isolate->debug()->set_disable_break(disable_break);
10214 return isolate->heap()->undefined_value();
Ben Murdochbb769b22010-08-11 14:56:33 +010010215}
10216
10217
Ben Murdoch8b112d22011-06-08 16:22:53 +010010218RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
Steve Block44f0eee2011-05-26 01:26:41 +010010219 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010220 ASSERT(args.length() == 1);
10221
10222 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10223 Handle<SharedFunctionInfo> shared(fun->shared());
10224 // Find the number of break points
10225 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
Steve Block44f0eee2011-05-26 01:26:41 +010010226 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010227 // Return array as JS array
Steve Block44f0eee2011-05-26 01:26:41 +010010228 return *isolate->factory()->NewJSArrayWithElements(
Steve Blocka7e24c12009-10-30 11:49:00 +000010229 Handle<FixedArray>::cast(break_locations));
10230}
10231
10232
10233// Set a break point in a function
10234// args[0]: function
10235// args[1]: number: break source position (within the function source)
10236// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010010237RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010010238 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010239 ASSERT(args.length() == 3);
10240 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10241 Handle<SharedFunctionInfo> shared(fun->shared());
10242 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10243 RUNTIME_ASSERT(source_position >= 0);
10244 Handle<Object> break_point_object_arg = args.at<Object>(2);
10245
10246 // Set break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010247 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10248 &source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010249
Steve Block8defd9f2010-07-08 12:39:36 +010010250 return Smi::FromInt(source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010251}
10252
10253
Steve Block44f0eee2011-05-26 01:26:41 +010010254Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10255 Handle<Script> script,
Steve Blocka7e24c12009-10-30 11:49:00 +000010256 int position) {
10257 // Iterate the heap looking for SharedFunctionInfo generated from the
10258 // script. The inner most SharedFunctionInfo containing the source position
10259 // for the requested break point is found.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010260 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
Steve Blocka7e24c12009-10-30 11:49:00 +000010261 // which is found is not compiled it is compiled and the heap is iterated
10262 // again as the compilation might create inner functions from the newly
10263 // compiled function and the actual requested break point might be in one of
10264 // these functions.
10265 bool done = false;
10266 // The current candidate for the source position:
10267 int target_start_position = RelocInfo::kNoPosition;
10268 Handle<SharedFunctionInfo> target;
Steve Blocka7e24c12009-10-30 11:49:00 +000010269 while (!done) {
10270 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000010271 for (HeapObject* obj = iterator.next();
10272 obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010273 if (obj->IsSharedFunctionInfo()) {
10274 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10275 if (shared->script() == *script) {
10276 // If the SharedFunctionInfo found has the requested script data and
10277 // contains the source position it is a candidate.
10278 int start_position = shared->function_token_position();
10279 if (start_position == RelocInfo::kNoPosition) {
10280 start_position = shared->start_position();
10281 }
10282 if (start_position <= position &&
10283 position <= shared->end_position()) {
10284 // If there is no candidate or this function is within the current
10285 // candidate this is the new candidate.
10286 if (target.is_null()) {
10287 target_start_position = start_position;
10288 target = shared;
10289 } else {
10290 if (target_start_position == start_position &&
10291 shared->end_position() == target->end_position()) {
10292 // If a top-level function contain only one function
10293 // declartion the source for the top-level and the function is
10294 // the same. In that case prefer the non top-level function.
10295 if (!shared->is_toplevel()) {
10296 target_start_position = start_position;
10297 target = shared;
10298 }
10299 } else if (target_start_position <= start_position &&
10300 shared->end_position() <= target->end_position()) {
10301 // This containment check includes equality as a function inside
10302 // a top-level function can share either start or end position
10303 // with the top-level function.
10304 target_start_position = start_position;
10305 target = shared;
10306 }
10307 }
10308 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010309 }
10310 }
10311 }
10312
Steve Blocka7e24c12009-10-30 11:49:00 +000010313 if (target.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010314 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010315 }
10316
10317 // If the candidate found is compiled we are done. NOTE: when lazy
10318 // compilation of inner functions is introduced some additional checking
10319 // needs to be done here to compile inner functions.
10320 done = target->is_compiled();
10321 if (!done) {
10322 // If the candidate is not compiled compile it to reveal any inner
10323 // functions which might contain the requested source position.
Leon Clarke4515c472010-02-03 11:58:03 +000010324 CompileLazyShared(target, KEEP_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +000010325 }
10326 }
10327
10328 return *target;
10329}
10330
10331
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010332// Changes the state of a break point in a script and returns source position
10333// where break point was set. NOTE: Regarding performance see the NOTE for
10334// GetScriptFromScriptData.
Steve Blocka7e24c12009-10-30 11:49:00 +000010335// args[0]: script to set break point in
10336// args[1]: number: break source position (within the script source)
10337// args[2]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010010338RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010010339 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010340 ASSERT(args.length() == 3);
10341 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10342 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10343 RUNTIME_ASSERT(source_position >= 0);
10344 Handle<Object> break_point_object_arg = args.at<Object>(2);
10345
10346 // Get the script from the script wrapper.
10347 RUNTIME_ASSERT(wrapper->value()->IsScript());
10348 Handle<Script> script(Script::cast(wrapper->value()));
10349
10350 Object* result = Runtime::FindSharedFunctionInfoInScript(
Steve Block44f0eee2011-05-26 01:26:41 +010010351 isolate, script, source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010352 if (!result->IsUndefined()) {
10353 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10354 // Find position within function. The script position might be before the
10355 // source position of the first function.
10356 int position;
10357 if (shared->start_position() > source_position) {
10358 position = 0;
10359 } else {
10360 position = source_position - shared->start_position();
10361 }
Steve Block44f0eee2011-05-26 01:26:41 +010010362 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010363 position += shared->start_position();
10364 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010365 }
Steve Block44f0eee2011-05-26 01:26:41 +010010366 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010367}
10368
10369
10370// Clear a break point
10371// args[0]: number: break point object
Ben Murdoch8b112d22011-06-08 16:22:53 +010010372RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
Steve Block44f0eee2011-05-26 01:26:41 +010010373 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010374 ASSERT(args.length() == 1);
10375 Handle<Object> break_point_object_arg = args.at<Object>(0);
10376
10377 // Clear break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010378 isolate->debug()->ClearBreakPoint(break_point_object_arg);
Steve Blocka7e24c12009-10-30 11:49:00 +000010379
Steve Block44f0eee2011-05-26 01:26:41 +010010380 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010381}
10382
10383
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010384// Change the state of break on exceptions.
10385// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10386// args[1]: Boolean indicating on/off.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010387RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010010388 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010389 ASSERT(args.length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010390 RUNTIME_ASSERT(args[0]->IsNumber());
10391 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010392
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010393 // If the number doesn't match an enum value, the ChangeBreakOnException
10394 // function will default to affecting caught exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +000010395 ExceptionBreakType type =
10396 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010397 // Update break point state.
Steve Block44f0eee2011-05-26 01:26:41 +010010398 isolate->debug()->ChangeBreakOnException(type, enable);
10399 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010400}
10401
10402
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010403// Returns the state of break on exceptions
10404// args[0]: boolean indicating uncaught exceptions
Ben Murdoch8b112d22011-06-08 16:22:53 +010010405RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
Steve Block44f0eee2011-05-26 01:26:41 +010010406 HandleScope scope(isolate);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010407 ASSERT(args.length() == 1);
10408 RUNTIME_ASSERT(args[0]->IsNumber());
10409
10410 ExceptionBreakType type =
10411 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Steve Block44f0eee2011-05-26 01:26:41 +010010412 bool result = isolate->debug()->IsBreakOnException(type);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010413 return Smi::FromInt(result);
10414}
10415
10416
Steve Blocka7e24c12009-10-30 11:49:00 +000010417// Prepare for stepping
10418// args[0]: break id for checking execution state
10419// args[1]: step action from the enumeration StepAction
10420// args[2]: number of times to perform the step, for step out it is the number
10421// of frames to step down.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010422RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
Steve Block44f0eee2011-05-26 01:26:41 +010010423 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010424 ASSERT(args.length() == 3);
10425 // Check arguments.
John Reck59135872010-11-02 12:39:01 -070010426 Object* check;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010427 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10428 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010429 if (!maybe_check->ToObject(&check)) return maybe_check;
10430 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010431 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010432 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010433 }
10434
10435 // Get the step action and check validity.
10436 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10437 if (step_action != StepIn &&
10438 step_action != StepNext &&
10439 step_action != StepOut &&
10440 step_action != StepInMin &&
10441 step_action != StepMin) {
Steve Block44f0eee2011-05-26 01:26:41 +010010442 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010443 }
10444
10445 // Get the number of steps.
10446 int step_count = NumberToInt32(args[2]);
10447 if (step_count < 1) {
Steve Block44f0eee2011-05-26 01:26:41 +010010448 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010449 }
10450
10451 // Clear all current stepping setup.
Steve Block44f0eee2011-05-26 01:26:41 +010010452 isolate->debug()->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +000010453
10454 // Prepare step.
Steve Block44f0eee2011-05-26 01:26:41 +010010455 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10456 step_count);
10457 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010458}
10459
10460
10461// Clear all stepping set by PrepareStep.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010462RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
Steve Block44f0eee2011-05-26 01:26:41 +010010463 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010464 ASSERT(args.length() == 0);
Steve Block44f0eee2011-05-26 01:26:41 +010010465 isolate->debug()->ClearStepping();
10466 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010467}
10468
10469
10470// Creates a copy of the with context chain. The copy of the context chain is
10471// is linked to the function context supplied.
10472static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10473 Handle<Context> function_context) {
10474 // At the bottom of the chain. Return the function context to link to.
10475 if (context_chain->is_function_context()) {
10476 return function_context;
10477 }
10478
10479 // Recursively copy the with contexts.
10480 Handle<Context> previous(context_chain->previous());
10481 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
Steve Block053d10c2011-06-13 19:13:29 +010010482 Handle<Context> context = CopyWithContextChain(function_context, previous);
Steve Block44f0eee2011-05-26 01:26:41 +010010483 return context->GetIsolate()->factory()->NewWithContext(
10484 context, extension, context_chain->IsCatchContext());
Steve Blocka7e24c12009-10-30 11:49:00 +000010485}
10486
10487
10488// Helper function to find or create the arguments object for
10489// Runtime_DebugEvaluate.
Steve Block44f0eee2011-05-26 01:26:41 +010010490static Handle<Object> GetArgumentsObject(Isolate* isolate,
10491 JavaScriptFrame* frame,
Steve Blocka7e24c12009-10-30 11:49:00 +000010492 Handle<JSFunction> function,
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010493 Handle<SerializedScopeInfo> scope_info,
Steve Blocka7e24c12009-10-30 11:49:00 +000010494 const ScopeInfo<>* sinfo,
10495 Handle<Context> function_context) {
10496 // Try to find the value of 'arguments' to pass as parameter. If it is not
10497 // found (that is the debugged function does not reference 'arguments' and
10498 // does not support eval) then create an 'arguments' object.
10499 int index;
10500 if (sinfo->number_of_stack_slots() > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +010010501 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +000010502 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010010503 return Handle<Object>(frame->GetExpression(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010504 }
10505 }
10506
10507 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
Steve Block44f0eee2011-05-26 01:26:41 +010010508 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10509 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010510 if (index != -1) {
Steve Block44f0eee2011-05-26 01:26:41 +010010511 return Handle<Object>(function_context->get(index), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010512 }
10513 }
10514
Steve Block44f0eee2011-05-26 01:26:41 +010010515 const int length = frame->ComputeParametersCount();
10516 Handle<JSObject> arguments =
10517 isolate->factory()->NewArgumentsObject(function, length);
10518 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Leon Clarke4515c472010-02-03 11:58:03 +000010519
10520 AssertNoAllocation no_gc;
10521 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000010522 for (int i = 0; i < length; i++) {
10523 array->set(i, frame->GetParameter(i), mode);
10524 }
10525 arguments->set_elements(*array);
10526 return arguments;
10527}
10528
10529
Steve Block44f0eee2011-05-26 01:26:41 +010010530static const char kSourceStr[] =
10531 "(function(arguments,__source__){return eval(__source__);})";
10532
10533
Steve Blocka7e24c12009-10-30 11:49:00 +000010534// Evaluate a piece of JavaScript in the context of a stack frame for
10535// debugging. This is accomplished by creating a new context which in its
10536// extension part has all the parameters and locals of the function on the
10537// stack frame. A function which calls eval with the code to evaluate is then
10538// compiled in this context and called in this context. As this context
10539// replaces the context of the function on the stack frame a new (empty)
10540// function is created as well to be used as the closure for the context.
10541// This function and the context acts as replacements for the function on the
10542// stack frame presenting the same view of the values of parameters and
10543// local variables as if the piece of JavaScript was evaluated at the point
10544// where the function on the stack frame is currently stopped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010545RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
Steve Block44f0eee2011-05-26 01:26:41 +010010546 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010547
10548 // Check the execution state and decode arguments frame and source to be
10549 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010550 ASSERT(args.length() == 5);
John Reck59135872010-11-02 12:39:01 -070010551 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010552 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10553 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010554 if (!maybe_check_result->ToObject(&check_result)) {
10555 return maybe_check_result;
10556 }
10557 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010558 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10559 CONVERT_ARG_CHECKED(String, source, 2);
10560 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010561 Handle<Object> additional_context(args[4]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010562
10563 // Handle the processing of break.
10564 DisableBreak disable_break_save(disable_break);
10565
10566 // Get the frame where the debugging is performed.
10567 StackFrame::Id id = UnwrapFrameId(wrapped_id);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010568 JavaScriptFrameIterator it(isolate, id);
Steve Blocka7e24c12009-10-30 11:49:00 +000010569 JavaScriptFrame* frame = it.frame();
10570 Handle<JSFunction> function(JSFunction::cast(frame->function()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010571 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
10572 ScopeInfo<> sinfo(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +000010573
10574 // Traverse the saved contexts chain to find the active context for the
10575 // selected frame.
Steve Block44f0eee2011-05-26 01:26:41 +010010576 SaveContext* save = isolate->save_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000010577 while (save != NULL && !save->below(frame)) {
10578 save = save->prev();
10579 }
10580 ASSERT(save != NULL);
Steve Block44f0eee2011-05-26 01:26:41 +010010581 SaveContext savex(isolate);
10582 isolate->set_context(*(save->context()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010583
10584 // Create the (empty) function replacing the function on the stack frame for
10585 // the purpose of evaluating in the context created below. It is important
10586 // that this function does not describe any parameters and local variables
10587 // in the context. If it does then this will cause problems with the lookup
10588 // in Context::Lookup, where context slots for parameters and local variables
10589 // are looked at before the extension object.
10590 Handle<JSFunction> go_between =
Steve Block44f0eee2011-05-26 01:26:41 +010010591 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10592 isolate->factory()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010593 go_between->set_context(function->context());
10594#ifdef DEBUG
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010595 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +000010596 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10597 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10598#endif
10599
10600 // Materialize the content of the local scope into a JSObject.
Steve Block44f0eee2011-05-26 01:26:41 +010010601 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10602 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
Steve Blocka7e24c12009-10-30 11:49:00 +000010603
10604 // Allocate a new context for the debug evaluation and set the extension
10605 // object build.
10606 Handle<Context> context =
Steve Block44f0eee2011-05-26 01:26:41 +010010607 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10608 go_between);
Steve Blocka7e24c12009-10-30 11:49:00 +000010609 context->set_extension(*local_scope);
10610 // Copy any with contexts present and chain them in front of this context.
10611 Handle<Context> frame_context(Context::cast(frame->context()));
10612 Handle<Context> function_context(frame_context->fcontext());
10613 context = CopyWithContextChain(frame_context, context);
10614
Ben Murdochb0fe1622011-05-05 13:52:32 +010010615 if (additional_context->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010616 context = isolate->factory()->NewWithContext(context,
Ben Murdochb0fe1622011-05-05 13:52:32 +010010617 Handle<JSObject>::cast(additional_context), false);
10618 }
10619
Steve Blocka7e24c12009-10-30 11:49:00 +000010620 // Wrap the evaluation statement in a new function compiled in the newly
10621 // created context. The function has one parameter which has to be called
10622 // 'arguments'. This it to have access to what would have been 'arguments' in
10623 // the function being debugged.
10624 // function(arguments,__source__) {return eval(__source__);}
Steve Block44f0eee2011-05-26 01:26:41 +010010625
Steve Blocka7e24c12009-10-30 11:49:00 +000010626 Handle<String> function_source =
Steve Block44f0eee2011-05-26 01:26:41 +010010627 isolate->factory()->NewStringFromAscii(
10628 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
Steve Block1e0659c2011-05-24 12:43:12 +010010629
10630 // Currently, the eval code will be executed in non-strict mode,
10631 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010010632 Handle<SharedFunctionInfo> shared =
Steve Blocka7e24c12009-10-30 11:49:00 +000010633 Compiler::CompileEval(function_source,
10634 context,
Steve Block1e0659c2011-05-24 12:43:12 +010010635 context->IsGlobalContext(),
10636 kNonStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +010010637 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000010638 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010010639 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
Steve Blocka7e24c12009-10-30 11:49:00 +000010640
10641 // Invoke the result of the compilation to get the evaluation function.
10642 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010010643 Handle<Object> receiver(frame->receiver(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010644 Handle<Object> evaluation_function =
10645 Execution::Call(compiled_function, receiver, 0, NULL,
10646 &has_pending_exception);
10647 if (has_pending_exception) return Failure::Exception();
10648
Steve Block44f0eee2011-05-26 01:26:41 +010010649 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10650 function, scope_info,
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010651 &sinfo, function_context);
Steve Blocka7e24c12009-10-30 11:49:00 +000010652
10653 // Invoke the evaluation function and return the result.
10654 const int argc = 2;
10655 Object** argv[argc] = { arguments.location(),
10656 Handle<Object>::cast(source).location() };
10657 Handle<Object> result =
10658 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10659 argc, argv, &has_pending_exception);
10660 if (has_pending_exception) return Failure::Exception();
10661
10662 // Skip the global proxy as it has no properties and always delegates to the
10663 // real global object.
10664 if (result->IsJSGlobalProxy()) {
10665 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10666 }
10667
10668 return *result;
10669}
10670
10671
Ben Murdoch8b112d22011-06-08 16:22:53 +010010672RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
Steve Block44f0eee2011-05-26 01:26:41 +010010673 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010674
10675 // Check the execution state and decode arguments frame and source to be
10676 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010677 ASSERT(args.length() == 4);
John Reck59135872010-11-02 12:39:01 -070010678 Object* check_result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010679 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10680 RUNTIME_ARGUMENTS(isolate, args));
John Reck59135872010-11-02 12:39:01 -070010681 if (!maybe_check_result->ToObject(&check_result)) {
10682 return maybe_check_result;
10683 }
10684 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010685 CONVERT_ARG_CHECKED(String, source, 1);
10686 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010687 Handle<Object> additional_context(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010688
10689 // Handle the processing of break.
10690 DisableBreak disable_break_save(disable_break);
10691
10692 // Enter the top context from before the debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010010693 SaveContext save(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010694 SaveContext* top = &save;
Steve Block44f0eee2011-05-26 01:26:41 +010010695 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010696 top = top->prev();
10697 }
10698 if (top != NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +010010699 isolate->set_context(*top->context());
Steve Blocka7e24c12009-10-30 11:49:00 +000010700 }
10701
10702 // Get the global context now set to the top context from before the
10703 // debugger was invoked.
Steve Block44f0eee2011-05-26 01:26:41 +010010704 Handle<Context> context = isolate->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000010705
Ben Murdochb0fe1622011-05-05 13:52:32 +010010706 bool is_global = true;
10707
10708 if (additional_context->IsJSObject()) {
10709 // Create a function context first, than put 'with' context on top of it.
Steve Block44f0eee2011-05-26 01:26:41 +010010710 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10711 isolate->factory()->empty_string(),
10712 isolate->factory()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010713 go_between->set_context(*context);
10714 context =
Steve Block44f0eee2011-05-26 01:26:41 +010010715 isolate->factory()->NewFunctionContext(
10716 Context::MIN_CONTEXT_SLOTS, go_between);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010717 context->set_extension(JSObject::cast(*additional_context));
10718 is_global = false;
10719 }
10720
Steve Blocka7e24c12009-10-30 11:49:00 +000010721 // Compile the source to be evaluated.
Steve Block1e0659c2011-05-24 12:43:12 +010010722 // Currently, the eval code will be executed in non-strict mode,
10723 // even in the strict code context.
Steve Block6ded16b2010-05-10 14:33:55 +010010724 Handle<SharedFunctionInfo> shared =
Steve Block1e0659c2011-05-24 12:43:12 +010010725 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
Steve Block6ded16b2010-05-10 14:33:55 +010010726 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +000010727 Handle<JSFunction> compiled_function =
Steve Block44f0eee2011-05-26 01:26:41 +010010728 Handle<JSFunction>(
10729 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10730 context));
Steve Blocka7e24c12009-10-30 11:49:00 +000010731
10732 // Invoke the result of the compilation to get the evaluation function.
10733 bool has_pending_exception;
Steve Block44f0eee2011-05-26 01:26:41 +010010734 Handle<Object> receiver = isolate->global();
Steve Blocka7e24c12009-10-30 11:49:00 +000010735 Handle<Object> result =
10736 Execution::Call(compiled_function, receiver, 0, NULL,
10737 &has_pending_exception);
10738 if (has_pending_exception) return Failure::Exception();
10739 return *result;
10740}
10741
10742
Ben Murdoch8b112d22011-06-08 16:22:53 +010010743RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
Steve Block44f0eee2011-05-26 01:26:41 +010010744 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010745 ASSERT(args.length() == 0);
10746
10747 // Fill the script objects.
Steve Block44f0eee2011-05-26 01:26:41 +010010748 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
Steve Blocka7e24c12009-10-30 11:49:00 +000010749
10750 // Convert the script objects to proper JS objects.
10751 for (int i = 0; i < instances->length(); i++) {
10752 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10753 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10754 // because using
10755 // instances->set(i, *GetScriptWrapper(script))
10756 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10757 // already have deferenced the instances handle.
10758 Handle<JSValue> wrapper = GetScriptWrapper(script);
10759 instances->set(i, *wrapper);
10760 }
10761
10762 // Return result as a JS array.
Steve Block44f0eee2011-05-26 01:26:41 +010010763 Handle<JSObject> result =
10764 isolate->factory()->NewJSObject(isolate->array_function());
Steve Blocka7e24c12009-10-30 11:49:00 +000010765 Handle<JSArray>::cast(result)->SetContent(*instances);
10766 return *result;
10767}
10768
10769
10770// Helper function used by Runtime_DebugReferencedBy below.
10771static int DebugReferencedBy(JSObject* target,
10772 Object* instance_filter, int max_references,
10773 FixedArray* instances, int instances_size,
10774 JSFunction* arguments_function) {
10775 NoHandleAllocation ha;
10776 AssertNoAllocation no_alloc;
10777
10778 // Iterate the heap.
10779 int count = 0;
10780 JSObject* last = NULL;
10781 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000010782 HeapObject* heap_obj = NULL;
10783 while (((heap_obj = iterator.next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000010784 (max_references == 0 || count < max_references)) {
10785 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000010786 if (heap_obj->IsJSObject()) {
10787 // Skip context extension objects and argument arrays as these are
10788 // checked in the context of functions using them.
10789 JSObject* obj = JSObject::cast(heap_obj);
10790 if (obj->IsJSContextExtensionObject() ||
10791 obj->map()->constructor() == arguments_function) {
10792 continue;
10793 }
10794
10795 // Check if the JS object has a reference to the object looked for.
10796 if (obj->ReferencesObject(target)) {
10797 // Check instance filter if supplied. This is normally used to avoid
10798 // references from mirror objects (see Runtime_IsInPrototypeChain).
10799 if (!instance_filter->IsUndefined()) {
10800 Object* V = obj;
10801 while (true) {
10802 Object* prototype = V->GetPrototype();
10803 if (prototype->IsNull()) {
10804 break;
10805 }
10806 if (instance_filter == prototype) {
10807 obj = NULL; // Don't add this object.
10808 break;
10809 }
10810 V = prototype;
10811 }
10812 }
10813
10814 if (obj != NULL) {
10815 // Valid reference found add to instance array if supplied an update
10816 // count.
10817 if (instances != NULL && count < instances_size) {
10818 instances->set(count, obj);
10819 }
10820 last = obj;
10821 count++;
10822 }
10823 }
10824 }
10825 }
10826
10827 // Check for circular reference only. This can happen when the object is only
10828 // referenced from mirrors and has a circular reference in which case the
10829 // object is not really alive and would have been garbage collected if not
10830 // referenced from the mirror.
10831 if (count == 1 && last == target) {
10832 count = 0;
10833 }
10834
10835 // Return the number of referencing objects found.
10836 return count;
10837}
10838
10839
10840// Scan the heap for objects with direct references to an object
10841// args[0]: the object to find references to
10842// args[1]: constructor function for instances to exclude (Mirror)
10843// args[2]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010010844RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010845 ASSERT(args.length() == 3);
10846
10847 // First perform a full GC in order to avoid references from dead objects.
Steve Block44f0eee2011-05-26 01:26:41 +010010848 isolate->heap()->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010849
10850 // Check parameters.
10851 CONVERT_CHECKED(JSObject, target, args[0]);
10852 Object* instance_filter = args[1];
10853 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10854 instance_filter->IsJSObject());
10855 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10856 RUNTIME_ASSERT(max_references >= 0);
10857
10858 // Get the constructor function for context extension and arguments array.
10859 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +010010860 isolate->context()->global_context()->arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +000010861 JSFunction* arguments_function =
10862 JSFunction::cast(arguments_boilerplate->map()->constructor());
10863
10864 // Get the number of referencing objects.
10865 int count;
10866 count = DebugReferencedBy(target, instance_filter, max_references,
10867 NULL, 0, arguments_function);
10868
10869 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070010870 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010010871 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070010872 if (!maybe_object->ToObject(&object)) return maybe_object;
10873 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010874 FixedArray* instances = FixedArray::cast(object);
10875
10876 // Fill the referencing objects.
10877 count = DebugReferencedBy(target, instance_filter, max_references,
10878 instances, count, arguments_function);
10879
10880 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070010881 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010010882 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10883 isolate->context()->global_context()->array_function());
John Reck59135872010-11-02 12:39:01 -070010884 if (!maybe_result->ToObject(&result)) return maybe_result;
10885 }
10886 JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000010887 return result;
10888}
10889
10890
10891// Helper function used by Runtime_DebugConstructedBy below.
10892static int DebugConstructedBy(JSFunction* constructor, int max_references,
10893 FixedArray* instances, int instances_size) {
10894 AssertNoAllocation no_alloc;
10895
10896 // Iterate the heap.
10897 int count = 0;
10898 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000010899 HeapObject* heap_obj = NULL;
10900 while (((heap_obj = iterator.next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000010901 (max_references == 0 || count < max_references)) {
10902 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000010903 if (heap_obj->IsJSObject()) {
10904 JSObject* obj = JSObject::cast(heap_obj);
10905 if (obj->map()->constructor() == constructor) {
10906 // Valid reference found add to instance array if supplied an update
10907 // count.
10908 if (instances != NULL && count < instances_size) {
10909 instances->set(count, obj);
10910 }
10911 count++;
10912 }
10913 }
10914 }
10915
10916 // Return the number of referencing objects found.
10917 return count;
10918}
10919
10920
10921// Scan the heap for objects constructed by a specific function.
10922// args[0]: the constructor to find instances of
10923// args[1]: the the maximum number of objects to return
Ben Murdoch8b112d22011-06-08 16:22:53 +010010924RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010925 ASSERT(args.length() == 2);
10926
10927 // First perform a full GC in order to avoid dead objects.
Steve Block44f0eee2011-05-26 01:26:41 +010010928 isolate->heap()->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010929
10930 // Check parameters.
10931 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10932 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10933 RUNTIME_ASSERT(max_references >= 0);
10934
10935 // Get the number of referencing objects.
10936 int count;
10937 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10938
10939 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070010940 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +010010941 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
John Reck59135872010-11-02 12:39:01 -070010942 if (!maybe_object->ToObject(&object)) return maybe_object;
10943 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010944 FixedArray* instances = FixedArray::cast(object);
10945
10946 // Fill the referencing objects.
10947 count = DebugConstructedBy(constructor, max_references, instances, count);
10948
10949 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070010950 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010010951 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10952 isolate->context()->global_context()->array_function());
John Reck59135872010-11-02 12:39:01 -070010953 if (!maybe_result->ToObject(&result)) return maybe_result;
10954 }
10955 JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000010956 return result;
10957}
10958
10959
10960// Find the effective prototype object as returned by __proto__.
10961// args[0]: the object to find the prototype for.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010962RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010963 ASSERT(args.length() == 1);
10964
10965 CONVERT_CHECKED(JSObject, obj, args[0]);
10966
10967 // Use the __proto__ accessor.
10968 return Accessors::ObjectPrototype.getter(obj, NULL);
10969}
10970
10971
Ben Murdoch8b112d22011-06-08 16:22:53 +010010972RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010973 ASSERT(args.length() == 0);
10974 CPU::DebugBreak();
Steve Block44f0eee2011-05-26 01:26:41 +010010975 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010976}
10977
10978
Ben Murdoch8b112d22011-06-08 16:22:53 +010010979RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010980#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010010981 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010982 ASSERT(args.length() == 1);
10983 // Get the function and make sure it is compiled.
10984 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000010985 Handle<SharedFunctionInfo> shared(func->shared());
10986 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010987 return Failure::Exception();
10988 }
10989 func->code()->PrintLn();
10990#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010010991 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010992}
10993
10994
Ben Murdoch8b112d22011-06-08 16:22:53 +010010995RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010996#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010010997 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010998 ASSERT(args.length() == 1);
10999 // Get the function and make sure it is compiled.
11000 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000011001 Handle<SharedFunctionInfo> shared(func->shared());
11002 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011003 return Failure::Exception();
11004 }
Leon Clarke4515c472010-02-03 11:58:03 +000011005 shared->construct_stub()->PrintLn();
Steve Blocka7e24c12009-10-30 11:49:00 +000011006#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +010011007 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011008}
11009
11010
Ben Murdoch8b112d22011-06-08 16:22:53 +010011011RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011012 NoHandleAllocation ha;
11013 ASSERT(args.length() == 1);
11014
11015 CONVERT_CHECKED(JSFunction, f, args[0]);
11016 return f->shared()->inferred_name();
11017}
Steve Blockd0582a62009-12-15 09:54:21 +000011018
Steve Block6ded16b2010-05-10 14:33:55 +010011019
11020static int FindSharedFunctionInfosForScript(Script* script,
Steve Block44f0eee2011-05-26 01:26:41 +010011021 FixedArray* buffer) {
Steve Block6ded16b2010-05-10 14:33:55 +010011022 AssertNoAllocation no_allocations;
11023
11024 int counter = 0;
11025 int buffer_size = buffer->length();
11026 HeapIterator iterator;
11027 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11028 ASSERT(obj != NULL);
11029 if (!obj->IsSharedFunctionInfo()) {
11030 continue;
11031 }
11032 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11033 if (shared->script() != script) {
11034 continue;
11035 }
11036 if (counter < buffer_size) {
11037 buffer->set(counter, shared);
11038 }
11039 counter++;
11040 }
11041 return counter;
11042}
11043
11044// For a script finds all SharedFunctionInfo's in the heap that points
11045// to this script. Returns JSArray of SharedFunctionInfo wrapped
11046// in OpaqueReferences.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011047RUNTIME_FUNCTION(MaybeObject*,
11048 Runtime_LiveEditFindSharedFunctionInfosForScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010011049 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010011050 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011051 CONVERT_CHECKED(JSValue, script_value, args[0]);
11052
11053 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11054
11055 const int kBufferSize = 32;
11056
11057 Handle<FixedArray> array;
Steve Block44f0eee2011-05-26 01:26:41 +010011058 array = isolate->factory()->NewFixedArray(kBufferSize);
Steve Block6ded16b2010-05-10 14:33:55 +010011059 int number = FindSharedFunctionInfosForScript(*script, *array);
11060 if (number > kBufferSize) {
Steve Block44f0eee2011-05-26 01:26:41 +010011061 array = isolate->factory()->NewFixedArray(number);
Steve Block6ded16b2010-05-10 14:33:55 +010011062 FindSharedFunctionInfosForScript(*script, *array);
11063 }
11064
Steve Block44f0eee2011-05-26 01:26:41 +010011065 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
Steve Block6ded16b2010-05-10 14:33:55 +010011066 result->set_length(Smi::FromInt(number));
11067
11068 LiveEdit::WrapSharedFunctionInfos(result);
11069
11070 return *result;
11071}
11072
11073// For a script calculates compilation information about all its functions.
11074// The script source is explicitly specified by the second argument.
11075// The source of the actual script is not used, however it is important that
11076// all generated code keeps references to this particular instance of script.
11077// Returns a JSArray of compilation infos. The array is ordered so that
11078// each function with all its descendant is always stored in a continues range
11079// with the function itself going first. The root function is a script function.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011080RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
Steve Block6ded16b2010-05-10 14:33:55 +010011081 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011082 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011083 CONVERT_CHECKED(JSValue, script, args[0]);
11084 CONVERT_ARG_CHECKED(String, source, 1);
11085 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11086
11087 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11088
Steve Block44f0eee2011-05-26 01:26:41 +010011089 if (isolate->has_pending_exception()) {
Steve Block6ded16b2010-05-10 14:33:55 +010011090 return Failure::Exception();
11091 }
11092
11093 return result;
11094}
11095
11096// Changes the source of the script to a new_source.
11097// If old_script_name is provided (i.e. is a String), also creates a copy of
11098// the script with its original source and sends notification to debugger.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011099RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010011100 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010011101 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011102 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11103 CONVERT_ARG_CHECKED(String, new_source, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010011104 Handle<Object> old_script_name(args[2], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011105
11106 CONVERT_CHECKED(Script, original_script_pointer,
11107 original_script_value->value());
11108 Handle<Script> original_script(original_script_pointer);
11109
11110 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11111 new_source,
11112 old_script_name);
11113
11114 if (old_script->IsScript()) {
11115 Handle<Script> script_handle(Script::cast(old_script));
11116 return *(GetScriptWrapper(script_handle));
11117 } else {
Steve Block44f0eee2011-05-26 01:26:41 +010011118 return isolate->heap()->null_value();
Steve Block6ded16b2010-05-10 14:33:55 +010011119 }
11120}
11121
Ben Murdochb0fe1622011-05-05 13:52:32 +010011122
Ben Murdoch8b112d22011-06-08 16:22:53 +010011123RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010011124 ASSERT(args.length() == 1);
Steve Block44f0eee2011-05-26 01:26:41 +010011125 HandleScope scope(isolate);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011126 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11127 return LiveEdit::FunctionSourceUpdated(shared_info);
11128}
11129
11130
Steve Block6ded16b2010-05-10 14:33:55 +010011131// Replaces code of SharedFunctionInfo with a new one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011132RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
Steve Block6ded16b2010-05-10 14:33:55 +010011133 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011134 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011135 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11136 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11137
11138 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
11139}
11140
11141// Connects SharedFunctionInfo to another script.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011142RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
Steve Block6ded16b2010-05-10 14:33:55 +010011143 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011144 HandleScope scope(isolate);
11145 Handle<Object> function_object(args[0], isolate);
11146 Handle<Object> script_object(args[1], isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011147
11148 if (function_object->IsJSValue()) {
11149 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11150 if (script_object->IsJSValue()) {
11151 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
Steve Block44f0eee2011-05-26 01:26:41 +010011152 script_object = Handle<Object>(script, isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011153 }
11154
11155 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11156 } else {
11157 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11158 // and we check it in this function.
11159 }
11160
Steve Block44f0eee2011-05-26 01:26:41 +010011161 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010011162}
11163
11164
11165// In a code of a parent function replaces original function as embedded object
11166// with a substitution one.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011167RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
Steve Block6ded16b2010-05-10 14:33:55 +010011168 ASSERT(args.length() == 3);
Steve Block44f0eee2011-05-26 01:26:41 +010011169 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011170
11171 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11172 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11173 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11174
11175 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11176 subst_wrapper);
11177
Steve Block44f0eee2011-05-26 01:26:41 +010011178 return isolate->heap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +010011179}
11180
11181
11182// Updates positions of a shared function info (first parameter) according
11183// to script source change. Text change is described in second parameter as
11184// array of groups of 3 numbers:
11185// (change_begin, change_end, change_end_new_position).
11186// Each group describes a change in text; groups are sorted by change_begin.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011187RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
Steve Block6ded16b2010-05-10 14:33:55 +010011188 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011189 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011190 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11191 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11192
11193 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
11194}
11195
11196
11197// For array of SharedFunctionInfo's (each wrapped in JSValue)
11198// checks that none of them have activations on stacks (of any thread).
11199// Returns array of the same length with corresponding results of
11200// LiveEdit::FunctionPatchabilityStatus type.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011201RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
Steve Block6ded16b2010-05-10 14:33:55 +010011202 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011203 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011204 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11205 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
11206
11207 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
11208}
11209
Ben Murdochb8e0da22011-05-16 14:20:40 +010011210// Compares 2 strings line-by-line, then token-wise and returns diff in form
11211// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11212// of diff chunks.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011213RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
Steve Block6ded16b2010-05-10 14:33:55 +010011214 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011215 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011216 CONVERT_ARG_CHECKED(String, s1, 0);
11217 CONVERT_ARG_CHECKED(String, s2, 1);
11218
Ben Murdochb8e0da22011-05-16 14:20:40 +010011219 return *LiveEdit::CompareStrings(s1, s2);
Steve Block6ded16b2010-05-10 14:33:55 +010011220}
11221
11222
Steve Block6ded16b2010-05-10 14:33:55 +010011223// A testing entry. Returns statement position which is the closest to
11224// source_position.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011225RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
Steve Block6ded16b2010-05-10 14:33:55 +010011226 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011227 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011228 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11229 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11230
Steve Block44f0eee2011-05-26 01:26:41 +010011231 Handle<Code> code(function->code(), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011232
Ben Murdochb0fe1622011-05-05 13:52:32 +010011233 if (code->kind() != Code::FUNCTION &&
11234 code->kind() != Code::OPTIMIZED_FUNCTION) {
Steve Block44f0eee2011-05-26 01:26:41 +010011235 return isolate->heap()->undefined_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011236 }
11237
11238 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
Steve Block6ded16b2010-05-10 14:33:55 +010011239 int closest_pc = 0;
11240 int distance = kMaxInt;
11241 while (!it.done()) {
11242 int statement_position = static_cast<int>(it.rinfo()->data());
11243 // Check if this break point is closer that what was previously found.
11244 if (source_position <= statement_position &&
11245 statement_position - source_position < distance) {
11246 closest_pc =
11247 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
11248 distance = statement_position - source_position;
11249 // Check whether we can't get any closer.
11250 if (distance == 0) break;
11251 }
11252 it.next();
11253 }
11254
11255 return Smi::FromInt(closest_pc);
11256}
11257
11258
11259// Calls specified function with or without entering the debugger.
11260// This is used in unit tests to run code as if debugger is entered or simply
11261// to have a stack with C++ frame in the middle.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011262RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
Steve Block6ded16b2010-05-10 14:33:55 +010011263 ASSERT(args.length() == 2);
Steve Block44f0eee2011-05-26 01:26:41 +010011264 HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +010011265 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11266 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11267
11268 Handle<Object> result;
11269 bool pending_exception;
11270 {
11271 if (without_debugger) {
Steve Block44f0eee2011-05-26 01:26:41 +010011272 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010011273 &pending_exception);
11274 } else {
11275 EnterDebugger enter_debugger;
Steve Block44f0eee2011-05-26 01:26:41 +010011276 result = Execution::Call(function, isolate->global(), 0, NULL,
Steve Block6ded16b2010-05-10 14:33:55 +010011277 &pending_exception);
11278 }
11279 }
11280 if (!pending_exception) {
11281 return *result;
11282 } else {
11283 return Failure::Exception();
11284 }
11285}
11286
11287
Ben Murdoch086aeea2011-05-13 15:57:08 +010011288// Sets a v8 flag.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011289RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
Ben Murdoch086aeea2011-05-13 15:57:08 +010011290 CONVERT_CHECKED(String, arg, args[0]);
11291 SmartPointer<char> flags =
11292 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11293 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
Steve Block44f0eee2011-05-26 01:26:41 +010011294 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010011295}
11296
11297
11298// Performs a GC.
11299// Presently, it only does a full GC.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011300RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
Steve Block44f0eee2011-05-26 01:26:41 +010011301 isolate->heap()->CollectAllGarbage(true);
11302 return isolate->heap()->undefined_value();
Ben Murdoch086aeea2011-05-13 15:57:08 +010011303}
11304
11305
11306// Gets the current heap usage.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011307RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
Steve Block44f0eee2011-05-26 01:26:41 +010011308 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
Ben Murdoch086aeea2011-05-13 15:57:08 +010011309 if (!Smi::IsValid(usage)) {
Steve Block44f0eee2011-05-26 01:26:41 +010011310 return *isolate->factory()->NewNumberFromInt(usage);
Ben Murdoch086aeea2011-05-13 15:57:08 +010011311 }
11312 return Smi::FromInt(usage);
11313}
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011314
11315
11316// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011317RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011318#ifdef LIVE_OBJECT_LIST
Steve Block44f0eee2011-05-26 01:26:41 +010011319 return isolate->heap()->true_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011320#else
Steve Block44f0eee2011-05-26 01:26:41 +010011321 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011322#endif
11323}
11324
11325
11326// Captures a live object list from the present heap.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011327RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011328#ifdef LIVE_OBJECT_LIST
11329 return LiveObjectList::Capture();
11330#else
Steve Block44f0eee2011-05-26 01:26:41 +010011331 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011332#endif
11333}
11334
11335
11336// Deletes the specified live object list.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011337RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011338#ifdef LIVE_OBJECT_LIST
11339 CONVERT_SMI_CHECKED(id, args[0]);
11340 bool success = LiveObjectList::Delete(id);
Steve Block44f0eee2011-05-26 01:26:41 +010011341 return success ? isolate->heap()->true_value() :
11342 isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011343#else
Steve Block44f0eee2011-05-26 01:26:41 +010011344 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011345#endif
11346}
11347
11348
11349// Generates the response to a debugger request for a dump of the objects
11350// contained in the difference between the captured live object lists
11351// specified by id1 and id2.
11352// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11353// dumped.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011354RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011355#ifdef LIVE_OBJECT_LIST
11356 HandleScope scope;
11357 CONVERT_SMI_CHECKED(id1, args[0]);
11358 CONVERT_SMI_CHECKED(id2, args[1]);
11359 CONVERT_SMI_CHECKED(start, args[2]);
11360 CONVERT_SMI_CHECKED(count, args[3]);
11361 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11362 EnterDebugger enter_debugger;
11363 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11364#else
Steve Block44f0eee2011-05-26 01:26:41 +010011365 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011366#endif
11367}
11368
11369
11370// Gets the specified object as requested by the debugger.
11371// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011372RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011373#ifdef LIVE_OBJECT_LIST
11374 CONVERT_SMI_CHECKED(obj_id, args[0]);
11375 Object* result = LiveObjectList::GetObj(obj_id);
11376 return result;
11377#else
Steve Block44f0eee2011-05-26 01:26:41 +010011378 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011379#endif
11380}
11381
11382
11383// Gets the obj id for the specified address if valid.
11384// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011385RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011386#ifdef LIVE_OBJECT_LIST
11387 HandleScope scope;
11388 CONVERT_ARG_CHECKED(String, address, 0);
11389 Object* result = LiveObjectList::GetObjId(address);
11390 return result;
11391#else
Steve Block44f0eee2011-05-26 01:26:41 +010011392 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011393#endif
11394}
11395
11396
11397// Gets the retainers that references the specified object alive.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011398RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011399#ifdef LIVE_OBJECT_LIST
11400 HandleScope scope;
11401 CONVERT_SMI_CHECKED(obj_id, args[0]);
11402 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11403 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11404 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11405 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11406 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11407
11408 Handle<JSObject> instance_filter;
11409 if (args[1]->IsJSObject()) {
11410 instance_filter = args.at<JSObject>(1);
11411 }
11412 bool verbose = false;
11413 if (args[2]->IsBoolean()) {
11414 verbose = args[2]->IsTrue();
11415 }
11416 int start = 0;
11417 if (args[3]->IsSmi()) {
11418 start = Smi::cast(args[3])->value();
11419 }
11420 int limit = Smi::kMaxValue;
11421 if (args[4]->IsSmi()) {
11422 limit = Smi::cast(args[4])->value();
11423 }
11424
11425 return LiveObjectList::GetObjRetainers(obj_id,
11426 instance_filter,
11427 verbose,
11428 start,
11429 limit,
11430 filter_obj);
11431#else
Steve Block44f0eee2011-05-26 01:26:41 +010011432 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011433#endif
11434}
11435
11436
11437// Gets the reference path between 2 objects.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011438RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011439#ifdef LIVE_OBJECT_LIST
11440 HandleScope scope;
11441 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11442 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11443 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11444
11445 Handle<JSObject> instance_filter;
11446 if (args[2]->IsJSObject()) {
11447 instance_filter = args.at<JSObject>(2);
11448 }
11449
11450 Object* result =
11451 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11452 return result;
11453#else
Steve Block44f0eee2011-05-26 01:26:41 +010011454 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011455#endif
11456}
11457
11458
11459// Generates the response to a debugger request for a list of all
11460// previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011461RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011462#ifdef LIVE_OBJECT_LIST
11463 CONVERT_SMI_CHECKED(start, args[0]);
11464 CONVERT_SMI_CHECKED(count, args[1]);
11465 return LiveObjectList::Info(start, count);
11466#else
Steve Block44f0eee2011-05-26 01:26:41 +010011467 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011468#endif
11469}
11470
11471
11472// Gets a dump of the specified object as requested by the debugger.
11473// This is only used for obj ids shown in live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011474RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011475#ifdef LIVE_OBJECT_LIST
11476 HandleScope scope;
11477 CONVERT_SMI_CHECKED(obj_id, args[0]);
11478 Object* result = LiveObjectList::PrintObj(obj_id);
11479 return result;
11480#else
Steve Block44f0eee2011-05-26 01:26:41 +010011481 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011482#endif
11483}
11484
11485
11486// Resets and releases all previously captured live object lists.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011487RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011488#ifdef LIVE_OBJECT_LIST
11489 LiveObjectList::Reset();
Steve Block44f0eee2011-05-26 01:26:41 +010011490 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011491#else
Steve Block44f0eee2011-05-26 01:26:41 +010011492 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011493#endif
11494}
11495
11496
11497// Generates the response to a debugger request for a summary of the types
11498// of objects in the difference between the captured live object lists
11499// specified by id1 and id2.
11500// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11501// summarized.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011502RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011503#ifdef LIVE_OBJECT_LIST
11504 HandleScope scope;
11505 CONVERT_SMI_CHECKED(id1, args[0]);
11506 CONVERT_SMI_CHECKED(id2, args[1]);
11507 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11508
11509 EnterDebugger enter_debugger;
11510 return LiveObjectList::Summarize(id1, id2, filter_obj);
11511#else
Steve Block44f0eee2011-05-26 01:26:41 +010011512 return isolate->heap()->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011513#endif
11514}
11515
Steve Blocka7e24c12009-10-30 11:49:00 +000011516#endif // ENABLE_DEBUGGER_SUPPORT
11517
Steve Blockd0582a62009-12-15 09:54:21 +000011518
Ben Murdoch086aeea2011-05-13 15:57:08 +010011519#ifdef ENABLE_LOGGING_AND_PROFILING
Ben Murdoch8b112d22011-06-08 16:22:53 +010011520RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
Steve Blockd0582a62009-12-15 09:54:21 +000011521 NoHandleAllocation ha;
Andrei Popescu402d9372010-02-26 13:31:12 +000011522 ASSERT(args.length() == 2);
Steve Blockd0582a62009-12-15 09:54:21 +000011523
11524 CONVERT_CHECKED(Smi, smi_modules, args[0]);
Andrei Popescu402d9372010-02-26 13:31:12 +000011525 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11526 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
Steve Block44f0eee2011-05-26 01:26:41 +010011527 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000011528}
11529
11530
Ben Murdoch8b112d22011-06-08 16:22:53 +010011531RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
Steve Blockd0582a62009-12-15 09:54:21 +000011532 NoHandleAllocation ha;
Andrei Popescu402d9372010-02-26 13:31:12 +000011533 ASSERT(args.length() == 2);
Steve Blockd0582a62009-12-15 09:54:21 +000011534
11535 CONVERT_CHECKED(Smi, smi_modules, args[0]);
Andrei Popescu402d9372010-02-26 13:31:12 +000011536 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11537 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
Steve Block44f0eee2011-05-26 01:26:41 +010011538 return isolate->heap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000011539}
11540
11541#endif // ENABLE_LOGGING_AND_PROFILING
Steve Blocka7e24c12009-10-30 11:49:00 +000011542
11543// Finds the script object from the script data. NOTE: This operation uses
11544// heap traversal to find the function generated for the source position
11545// for the requested break point. For lazily compiled functions several heap
11546// traversals might be required rendering this operation as a rather slow
11547// operation. However for setting break points which is normally done through
11548// some kind of user interaction the performance is not crucial.
11549static Handle<Object> Runtime_GetScriptFromScriptName(
11550 Handle<String> script_name) {
11551 // Scan the heap for Script objects to find the script with the requested
11552 // script data.
11553 Handle<Script> script;
11554 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000011555 HeapObject* obj = NULL;
11556 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011557 // If a script is found check if it has the script data requested.
11558 if (obj->IsScript()) {
11559 if (Script::cast(obj)->name()->IsString()) {
11560 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11561 script = Handle<Script>(Script::cast(obj));
11562 }
11563 }
11564 }
11565 }
11566
11567 // If no script with the requested script data is found return undefined.
Steve Block44f0eee2011-05-26 01:26:41 +010011568 if (script.is_null()) return FACTORY->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011569
11570 // Return the script found.
11571 return GetScriptWrapper(script);
11572}
11573
11574
11575// Get the script object from script data. NOTE: Regarding performance
11576// see the NOTE for GetScriptFromScriptData.
11577// args[0]: script data for the script to find the source for
Ben Murdoch8b112d22011-06-08 16:22:53 +010011578RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
Steve Block44f0eee2011-05-26 01:26:41 +010011579 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011580
11581 ASSERT(args.length() == 1);
11582
11583 CONVERT_CHECKED(String, script_name, args[0]);
11584
11585 // Find the requested script.
11586 Handle<Object> result =
11587 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11588 return *result;
11589}
11590
11591
11592// Determines whether the given stack frame should be displayed in
11593// a stack trace. The caller is the error constructor that asked
11594// for the stack trace to be collected. The first time a construct
11595// call to this function is encountered it is skipped. The seen_caller
11596// in/out parameter is used to remember if the caller has been seen
11597// yet.
11598static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11599 bool* seen_caller) {
11600 // Only display JS frames.
11601 if (!raw_frame->is_java_script())
11602 return false;
11603 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11604 Object* raw_fun = frame->function();
11605 // Not sure when this can happen but skip it just in case.
11606 if (!raw_fun->IsJSFunction())
11607 return false;
11608 if ((raw_fun == caller) && !(*seen_caller)) {
11609 *seen_caller = true;
11610 return false;
11611 }
11612 // Skip all frames until we've seen the caller. Also, skip the most
11613 // obvious builtin calls. Some builtin calls (such as Number.ADD
11614 // which is invoked using 'call') are very difficult to recognize
11615 // so we're leaving them in for now.
11616 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
11617}
11618
11619
Ben Murdochb0fe1622011-05-05 13:52:32 +010011620// Collect the raw data for a stack trace. Returns an array of 4
11621// element segments each containing a receiver, function, code and
11622// native code offset.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011623RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011624 ASSERT_EQ(args.length(), 2);
11625 Handle<Object> caller = args.at<Object>(0);
11626 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11627
Steve Block44f0eee2011-05-26 01:26:41 +010011628 HandleScope scope(isolate);
11629 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +000011630
Leon Clarkee46be812010-01-19 14:06:41 +000011631 limit = Max(limit, 0); // Ensure that limit is not negative.
11632 int initial_size = Min(limit, 10);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011633 Handle<FixedArray> elements =
Steve Block44f0eee2011-05-26 01:26:41 +010011634 factory->NewFixedArrayWithHoles(initial_size * 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000011635
Ben Murdoch8b112d22011-06-08 16:22:53 +010011636 StackFrameIterator iter(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000011637 // If the caller parameter is a function we skip frames until we're
11638 // under it before starting to collect.
11639 bool seen_caller = !caller->IsJSFunction();
11640 int cursor = 0;
11641 int frames_seen = 0;
11642 while (!iter.done() && frames_seen < limit) {
11643 StackFrame* raw_frame = iter.frame();
11644 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
11645 frames_seen++;
11646 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011647 // Set initial size to the maximum inlining level + 1 for the outermost
11648 // function.
11649 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011650 frame->Summarize(&frames);
11651 for (int i = frames.length() - 1; i >= 0; i--) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011652 if (cursor + 4 > elements->length()) {
11653 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11654 Handle<FixedArray> new_elements =
Steve Block44f0eee2011-05-26 01:26:41 +010011655 factory->NewFixedArrayWithHoles(new_capacity);
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011656 for (int i = 0; i < cursor; i++) {
11657 new_elements->set(i, elements->get(i));
11658 }
11659 elements = new_elements;
11660 }
11661 ASSERT(cursor + 4 <= elements->length());
11662
Ben Murdochb0fe1622011-05-05 13:52:32 +010011663 Handle<Object> recv = frames[i].receiver();
11664 Handle<JSFunction> fun = frames[i].function();
11665 Handle<Code> code = frames[i].code();
11666 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011667 elements->set(cursor++, *recv);
11668 elements->set(cursor++, *fun);
11669 elements->set(cursor++, *code);
11670 elements->set(cursor++, *offset);
Steve Blocka7e24c12009-10-30 11:49:00 +000011671 }
11672 }
11673 iter.Advance();
11674 }
Steve Block44f0eee2011-05-26 01:26:41 +010011675 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Leon Clarke4515c472010-02-03 11:58:03 +000011676 result->set_length(Smi::FromInt(cursor));
Steve Blocka7e24c12009-10-30 11:49:00 +000011677 return *result;
11678}
11679
11680
Steve Block3ce2e202009-11-05 08:53:23 +000011681// Returns V8 version as a string.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
Steve Block3ce2e202009-11-05 08:53:23 +000011683 ASSERT_EQ(args.length(), 0);
11684
11685 NoHandleAllocation ha;
11686
11687 const char* version_string = v8::V8::GetVersion();
11688
Steve Block44f0eee2011-05-26 01:26:41 +010011689 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11690 NOT_TENURED);
Steve Block3ce2e202009-11-05 08:53:23 +000011691}
11692
11693
Ben Murdoch8b112d22011-06-08 16:22:53 +010011694RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011695 ASSERT(args.length() == 2);
11696 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11697 Smi::cast(args[1])->value());
Steve Block44f0eee2011-05-26 01:26:41 +010011698 isolate->PrintStack();
Steve Blocka7e24c12009-10-30 11:49:00 +000011699 OS::Abort();
11700 UNREACHABLE();
11701 return NULL;
11702}
11703
11704
Ben Murdoch8b112d22011-06-08 16:22:53 +010011705RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
Steve Block6ded16b2010-05-10 14:33:55 +010011706 // This is only called from codegen, so checks might be more lax.
Ben Murdochb8e0da22011-05-16 14:20:40 +010011707 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +010011708 Object* key = args[1];
11709
Ben Murdochb8e0da22011-05-16 14:20:40 +010011710 int finger_index = cache->finger_index();
Steve Block6ded16b2010-05-10 14:33:55 +010011711 Object* o = cache->get(finger_index);
11712 if (o == key) {
11713 // The fastest case: hit the same place again.
11714 return cache->get(finger_index + 1);
11715 }
11716
11717 for (int i = finger_index - 2;
11718 i >= JSFunctionResultCache::kEntriesIndex;
11719 i -= 2) {
11720 o = cache->get(i);
11721 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010011722 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010011723 return cache->get(i + 1);
11724 }
11725 }
11726
Ben Murdochb8e0da22011-05-16 14:20:40 +010011727 int size = cache->size();
Steve Block6ded16b2010-05-10 14:33:55 +010011728 ASSERT(size <= cache->length());
11729
11730 for (int i = size - 2; i > finger_index; i -= 2) {
11731 o = cache->get(i);
11732 if (o == key) {
Ben Murdochb8e0da22011-05-16 14:20:40 +010011733 cache->set_finger_index(i);
Steve Block6ded16b2010-05-10 14:33:55 +010011734 return cache->get(i + 1);
11735 }
11736 }
11737
Ben Murdochb8e0da22011-05-16 14:20:40 +010011738 // There is no value in the cache. Invoke the function and cache result.
Steve Block44f0eee2011-05-26 01:26:41 +010011739 HandleScope scope(isolate);
Ben Murdochb8e0da22011-05-16 14:20:40 +010011740
11741 Handle<JSFunctionResultCache> cache_handle(cache);
11742 Handle<Object> key_handle(key);
11743 Handle<Object> value;
11744 {
11745 Handle<JSFunction> factory(JSFunction::cast(
11746 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11747 // TODO(antonm): consider passing a receiver when constructing a cache.
Steve Block44f0eee2011-05-26 01:26:41 +010011748 Handle<Object> receiver(isolate->global_context()->global());
Ben Murdochb8e0da22011-05-16 14:20:40 +010011749 // This handle is nor shared, nor used later, so it's safe.
11750 Object** argv[] = { key_handle.location() };
11751 bool pending_exception = false;
11752 value = Execution::Call(factory,
11753 receiver,
11754 1,
11755 argv,
11756 &pending_exception);
11757 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +010011758 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010011759
11760#ifdef DEBUG
11761 cache_handle->JSFunctionResultCacheVerify();
11762#endif
11763
11764 // Function invocation may have cleared the cache. Reread all the data.
11765 finger_index = cache_handle->finger_index();
11766 size = cache_handle->size();
11767
11768 // If we have spare room, put new data into it, otherwise evict post finger
11769 // entry which is likely to be the least recently used.
11770 int index = -1;
11771 if (size < cache_handle->length()) {
11772 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11773 index = size;
11774 } else {
11775 index = finger_index + JSFunctionResultCache::kEntrySize;
11776 if (index == cache_handle->length()) {
11777 index = JSFunctionResultCache::kEntriesIndex;
11778 }
11779 }
11780
11781 ASSERT(index % 2 == 0);
11782 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11783 ASSERT(index < cache_handle->length());
11784
11785 cache_handle->set(index, *key_handle);
11786 cache_handle->set(index + 1, *value);
11787 cache_handle->set_finger_index(index);
11788
11789#ifdef DEBUG
11790 cache_handle->JSFunctionResultCacheVerify();
11791#endif
11792
11793 return *value;
Steve Block6ded16b2010-05-10 14:33:55 +010011794}
11795
Steve Block1e0659c2011-05-24 12:43:12 +010011796
Ben Murdoch8b112d22011-06-08 16:22:53 +010011797RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
Steve Block44f0eee2011-05-26 01:26:41 +010011798 HandleScope scope(isolate);
Steve Block1e0659c2011-05-24 12:43:12 +010011799 CONVERT_ARG_CHECKED(String, type, 0);
11800 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
Steve Block44f0eee2011-05-26 01:26:41 +010011801 return *isolate->factory()->NewJSMessageObject(
11802 type,
11803 arguments,
11804 0,
11805 0,
11806 isolate->factory()->undefined_value(),
11807 isolate->factory()->undefined_value(),
11808 isolate->factory()->undefined_value());
Steve Block1e0659c2011-05-24 12:43:12 +010011809}
11810
11811
Ben Murdoch8b112d22011-06-08 16:22:53 +010011812RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
Steve Block1e0659c2011-05-24 12:43:12 +010011813 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11814 return message->type();
11815}
11816
11817
Ben Murdoch8b112d22011-06-08 16:22:53 +010011818RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
Steve Block1e0659c2011-05-24 12:43:12 +010011819 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11820 return message->arguments();
11821}
11822
11823
Ben Murdoch8b112d22011-06-08 16:22:53 +010011824RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
Steve Block1e0659c2011-05-24 12:43:12 +010011825 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11826 return Smi::FromInt(message->start_position());
11827}
11828
11829
Ben Murdoch8b112d22011-06-08 16:22:53 +010011830RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
Steve Block1e0659c2011-05-24 12:43:12 +010011831 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11832 return message->script();
11833}
11834
11835
Steve Blocka7e24c12009-10-30 11:49:00 +000011836#ifdef DEBUG
11837// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11838// Exclude the code in release mode.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011839RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011840 ASSERT(args.length() == 0);
11841 HandleScope scope;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011842#define COUNT_ENTRY(Name, argc, ressize) + 1
11843 int entry_count = 0
11844 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11845 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11846 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11847#undef COUNT_ENTRY
Steve Block44f0eee2011-05-26 01:26:41 +010011848 Factory* factory = isolate->factory();
11849 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
Steve Blocka7e24c12009-10-30 11:49:00 +000011850 int index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010011851 bool inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011852#define ADD_ENTRY(Name, argc, ressize) \
11853 { \
11854 HandleScope inner; \
Steve Block6ded16b2010-05-10 14:33:55 +010011855 Handle<String> name; \
11856 /* Inline runtime functions have an underscore in front of the name. */ \
11857 if (inline_runtime_functions) { \
Steve Block44f0eee2011-05-26 01:26:41 +010011858 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010011859 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11860 } else { \
Steve Block44f0eee2011-05-26 01:26:41 +010011861 name = factory->NewStringFromAscii( \
Steve Block6ded16b2010-05-10 14:33:55 +010011862 Vector<const char>(#Name, StrLength(#Name))); \
11863 } \
Steve Block44f0eee2011-05-26 01:26:41 +010011864 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011865 pair_elements->set(0, *name); \
11866 pair_elements->set(1, Smi::FromInt(argc)); \
Steve Block44f0eee2011-05-26 01:26:41 +010011867 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011868 elements->set(index++, *pair); \
Steve Blocka7e24c12009-10-30 11:49:00 +000011869 }
Steve Block6ded16b2010-05-10 14:33:55 +010011870 inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000011871 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010011872 inline_runtime_functions = true;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011873 INLINE_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010011874 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Blocka7e24c12009-10-30 11:49:00 +000011875#undef ADD_ENTRY
Ben Murdoche0cee9b2011-05-25 10:26:03 +010011876 ASSERT_EQ(index, entry_count);
Steve Block44f0eee2011-05-26 01:26:41 +010011877 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +000011878 return *result;
11879}
11880#endif
11881
11882
Ben Murdoch8b112d22011-06-08 16:22:53 +010011883RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011884 ASSERT(args.length() == 2);
11885 CONVERT_CHECKED(String, format, args[0]);
11886 CONVERT_CHECKED(JSArray, elms, args[1]);
11887 Vector<const char> chars = format->ToAsciiVector();
Steve Block44f0eee2011-05-26 01:26:41 +010011888 LOGGER->LogRuntime(chars, elms);
11889 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011890}
11891
11892
Ben Murdoch8b112d22011-06-08 16:22:53 +010011893RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011894 UNREACHABLE(); // implemented as macro in the parser
11895 return NULL;
11896}
11897
11898
11899// ----------------------------------------------------------------------------
11900// Implementation of Runtime
11901
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011902#define F(name, number_of_args, result_size) \
11903 { Runtime::k##name, Runtime::RUNTIME, #name, \
11904 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
Steve Blocka7e24c12009-10-30 11:49:00 +000011905
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011906
11907#define I(name, number_of_args, result_size) \
11908 { Runtime::kInline##name, Runtime::INLINE, \
11909 "_" #name, NULL, number_of_args, result_size },
11910
Steve Block44f0eee2011-05-26 01:26:41 +010011911static const Runtime::Function kIntrinsicFunctions[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000011912 RUNTIME_FUNCTION_LIST(F)
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011913 INLINE_FUNCTION_LIST(I)
11914 INLINE_RUNTIME_FUNCTION_LIST(I)
Steve Blocka7e24c12009-10-30 11:49:00 +000011915};
11916
Steve Blocka7e24c12009-10-30 11:49:00 +000011917
Steve Block44f0eee2011-05-26 01:26:41 +010011918MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11919 Object* dictionary) {
11920 ASSERT(Isolate::Current()->heap() == heap);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011921 ASSERT(dictionary != NULL);
11922 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11923 for (int i = 0; i < kNumFunctions; ++i) {
John Reck59135872010-11-02 12:39:01 -070011924 Object* name_symbol;
11925 { MaybeObject* maybe_name_symbol =
Steve Block44f0eee2011-05-26 01:26:41 +010011926 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
John Reck59135872010-11-02 12:39:01 -070011927 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11928 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011929 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
John Reck59135872010-11-02 12:39:01 -070011930 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11931 String::cast(name_symbol),
11932 Smi::FromInt(i),
11933 PropertyDetails(NONE, NORMAL));
11934 if (!maybe_dictionary->ToObject(&dictionary)) {
11935 // Non-recoverable failure. Calling code must restart heap
11936 // initialization.
11937 return maybe_dictionary;
11938 }
11939 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011940 }
11941 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000011942}
11943
11944
Steve Block44f0eee2011-05-26 01:26:41 +010011945const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11946 Heap* heap = name->GetHeap();
11947 int entry = heap->intrinsic_function_names()->FindEntry(*name);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011948 if (entry != kNotFound) {
Steve Block44f0eee2011-05-26 01:26:41 +010011949 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011950 int function_index = Smi::cast(smi_index)->value();
11951 return &(kIntrinsicFunctions[function_index]);
Steve Blocka7e24c12009-10-30 11:49:00 +000011952 }
11953 return NULL;
11954}
11955
11956
Steve Block44f0eee2011-05-26 01:26:41 +010011957const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011958 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11959}
11960
11961
Steve Blocka7e24c12009-10-30 11:49:00 +000011962void Runtime::PerformGC(Object* result) {
Steve Block44f0eee2011-05-26 01:26:41 +010011963 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011964 Failure* failure = Failure::cast(result);
11965 if (failure->IsRetryAfterGC()) {
11966 // Try to do a garbage collection; ignore it if it fails. The C
11967 // entry stub will throw an out-of-memory exception in that case.
Steve Block44f0eee2011-05-26 01:26:41 +010011968 isolate->heap()->CollectGarbage(failure->allocation_space());
Steve Blocka7e24c12009-10-30 11:49:00 +000011969 } else {
11970 // Handle last resort GC and make sure to allow future allocations
11971 // to grow the heap without causing GCs (if possible).
Steve Block44f0eee2011-05-26 01:26:41 +010011972 isolate->counters()->gc_last_resort_from_js()->Increment();
11973 isolate->heap()->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000011974 }
11975}
11976
11977
11978} } // namespace v8::internal