blob: 2aa443122c9713e5f11ba00e0b540bd3b3c26445 [file] [log] [blame]
Ben Murdochb0fe1622011-05-05 13:52:32 +01001// Copyright 2010 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"
43#include "jsregexp.h"
Steve Block6ded16b2010-05-10 14:33:55 +010044#include "liveedit.h"
Steve Block3ce2e202009-11-05 08:53:23 +000045#include "parser.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000046#include "platform.h"
47#include "runtime.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010048#include "runtime-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000049#include "scopeinfo.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000050#include "smart-pointer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000051#include "stub-cache.h"
Steve Block3ce2e202009-11-05 08:53:23 +000052#include "v8threads.h"
Steve Block59151502010-09-22 15:07:15 +010053#include "string-search.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000054
55namespace v8 {
56namespace internal {
57
58
59#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
61
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
73// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
80// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
87// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
103
104
John Reck59135872010-11-02 12:39:01 -0700105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
John Reck59135872010-11-02 12:39:01 -0700109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000121 JSObject* js_object = JSObject::cast(value);
John Reck59135872010-11-02 12:39:01 -0700122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
Leon Clarke4515c472010-02-03 11:58:03 +0000125 properties->set(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 }
127 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000132 JSObject* js_object = JSObject::cast(value);
John Reck59135872010-11-02 12:39:01 -0700133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
Leon Clarke4515c472010-02-03 11:58:03 +0000136 copy->InObjectPropertyAtPut(i, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 }
138 }
139 } else {
John Reck59135872010-11-02 12:39:01 -0700140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
Leon Clarke4515c472010-02-03 11:58:03 +0000148 String* key_string = String::cast(names->get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +0000149 PropertyAttributes attributes =
Leon Clarke4515c472010-02-03 11:58:03 +0000150 copy->GetLocalPropertyAttribute(key_string);
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
John Reck59135872010-11-02 12:39:01 -0700155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000158 JSObject* js_object = JSObject::cast(value);
John Reck59135872010-11-02 12:39:01 -0700159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
171 // Pixel elements cannot be created using an object literal.
Steve Block3ce2e202009-11-05 08:53:23 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
Iain Merrick75681382010-08-19 15:07:18 +0100176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
John Reck59135872010-11-02 12:39:01 -0700188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
Iain Merrick75681382010-08-19 15:07:18 +0100191 elements->set(i, result);
192 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 }
194 }
195 break;
196 }
197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
Leon Clarke4515c472010-02-03 11:58:03 +0000205 JSObject* js_object = JSObject::cast(value);
John Reck59135872010-11-02 12:39:01 -0700206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
218 }
219 return copy;
220}
221
222
John Reck59135872010-11-02 12:39:01 -0700223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
John Reck59135872010-11-02 12:39:01 -0700229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
231 return Heap::CopyJSObject(boilerplate);
232}
233
234
235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
238 bool* is_result_from_cache) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 if (FLAG_canonicalize_object_literal_maps) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100242 // Check that there are only symbols and array indices among keys.
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 int number_of_symbol_keys = 0;
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 }
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 const int kMaxKeys = 10;
262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
Kristian Monsen50ef84f2010-07-29 15:18:00 +0100266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
Steve Blocka7e24c12009-10-30 11:49:00 +0000275 }
276 *is_result_from_cache = true;
277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
280 *is_result_from_cache = false;
281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
284}
285
286
287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
290
291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
Steve Block6ded16b2010-05-10 14:33:55 +0100294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
308 &is_result_from_cache);
309
310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
Steve Block6ded16b2010-05-10 14:33:55 +0100311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 { // Add the constant properties to the boilerplate.
316 int length = constant_properties->length();
317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
318 length / 2,
319 !is_result_from_cache);
320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
330 Handle<Object> result;
331 uint32_t element_index = 0;
Iain Merrick75681382010-08-19 15:07:18 +0100332 if (key->IsSymbol()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +0100333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
Iain Merrick75681382010-08-19 15:07:18 +0100342 } else if (key->ToArrayIndex(&element_index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 // Array index (uint32).
Ben Murdoch086aeea2011-05-13 15:57:08 +0100344 result = SetOwnElement(boilerplate, element_index, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
Ben Murdoch086aeea2011-05-13 15:57:08 +0100353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000355 }
356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
360 if (result.is_null()) return result;
361 }
362 }
363
364 return boilerplate;
365}
366
367
368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
Iain Merrick75681382010-08-19 15:07:18 +0100376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
Iain Merrick75681382010-08-19 15:07:18 +0100381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
John Reck59135872010-11-02 12:39:01 -0700426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
437
438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
440
441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
444}
445
446
John Reck59135872010-11-02 12:39:01 -0700447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000448 HandleScope scope;
Steve Block6ded16b2010-05-10 14:33:55 +0100449 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Steve Block6ded16b2010-05-10 14:33:55 +0100453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
Leon Clarkee46be812010-01-19 14:06:41 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
John Reck59135872010-11-02 12:39:01 -0700470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000471 HandleScope scope;
Steve Block6ded16b2010-05-10 14:33:55 +0100472 ASSERT(args.length() == 4);
Leon Clarkee46be812010-01-19 14:06:41 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
Steve Block6ded16b2010-05-10 14:33:55 +0100476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
Leon Clarkee46be812010-01-19 14:06:41 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
Leon Clarkee46be812010-01-19 14:06:41 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
John Reck59135872010-11-02 12:39:01 -0700493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
John Reck59135872010-11-02 12:39:01 -0700512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
Iain Merrick75681382010-08-19 15:07:18 +0100527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
Leon Clarkee46be812010-01-19 14:06:41 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
John Reck59135872010-11-02 12:39:01 -0700535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
John Reck59135872010-11-02 12:39:01 -0700542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
John Reck59135872010-11-02 12:39:01 -0700548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 return object;
553}
554
555
John Reck59135872010-11-02 12:39:01 -0700556static MaybeObject* Runtime_ClassOf(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
564
John Reck59135872010-11-02 12:39:01 -0700565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
580// Inserts an object as the hidden prototype of another object.
John Reck59135872010-11-02 12:39:01 -0700581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
John Reck59135872010-11-02 12:39:01 -0700595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
John Reck59135872010-11-02 12:39:01 -0700603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
John Reck59135872010-11-02 12:39:01 -0700623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 0);
626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
Leon Clarkee46be812010-01-19 14:06:41 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100647// Enumerator used as indices into the array returned from GetOwnProperty
648enum PropertyDescriptorIndices {
649 IS_ACCESSOR_INDEX,
650 VALUE_INDEX,
651 GETTER_INDEX,
652 SETTER_INDEX,
653 WRITABLE_INDEX,
654 ENUMERABLE_INDEX,
655 CONFIGURABLE_INDEX,
656 DESCRIPTOR_SIZE
657};
658
Leon Clarkee46be812010-01-19 14:06:41 +0000659// Returns an array with the property description:
660// if args[1] is not a property on args[0]
661// returns undefined
662// if args[1] is a data property on args[0]
663// [false, value, Writeable, Enumerable, Configurable]
664// if args[1] is an accessor on args[0]
665// [true, GetFunction, SetFunction, Enumerable, Configurable]
John Reck59135872010-11-02 12:39:01 -0700666static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000667 ASSERT(args.length() == 2);
668 HandleScope scope;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100669 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
Leon Clarkee46be812010-01-19 14:06:41 +0000670 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
671 LookupResult result;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100672 CONVERT_ARG_CHECKED(JSObject, obj, 0);
673 CONVERT_ARG_CHECKED(String, name, 1);
Leon Clarkee46be812010-01-19 14:06:41 +0000674
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100675 // This could be an element.
676 uint32_t index;
677 if (name->AsArrayIndex(&index)) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100678 switch (obj->HasLocalElement(index)) {
679 case JSObject::UNDEFINED_ELEMENT:
680 return Heap::undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100681
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100682 case JSObject::STRING_CHARACTER_ELEMENT: {
683 // Special handling of string objects according to ECMAScript 5
684 // 15.5.5.2. Note that this might be a string object with elements
685 // other than the actual string value. This is covered by the
686 // subsequent cases.
687 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
688 Handle<String> str(String::cast(js_value->value()));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100689 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100690
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100691 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
692 elms->set(VALUE_INDEX, *substr);
693 elms->set(WRITABLE_INDEX, Heap::false_value());
694 elms->set(ENUMERABLE_INDEX, Heap::false_value());
695 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
696 return *desc;
697 }
698
699 case JSObject::INTERCEPTED_ELEMENT:
700 case JSObject::FAST_ELEMENT: {
701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100702 Handle<Object> element = GetElement(Handle<Object>(obj), index);
703 elms->set(VALUE_INDEX, *element);
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100704 elms->set(WRITABLE_INDEX, Heap::true_value());
705 elms->set(ENUMERABLE_INDEX, Heap::true_value());
706 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
707 return *desc;
708 }
709
710 case JSObject::DICTIONARY_ELEMENT: {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100711 NumberDictionary* dictionary = obj->element_dictionary();
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100712 int entry = dictionary->FindEntry(index);
713 ASSERT(entry != NumberDictionary::kNotFound);
714 PropertyDetails details = dictionary->DetailsAt(entry);
715 switch (details.type()) {
716 case CALLBACKS: {
717 // This is an accessor property with getter and/or setter.
718 FixedArray* callbacks =
719 FixedArray::cast(dictionary->ValueAt(entry));
720 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100721 elms->set(GETTER_INDEX, callbacks->get(0));
722 elms->set(SETTER_INDEX, callbacks->get(1));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100723 break;
724 }
725 case NORMAL:
726 // This is a data property.
727 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100728 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100729 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
730 break;
731 default:
732 UNREACHABLE();
733 break;
734 }
735 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
736 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
737 return *desc;
738 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100739 }
740 }
741
Leon Clarkee46be812010-01-19 14:06:41 +0000742 // Use recursive implementation to also traverse hidden prototypes
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100743 GetOwnPropertyImplementation(*obj, *name, &result);
Leon Clarkee46be812010-01-19 14:06:41 +0000744
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100745 if (!result.IsProperty()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000746 return Heap::undefined_value();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100747 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100748 if (result.type() == CALLBACKS) {
749 Object* structure = result.GetCallbackObject();
750 if (structure->IsProxy() || structure->IsAccessorInfo()) {
751 // Property that is internally implemented as a callback or
752 // an API defined callback.
753 Object* value;
754 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
755 *obj, structure, *name, result.holder());
756 if (!maybe_value->ToObject(&value)) return maybe_value;
757 }
758 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
759 elms->set(VALUE_INDEX, value);
760 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
761 } else if (structure->IsFixedArray()) {
762 // __defineGetter__/__defineSetter__ callback.
763 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
764 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
765 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
766 } else {
767 return Heap::undefined_value();
768 }
769 } else {
770 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
771 elms->set(VALUE_INDEX, result.GetLazyValue());
772 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
Leon Clarkee46be812010-01-19 14:06:41 +0000773 }
774
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100775 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
776 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
Leon Clarkee46be812010-01-19 14:06:41 +0000777 return *desc;
778}
779
780
John Reck59135872010-11-02 12:39:01 -0700781static MaybeObject* Runtime_PreventExtensions(Arguments args) {
Steve Block8defd9f2010-07-08 12:39:36 +0100782 ASSERT(args.length() == 1);
783 CONVERT_CHECKED(JSObject, obj, args[0]);
784 return obj->PreventExtensions();
785}
786
John Reck59135872010-11-02 12:39:01 -0700787static MaybeObject* Runtime_IsExtensible(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +0000788 ASSERT(args.length() == 1);
789 CONVERT_CHECKED(JSObject, obj, args[0]);
790 return obj->map()->is_extensible() ? Heap::true_value()
791 : Heap::false_value();
792}
793
794
John Reck59135872010-11-02 12:39:01 -0700795static MaybeObject* Runtime_RegExpCompile(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000796 HandleScope scope;
797 ASSERT(args.length() == 3);
798 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
799 CONVERT_ARG_CHECKED(String, pattern, 1);
800 CONVERT_ARG_CHECKED(String, flags, 2);
801 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
802 if (result.is_null()) return Failure::Exception();
803 return *result;
804}
805
806
John Reck59135872010-11-02 12:39:01 -0700807static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 HandleScope scope;
809 ASSERT(args.length() == 1);
810 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
811 return *Factory::CreateApiFunction(data);
812}
813
814
John Reck59135872010-11-02 12:39:01 -0700815static MaybeObject* Runtime_IsTemplate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 ASSERT(args.length() == 1);
817 Object* arg = args[0];
818 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
819 return Heap::ToBoolean(result);
820}
821
822
John Reck59135872010-11-02 12:39:01 -0700823static MaybeObject* Runtime_GetTemplateField(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000824 ASSERT(args.length() == 2);
825 CONVERT_CHECKED(HeapObject, templ, args[0]);
826 CONVERT_CHECKED(Smi, field, args[1]);
827 int index = field->value();
828 int offset = index * kPointerSize + HeapObject::kHeaderSize;
829 InstanceType type = templ->map()->instance_type();
830 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
831 type == OBJECT_TEMPLATE_INFO_TYPE);
832 RUNTIME_ASSERT(offset > 0);
Steve Block3ce2e202009-11-05 08:53:23 +0000833 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000834 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
835 } else {
836 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
837 }
838 return *HeapObject::RawField(templ, offset);
839}
840
841
John Reck59135872010-11-02 12:39:01 -0700842static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 ASSERT(args.length() == 1);
844 CONVERT_CHECKED(HeapObject, object, args[0]);
845 Map* old_map = object->map();
846 bool needs_access_checks = old_map->is_access_check_needed();
847 if (needs_access_checks) {
848 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -0700849 Object* new_map;
850 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
851 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
852 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000853
854 Map::cast(new_map)->set_is_access_check_needed(false);
855 object->set_map(Map::cast(new_map));
856 }
857 return needs_access_checks ? Heap::true_value() : Heap::false_value();
858}
859
860
John Reck59135872010-11-02 12:39:01 -0700861static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 ASSERT(args.length() == 1);
863 CONVERT_CHECKED(HeapObject, object, args[0]);
864 Map* old_map = object->map();
865 if (!old_map->is_access_check_needed()) {
866 // Copy map so it won't interfere constructor's initial map.
John Reck59135872010-11-02 12:39:01 -0700867 Object* new_map;
868 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
869 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
870 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000871
872 Map::cast(new_map)->set_is_access_check_needed(true);
873 object->set_map(Map::cast(new_map));
874 }
875 return Heap::undefined_value();
876}
877
878
John Reck59135872010-11-02 12:39:01 -0700879static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 HandleScope scope;
881 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
882 Handle<Object> args[2] = { type_handle, name };
883 Handle<Object> error =
884 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
885 return Top::Throw(*error);
886}
887
888
John Reck59135872010-11-02 12:39:01 -0700889static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 HandleScope scope;
891 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
892
Steve Block3ce2e202009-11-05 08:53:23 +0000893 Handle<Context> context = args.at<Context>(0);
894 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 bool is_eval = Smi::cast(args[2])->value() == 1;
896
897 // Compute the property attributes. According to ECMA-262, section
898 // 13, page 71, the property must be read-only and
899 // non-deletable. However, neither SpiderMonkey nor KJS creates the
900 // property as read-only, so we don't either.
901 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
902
903 // Traverse the name/value pairs and set the properties.
904 int length = pairs->length();
905 for (int i = 0; i < length; i += 2) {
906 HandleScope scope;
907 Handle<String> name(String::cast(pairs->get(i)));
908 Handle<Object> value(pairs->get(i + 1));
909
910 // We have to declare a global const property. To capture we only
911 // assign to it when evaluating the assignment for "const x =
912 // <expr>" the initial value is the hole.
913 bool is_const_property = value->IsTheHole();
914
915 if (value->IsUndefined() || is_const_property) {
916 // Lookup the property in the global object, and don't set the
917 // value of the variable if the property is already there.
918 LookupResult lookup;
919 global->Lookup(*name, &lookup);
920 if (lookup.IsProperty()) {
921 // Determine if the property is local by comparing the holder
922 // against the global object. The information will be used to
923 // avoid throwing re-declaration errors when declaring
924 // variables or constants that exist in the prototype chain.
925 bool is_local = (*global == lookup.holder());
926 // Get the property attributes and determine if the property is
927 // read-only.
928 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
929 bool is_read_only = (attributes & READ_ONLY) != 0;
930 if (lookup.type() == INTERCEPTOR) {
931 // If the interceptor says the property is there, we
932 // just return undefined without overwriting the property.
933 // Otherwise, we continue to setting the property.
934 if (attributes != ABSENT) {
935 // Check if the existing property conflicts with regards to const.
936 if (is_local && (is_read_only || is_const_property)) {
937 const char* type = (is_read_only) ? "const" : "var";
938 return ThrowRedeclarationError(type, name);
939 };
940 // The property already exists without conflicting: Go to
941 // the next declaration.
942 continue;
943 }
944 // Fall-through and introduce the absent property by using
945 // SetProperty.
946 } else {
947 if (is_local && (is_read_only || is_const_property)) {
948 const char* type = (is_read_only) ? "const" : "var";
949 return ThrowRedeclarationError(type, name);
950 }
951 // The property already exists without conflicting: Go to
952 // the next declaration.
953 continue;
954 }
955 }
956 } else {
957 // Copy the function and update its context. Use it as value.
Steve Block6ded16b2010-05-10 14:33:55 +0100958 Handle<SharedFunctionInfo> shared =
959 Handle<SharedFunctionInfo>::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000960 Handle<JSFunction> function =
Steve Block6ded16b2010-05-10 14:33:55 +0100961 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 value = function;
963 }
964
965 LookupResult lookup;
966 global->LocalLookup(*name, &lookup);
967
968 PropertyAttributes attributes = is_const_property
969 ? static_cast<PropertyAttributes>(base | READ_ONLY)
970 : base;
971
972 if (lookup.IsProperty()) {
973 // There's a local property that we need to overwrite because
974 // we're either declaring a function or there's an interceptor
975 // that claims the property is absent.
976
977 // Check for conflicting re-declarations. We cannot have
978 // conflicting types in case of intercepted properties because
979 // they are absent.
980 if (lookup.type() != INTERCEPTOR &&
981 (lookup.IsReadOnly() || is_const_property)) {
982 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
983 return ThrowRedeclarationError(type, name);
984 }
985 SetProperty(global, name, value, attributes);
986 } else {
987 // If a property with this name does not already exist on the
988 // global object add the property locally. We take special
989 // precautions to always add it as a local property even in case
990 // of callbacks in the prototype chain (this rules out using
991 // SetProperty). Also, we must use the handle-based version to
992 // avoid GC issues.
Ben Murdoch086aeea2011-05-13 15:57:08 +0100993 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000994 }
995 }
996
997 return Heap::undefined_value();
998}
999
1000
John Reck59135872010-11-02 12:39:01 -07001001static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001002 HandleScope scope;
1003 ASSERT(args.length() == 4);
1004
1005 CONVERT_ARG_CHECKED(Context, context, 0);
1006 Handle<String> name(String::cast(args[1]));
1007 PropertyAttributes mode =
1008 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001009 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001010 Handle<Object> initial_value(args[3]);
1011
1012 // Declarations are always done in the function context.
1013 context = Handle<Context>(context->fcontext());
1014
1015 int index;
1016 PropertyAttributes attributes;
1017 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
1018 Handle<Object> holder =
1019 context->Lookup(name, flags, &index, &attributes);
1020
1021 if (attributes != ABSENT) {
1022 // The name was declared before; check for conflicting
1023 // re-declarations: This is similar to the code in parser.cc in
1024 // the AstBuildingParser::Declare function.
1025 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1026 // Functions are not read-only.
1027 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1028 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1029 return ThrowRedeclarationError(type, name);
1030 }
1031
1032 // Initialize it if necessary.
1033 if (*initial_value != NULL) {
1034 if (index >= 0) {
1035 // The variable or constant context slot should always be in
Steve Blockd0582a62009-12-15 09:54:21 +00001036 // the function context or the arguments object.
1037 if (holder->IsContext()) {
1038 ASSERT(holder.is_identical_to(context));
1039 if (((attributes & READ_ONLY) == 0) ||
1040 context->get(index)->IsTheHole()) {
1041 context->set(index, *initial_value);
1042 }
1043 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001044 // The holder is an arguments object.
1045 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1046 SetElement(arguments, index, initial_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 }
1048 } else {
1049 // Slow case: The property is not in the FixedArray part of the context.
1050 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
1051 SetProperty(context_ext, name, initial_value, mode);
1052 }
1053 }
1054
1055 } else {
1056 // The property is not in the function context. It needs to be
1057 // "declared" in the function context's extension context, or in the
1058 // global context.
1059 Handle<JSObject> context_ext;
1060 if (context->has_extension()) {
1061 // The function context's extension context exists - use it.
1062 context_ext = Handle<JSObject>(context->extension());
1063 } else {
1064 // The function context's extension context does not exists - allocate
1065 // it.
1066 context_ext = Factory::NewJSObject(Top::context_extension_function());
1067 // And store it in the extension slot.
1068 context->set_extension(*context_ext);
1069 }
1070 ASSERT(*context_ext != NULL);
1071
1072 // Declare the property by setting it to the initial value if provided,
1073 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1074 // constant declarations).
1075 ASSERT(!context_ext->HasLocalProperty(*name));
1076 Handle<Object> value(Heap::undefined_value());
1077 if (*initial_value != NULL) value = initial_value;
1078 SetProperty(context_ext, name, value, mode);
1079 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1080 }
1081
1082 return Heap::undefined_value();
1083}
1084
1085
John Reck59135872010-11-02 12:39:01 -07001086static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001087 NoHandleAllocation nha;
1088
1089 // Determine if we need to assign to the variable if it already
1090 // exists (based on the number of arguments).
1091 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1092 bool assign = args.length() == 2;
1093
1094 CONVERT_ARG_CHECKED(String, name, 0);
1095 GlobalObject* global = Top::context()->global();
1096
1097 // According to ECMA-262, section 12.2, page 62, the property must
1098 // not be deletable.
1099 PropertyAttributes attributes = DONT_DELETE;
1100
1101 // Lookup the property locally in the global object. If it isn't
1102 // there, there is a property with this name in the prototype chain.
1103 // We follow Safari and Firefox behavior and only set the property
1104 // locally if there is an explicit initialization value that we have
1105 // to assign to the property. When adding the property we take
1106 // special precautions to always add it as a local property even in
1107 // case of callbacks in the prototype chain (this rules out using
Ben Murdoch086aeea2011-05-13 15:57:08 +01001108 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
Steve Blocka7e24c12009-10-30 11:49:00 +00001109 // this.
Steve Blockd0582a62009-12-15 09:54:21 +00001110 // Note that objects can have hidden prototypes, so we need to traverse
1111 // the whole chain of hidden prototypes to do a 'local' lookup.
1112 JSObject* real_holder = global;
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 LookupResult lookup;
Steve Blockd0582a62009-12-15 09:54:21 +00001114 while (true) {
1115 real_holder->LocalLookup(*name, &lookup);
1116 if (lookup.IsProperty()) {
1117 // Determine if this is a redeclaration of something read-only.
1118 if (lookup.IsReadOnly()) {
1119 // If we found readonly property on one of hidden prototypes,
1120 // just shadow it.
1121 if (real_holder != Top::context()->global()) break;
1122 return ThrowRedeclarationError("const", name);
1123 }
1124
1125 // Determine if this is a redeclaration of an intercepted read-only
1126 // property and figure out if the property exists at all.
1127 bool found = true;
1128 PropertyType type = lookup.type();
1129 if (type == INTERCEPTOR) {
1130 HandleScope handle_scope;
1131 Handle<JSObject> holder(real_holder);
1132 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1133 real_holder = *holder;
1134 if (intercepted == ABSENT) {
1135 // The interceptor claims the property isn't there. We need to
1136 // make sure to introduce it.
1137 found = false;
1138 } else if ((intercepted & READ_ONLY) != 0) {
1139 // The property is present, but read-only. Since we're trying to
1140 // overwrite it with a variable declaration we must throw a
1141 // re-declaration error. However if we found readonly property
1142 // on one of hidden prototypes, just shadow it.
1143 if (real_holder != Top::context()->global()) break;
1144 return ThrowRedeclarationError("const", name);
1145 }
1146 }
1147
1148 if (found && !assign) {
1149 // The global property is there and we're not assigning any value
1150 // to it. Just return.
1151 return Heap::undefined_value();
1152 }
1153
1154 // Assign the value (or undefined) to the property.
1155 Object* value = (assign) ? args[1] : Heap::undefined_value();
1156 return real_holder->SetProperty(&lookup, *name, value, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 }
Steve Blockd0582a62009-12-15 09:54:21 +00001158
1159 Object* proto = real_holder->GetPrototype();
1160 if (!proto->IsJSObject())
1161 break;
1162
1163 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1164 break;
1165
1166 real_holder = JSObject::cast(proto);
Steve Blocka7e24c12009-10-30 11:49:00 +00001167 }
1168
Steve Blockd0582a62009-12-15 09:54:21 +00001169 global = Top::context()->global();
1170 if (assign) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001171 return global->SetLocalPropertyIgnoreAttributes(*name,
1172 args[1],
1173 attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001174 }
Steve Blockd0582a62009-12-15 09:54:21 +00001175 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001176}
1177
1178
John Reck59135872010-11-02 12:39:01 -07001179static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 // All constants are declared with an initial value. The name
1181 // of the constant is the first argument and the initial value
1182 // is the second.
1183 RUNTIME_ASSERT(args.length() == 2);
1184 CONVERT_ARG_CHECKED(String, name, 0);
1185 Handle<Object> value = args.at<Object>(1);
1186
1187 // Get the current global object from top.
1188 GlobalObject* global = Top::context()->global();
1189
1190 // According to ECMA-262, section 12.2, page 62, the property must
1191 // not be deletable. Since it's a const, it must be READ_ONLY too.
1192 PropertyAttributes attributes =
1193 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1194
1195 // Lookup the property locally in the global object. If it isn't
1196 // there, we add the property and take special precautions to always
1197 // add it as a local property even in case of callbacks in the
1198 // prototype chain (this rules out using SetProperty).
Ben Murdoch086aeea2011-05-13 15:57:08 +01001199 // We use SetLocalPropertyIgnoreAttributes instead
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 LookupResult lookup;
1201 global->LocalLookup(*name, &lookup);
1202 if (!lookup.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01001203 return global->SetLocalPropertyIgnoreAttributes(*name,
1204 *value,
1205 attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 }
1207
1208 // Determine if this is a redeclaration of something not
1209 // read-only. In case the result is hidden behind an interceptor we
1210 // need to ask it for the property attributes.
1211 if (!lookup.IsReadOnly()) {
1212 if (lookup.type() != INTERCEPTOR) {
1213 return ThrowRedeclarationError("var", name);
1214 }
1215
1216 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1217
1218 // Throw re-declaration error if the intercepted property is present
1219 // but not read-only.
1220 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1221 return ThrowRedeclarationError("var", name);
1222 }
1223
1224 // Restore global object from context (in case of GC) and continue
1225 // with setting the value because the property is either absent or
1226 // read-only. We also have to do redo the lookup.
John Reck59135872010-11-02 12:39:01 -07001227 HandleScope handle_scope;
1228 Handle<GlobalObject>global(Top::context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +00001229
1230 // BUG 1213579: Handle the case where we have to set a read-only
1231 // property through an interceptor and only do it if it's
1232 // uninitialized, e.g. the hole. Nirk...
John Reck59135872010-11-02 12:39:01 -07001233 SetProperty(global, name, value, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 return *value;
1235 }
1236
1237 // Set the value, but only we're assigning the initial value to a
1238 // constant. For now, we determine this by checking if the
1239 // current value is the hole.
1240 PropertyType type = lookup.type();
1241 if (type == FIELD) {
1242 FixedArray* properties = global->properties();
1243 int index = lookup.GetFieldIndex();
1244 if (properties->get(index)->IsTheHole()) {
1245 properties->set(index, *value);
1246 }
1247 } else if (type == NORMAL) {
1248 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1249 global->SetNormalizedProperty(&lookup, *value);
1250 }
1251 } else {
1252 // Ignore re-initialization of constants that have already been
1253 // assigned a function value.
1254 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1255 }
1256
1257 // Use the set value as the result of the operation.
1258 return *value;
1259}
1260
1261
John Reck59135872010-11-02 12:39:01 -07001262static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 HandleScope scope;
1264 ASSERT(args.length() == 3);
1265
1266 Handle<Object> value(args[0]);
1267 ASSERT(!value->IsTheHole());
1268 CONVERT_ARG_CHECKED(Context, context, 1);
1269 Handle<String> name(String::cast(args[2]));
1270
1271 // Initializations are always done in the function context.
1272 context = Handle<Context>(context->fcontext());
1273
1274 int index;
1275 PropertyAttributes attributes;
1276 ContextLookupFlags flags = FOLLOW_CHAINS;
1277 Handle<Object> holder =
1278 context->Lookup(name, flags, &index, &attributes);
1279
1280 // In most situations, the property introduced by the const
1281 // declaration should be present in the context extension object.
1282 // However, because declaration and initialization are separate, the
1283 // property might have been deleted (if it was introduced by eval)
1284 // before we reach the initialization point.
1285 //
1286 // Example:
1287 //
1288 // function f() { eval("delete x; const x;"); }
1289 //
1290 // In that case, the initialization behaves like a normal assignment
1291 // to property 'x'.
1292 if (index >= 0) {
1293 // Property was found in a context.
1294 if (holder->IsContext()) {
1295 // The holder cannot be the function context. If it is, there
1296 // should have been a const redeclaration error when declaring
1297 // the const property.
1298 ASSERT(!holder.is_identical_to(context));
1299 if ((attributes & READ_ONLY) == 0) {
1300 Handle<Context>::cast(holder)->set(index, *value);
1301 }
1302 } else {
1303 // The holder is an arguments object.
1304 ASSERT((attributes & READ_ONLY) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001305 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1306 SetElement(arguments, index, value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 }
1308 return *value;
1309 }
1310
1311 // The property could not be found, we introduce it in the global
1312 // context.
1313 if (attributes == ABSENT) {
1314 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1315 SetProperty(global, name, value, NONE);
1316 return *value;
1317 }
1318
1319 // The property was present in a context extension object.
1320 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
1321
1322 if (*context_ext == context->extension()) {
1323 // This is the property that was introduced by the const
1324 // declaration. Set it if it hasn't been set before. NOTE: We
1325 // cannot use GetProperty() to get the current value as it
1326 // 'unholes' the value.
1327 LookupResult lookup;
1328 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1329 ASSERT(lookup.IsProperty()); // the property was declared
1330 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1331
1332 PropertyType type = lookup.type();
1333 if (type == FIELD) {
1334 FixedArray* properties = context_ext->properties();
1335 int index = lookup.GetFieldIndex();
1336 if (properties->get(index)->IsTheHole()) {
1337 properties->set(index, *value);
1338 }
1339 } else if (type == NORMAL) {
1340 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1341 context_ext->SetNormalizedProperty(&lookup, *value);
1342 }
1343 } else {
1344 // We should not reach here. Any real, named property should be
1345 // either a field or a dictionary slot.
1346 UNREACHABLE();
1347 }
1348 } else {
1349 // The property was found in a different context extension object.
1350 // Set it if it is not a read-only property.
1351 if ((attributes & READ_ONLY) == 0) {
1352 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1353 // Setting a property might throw an exception. Exceptions
1354 // are converted to empty handles in handle operations. We
1355 // need to convert back to exceptions here.
1356 if (set.is_null()) {
1357 ASSERT(Top::has_pending_exception());
1358 return Failure::Exception();
1359 }
1360 }
1361 }
1362
1363 return *value;
1364}
1365
1366
John Reck59135872010-11-02 12:39:01 -07001367static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
Steve Blocka7e24c12009-10-30 11:49:00 +00001368 Arguments args) {
1369 HandleScope scope;
1370 ASSERT(args.length() == 2);
1371 CONVERT_ARG_CHECKED(JSObject, object, 0);
1372 CONVERT_SMI_CHECKED(properties, args[1]);
1373 if (object->HasFastProperties()) {
1374 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1375 }
1376 return *object;
1377}
1378
1379
John Reck59135872010-11-02 12:39:01 -07001380static MaybeObject* Runtime_RegExpExec(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 HandleScope scope;
1382 ASSERT(args.length() == 4);
1383 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1384 CONVERT_ARG_CHECKED(String, subject, 1);
1385 // Due to the way the JS calls are constructed this must be less than the
1386 // length of a string, i.e. it is always a Smi. We check anyway for security.
1387 CONVERT_SMI_CHECKED(index, args[2]);
1388 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
1389 RUNTIME_ASSERT(last_match_info->HasFastElements());
1390 RUNTIME_ASSERT(index >= 0);
1391 RUNTIME_ASSERT(index <= subject->length());
Leon Clarkee46be812010-01-19 14:06:41 +00001392 Counters::regexp_entry_runtime.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 Handle<Object> result = RegExpImpl::Exec(regexp,
1394 subject,
1395 index,
1396 last_match_info);
1397 if (result.is_null()) return Failure::Exception();
1398 return *result;
1399}
1400
1401
John Reck59135872010-11-02 12:39:01 -07001402static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001403 ASSERT(args.length() == 3);
1404 CONVERT_SMI_CHECKED(elements_count, args[0]);
1405 if (elements_count > JSArray::kMaxFastElementsLength) {
1406 return Top::ThrowIllegalOperation();
1407 }
John Reck59135872010-11-02 12:39:01 -07001408 Object* new_object;
1409 { MaybeObject* maybe_new_object =
1410 Heap::AllocateFixedArrayWithHoles(elements_count);
1411 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1412 }
Steve Block6ded16b2010-05-10 14:33:55 +01001413 FixedArray* elements = FixedArray::cast(new_object);
John Reck59135872010-11-02 12:39:01 -07001414 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1415 NEW_SPACE,
1416 OLD_POINTER_SPACE);
1417 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1418 }
Steve Block6ded16b2010-05-10 14:33:55 +01001419 {
1420 AssertNoAllocation no_gc;
1421 HandleScope scope;
1422 reinterpret_cast<HeapObject*>(new_object)->
1423 set_map(Top::global_context()->regexp_result_map());
1424 }
1425 JSArray* array = JSArray::cast(new_object);
1426 array->set_properties(Heap::empty_fixed_array());
1427 array->set_elements(elements);
1428 array->set_length(Smi::FromInt(elements_count));
1429 // Write in-object properties after the length of the array.
1430 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1431 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1432 return array;
1433}
1434
1435
John Reck59135872010-11-02 12:39:01 -07001436static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001437 AssertNoAllocation no_alloc;
1438 ASSERT(args.length() == 5);
1439 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1440 CONVERT_CHECKED(String, source, args[1]);
1441
1442 Object* global = args[2];
1443 if (!global->IsTrue()) global = Heap::false_value();
1444
1445 Object* ignoreCase = args[3];
1446 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1447
1448 Object* multiline = args[4];
1449 if (!multiline->IsTrue()) multiline = Heap::false_value();
1450
1451 Map* map = regexp->map();
1452 Object* constructor = map->constructor();
1453 if (constructor->IsJSFunction() &&
1454 JSFunction::cast(constructor)->initial_map() == map) {
1455 // If we still have the original map, set in-object properties directly.
1456 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1457 // TODO(lrn): Consider skipping write barrier on booleans as well.
1458 // Both true and false should be in oldspace at all times.
1459 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1460 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1461 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1462 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1463 Smi::FromInt(0),
1464 SKIP_WRITE_BARRIER);
1465 return regexp;
1466 }
1467
John Reck59135872010-11-02 12:39:01 -07001468 // Map has changed, so use generic, but slower, method. Since these
1469 // properties were all added as DONT_DELETE they must be present and
1470 // normal so no failures can be expected.
Steve Block6ded16b2010-05-10 14:33:55 +01001471 PropertyAttributes final =
1472 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1473 PropertyAttributes writable =
1474 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
John Reck59135872010-11-02 12:39:01 -07001475 MaybeObject* result;
Ben Murdoch086aeea2011-05-13 15:57:08 +01001476 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1477 source,
1478 final);
John Reck59135872010-11-02 12:39:01 -07001479 ASSERT(!result->IsFailure());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001480 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1481 global,
1482 final);
John Reck59135872010-11-02 12:39:01 -07001483 ASSERT(!result->IsFailure());
1484 result =
Ben Murdoch086aeea2011-05-13 15:57:08 +01001485 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1486 ignoreCase,
1487 final);
John Reck59135872010-11-02 12:39:01 -07001488 ASSERT(!result->IsFailure());
Ben Murdoch086aeea2011-05-13 15:57:08 +01001489 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1490 multiline,
1491 final);
John Reck59135872010-11-02 12:39:01 -07001492 ASSERT(!result->IsFailure());
1493 result =
Ben Murdoch086aeea2011-05-13 15:57:08 +01001494 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1495 Smi::FromInt(0),
1496 writable);
John Reck59135872010-11-02 12:39:01 -07001497 ASSERT(!result->IsFailure());
1498 USE(result);
Steve Block6ded16b2010-05-10 14:33:55 +01001499 return regexp;
1500}
1501
1502
John Reck59135872010-11-02 12:39:01 -07001503static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001504 HandleScope scope;
1505 ASSERT(args.length() == 1);
1506 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1507 // This is necessary to enable fast checks for absence of elements
1508 // on Array.prototype and below.
1509 prototype->set_elements(Heap::empty_fixed_array());
1510 return Smi::FromInt(0);
1511}
1512
1513
Steve Block6ded16b2010-05-10 14:33:55 +01001514static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1515 const char* name,
Kristian Monsen25f61362010-05-21 11:50:48 +01001516 Builtins::Name builtin_name) {
Steve Block6ded16b2010-05-10 14:33:55 +01001517 Handle<String> key = Factory::LookupAsciiSymbol(name);
1518 Handle<Code> code(Builtins::builtin(builtin_name));
1519 Handle<JSFunction> optimized = Factory::NewFunction(key,
1520 JS_OBJECT_TYPE,
1521 JSObject::kHeaderSize,
1522 code,
1523 false);
1524 optimized->shared()->DontAdaptArguments();
Steve Block6ded16b2010-05-10 14:33:55 +01001525 SetProperty(holder, key, optimized, NONE);
1526 return optimized;
1527}
1528
1529
John Reck59135872010-11-02 12:39:01 -07001530static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001531 HandleScope scope;
1532 ASSERT(args.length() == 1);
1533 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1534
Kristian Monsen25f61362010-05-21 11:50:48 +01001535 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1536 InstallBuiltin(holder, "push", Builtins::ArrayPush);
Steve Block6ded16b2010-05-10 14:33:55 +01001537 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1538 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1539 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1540 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
1541 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
1542
1543 return *holder;
1544}
1545
1546
John Reck59135872010-11-02 12:39:01 -07001547static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001548 // Returns a real global receiver, not one of builtins object.
1549 Context* global_context = Top::context()->global()->global_context();
1550 return global_context->global()->global_receiver();
1551}
1552
1553
John Reck59135872010-11-02 12:39:01 -07001554static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 4);
1557 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1558 int index = Smi::cast(args[1])->value();
1559 Handle<String> pattern = args.at<String>(2);
1560 Handle<String> flags = args.at<String>(3);
1561
1562 // Get the RegExp function from the context in the literals array.
1563 // This is the RegExp function from the context in which the
1564 // function was created. We do not use the RegExp function from the
1565 // current global context because this might be the RegExp function
1566 // from another context which we should not have access to.
1567 Handle<JSFunction> constructor =
1568 Handle<JSFunction>(
1569 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
1570 // Compute the regular expression literal.
1571 bool has_pending_exception;
1572 Handle<Object> regexp =
1573 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1574 &has_pending_exception);
1575 if (has_pending_exception) {
1576 ASSERT(Top::has_pending_exception());
1577 return Failure::Exception();
1578 }
1579 literals->set(index, *regexp);
1580 return *regexp;
1581}
1582
1583
John Reck59135872010-11-02 12:39:01 -07001584static MaybeObject* Runtime_FunctionGetName(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001585 NoHandleAllocation ha;
1586 ASSERT(args.length() == 1);
1587
1588 CONVERT_CHECKED(JSFunction, f, args[0]);
1589 return f->shared()->name();
1590}
1591
1592
John Reck59135872010-11-02 12:39:01 -07001593static MaybeObject* Runtime_FunctionSetName(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001594 NoHandleAllocation ha;
1595 ASSERT(args.length() == 2);
1596
1597 CONVERT_CHECKED(JSFunction, f, args[0]);
1598 CONVERT_CHECKED(String, name, args[1]);
1599 f->shared()->set_name(name);
1600 return Heap::undefined_value();
1601}
1602
1603
John Reck59135872010-11-02 12:39:01 -07001604static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01001605 NoHandleAllocation ha;
1606 ASSERT(args.length() == 1);
1607
1608 CONVERT_CHECKED(JSFunction, f, args[0]);
John Reck59135872010-11-02 12:39:01 -07001609 Object* obj;
1610 { MaybeObject* maybe_obj = f->RemovePrototype();
1611 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1612 }
Steve Block6ded16b2010-05-10 14:33:55 +01001613
1614 return Heap::undefined_value();
1615}
1616
1617
John Reck59135872010-11-02 12:39:01 -07001618static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001619 HandleScope scope;
1620 ASSERT(args.length() == 1);
1621
1622 CONVERT_CHECKED(JSFunction, fun, args[0]);
1623 Handle<Object> script = Handle<Object>(fun->shared()->script());
1624 if (!script->IsScript()) return Heap::undefined_value();
1625
1626 return *GetScriptWrapper(Handle<Script>::cast(script));
1627}
1628
1629
John Reck59135872010-11-02 12:39:01 -07001630static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 1);
1633
1634 CONVERT_CHECKED(JSFunction, f, args[0]);
1635 return f->shared()->GetSourceCode();
1636}
1637
1638
John Reck59135872010-11-02 12:39:01 -07001639static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 NoHandleAllocation ha;
1641 ASSERT(args.length() == 1);
1642
1643 CONVERT_CHECKED(JSFunction, fun, args[0]);
1644 int pos = fun->shared()->start_position();
1645 return Smi::FromInt(pos);
1646}
1647
1648
John Reck59135872010-11-02 12:39:01 -07001649static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001650 ASSERT(args.length() == 2);
1651
Ben Murdochb0fe1622011-05-05 13:52:32 +01001652 CONVERT_CHECKED(Code, code, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001653 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1654
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1656
1657 Address pc = code->address() + offset;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001658 return Smi::FromInt(code->SourcePosition(pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00001659}
1660
1661
1662
John Reck59135872010-11-02 12:39:01 -07001663static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 NoHandleAllocation ha;
1665 ASSERT(args.length() == 2);
1666
1667 CONVERT_CHECKED(JSFunction, fun, args[0]);
1668 CONVERT_CHECKED(String, name, args[1]);
1669 fun->SetInstanceClassName(name);
1670 return Heap::undefined_value();
1671}
1672
1673
John Reck59135872010-11-02 12:39:01 -07001674static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 NoHandleAllocation ha;
1676 ASSERT(args.length() == 2);
1677
1678 CONVERT_CHECKED(JSFunction, fun, args[0]);
1679 CONVERT_CHECKED(Smi, length, args[1]);
1680 fun->shared()->set_length(length->value());
1681 return length;
1682}
1683
1684
John Reck59135872010-11-02 12:39:01 -07001685static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001686 NoHandleAllocation ha;
1687 ASSERT(args.length() == 2);
1688
1689 CONVERT_CHECKED(JSFunction, fun, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01001690 ASSERT(fun->should_have_prototype());
John Reck59135872010-11-02 12:39:01 -07001691 Object* obj;
1692 { MaybeObject* maybe_obj =
1693 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1695 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001696 return args[0]; // return TOS
1697}
1698
1699
John Reck59135872010-11-02 12:39:01 -07001700static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001707}
1708
John Reck59135872010-11-02 12:39:01 -07001709static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
1717
John Reck59135872010-11-02 12:39:01 -07001718static MaybeObject* Runtime_SetCode(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
1722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
1723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
Leon Clarke4515c472010-02-03 11:58:03 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
Leon Clarke4515c472010-02-03 11:58:03 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001733 return Failure::Exception();
1734 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001735 // Since we don't store the source for this we should never
1736 // optimize this.
1737 shared->code()->set_optimizable(false);
1738
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001739 // Set the code, scope info, formal parameter count,
1740 // and the length of the target function.
Iain Merrick75681382010-08-19 15:07:18 +01001741 target->shared()->set_code(shared->code());
Ben Murdochb0fe1622011-05-05 13:52:32 +01001742 target->ReplaceCode(shared->code());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001743 target->shared()->set_scope_info(shared->scope_info());
Leon Clarke4515c472010-02-03 11:58:03 +00001744 target->shared()->set_length(shared->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 target->shared()->set_formal_parameter_count(
Leon Clarke4515c472010-02-03 11:58:03 +00001746 shared->formal_parameter_count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001747 // Set the source code of the target function to undefined.
1748 // SetCode is only used for built-in constructors like String,
1749 // Array, and Object, and some web code
1750 // doesn't like seeing source code for constructors.
1751 target->shared()->set_script(Heap::undefined_value());
1752 // Clear the optimization hints related to the compiled code as these are no
1753 // longer valid when the code is overwritten.
1754 target->shared()->ClearThisPropertyAssignmentsInfo();
1755 context = Handle<Context>(fun->context());
1756
1757 // Make sure we get a fresh copy of the literal vector to avoid
1758 // cross context contamination.
1759 int number_of_literals = fun->NumberOfLiterals();
1760 Handle<FixedArray> literals =
1761 Factory::NewFixedArray(number_of_literals, TENURED);
1762 if (number_of_literals > 0) {
1763 // Insert the object, regexp and array functions in the literals
1764 // array prefix. These are the functions that will be used when
1765 // creating object, regexp and array literals.
1766 literals->set(JSFunction::kLiteralGlobalContextIndex,
1767 context->global_context());
1768 }
Leon Clarke4515c472010-02-03 11:58:03 +00001769 // It's okay to skip the write barrier here because the literals
1770 // are guaranteed to be in old space.
Steve Blocka7e24c12009-10-30 11:49:00 +00001771 target->set_literals(*literals, SKIP_WRITE_BARRIER);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001772 target->set_next_function_link(Heap::undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 }
1774
1775 target->set_context(*context);
1776 return *target;
1777}
1778
1779
John Reck59135872010-11-02 12:39:01 -07001780static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001781 HandleScope scope;
1782 ASSERT(args.length() == 2);
1783 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1784 CONVERT_SMI_CHECKED(num, args[1]);
1785 RUNTIME_ASSERT(num >= 0);
1786 SetExpectedNofProperties(function, num);
1787 return Heap::undefined_value();
1788}
1789
1790
John Reck59135872010-11-02 12:39:01 -07001791MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
Leon Clarkee46be812010-01-19 14:06:41 +00001792 uint32_t code;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001793 if (char_code->ToArrayIndex(&code)) {
Leon Clarkee46be812010-01-19 14:06:41 +00001794 if (code <= 0xffff) {
1795 return Heap::LookupSingleCharacterStringFromCode(code);
1796 }
1797 }
1798 return Heap::empty_string();
1799}
1800
1801
John Reck59135872010-11-02 12:39:01 -07001802static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001803 NoHandleAllocation ha;
1804 ASSERT(args.length() == 2);
1805
1806 CONVERT_CHECKED(String, subject, args[0]);
1807 Object* index = args[1];
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001808 RUNTIME_ASSERT(index->IsNumber());
Steve Blocka7e24c12009-10-30 11:49:00 +00001809
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001810 uint32_t i = 0;
1811 if (index->IsSmi()) {
1812 int value = Smi::cast(index)->value();
1813 if (value < 0) return Heap::nan_value();
1814 i = value;
1815 } else {
1816 ASSERT(index->IsHeapNumber());
1817 double value = HeapNumber::cast(index)->value();
1818 i = static_cast<uint32_t>(DoubleToInteger(value));
Leon Clarkee46be812010-01-19 14:06:41 +00001819 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001820
1821 // Flatten the string. If someone wants to get a char at an index
1822 // in a cons string, it is likely that more indices will be
1823 // accessed.
John Reck59135872010-11-02 12:39:01 -07001824 Object* flat;
1825 { MaybeObject* maybe_flat = subject->TryFlatten();
1826 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1827 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001828 subject = String::cast(flat);
1829
1830 if (i >= static_cast<uint32_t>(subject->length())) {
1831 return Heap::nan_value();
1832 }
1833
1834 return Smi::FromInt(subject->Get(i));
Leon Clarkee46be812010-01-19 14:06:41 +00001835}
1836
1837
John Reck59135872010-11-02 12:39:01 -07001838static MaybeObject* Runtime_CharFromCode(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 NoHandleAllocation ha;
1840 ASSERT(args.length() == 1);
Leon Clarkee46be812010-01-19 14:06:41 +00001841 return CharFromCode(args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00001842}
1843
Steve Block6ded16b2010-05-10 14:33:55 +01001844
1845class FixedArrayBuilder {
1846 public:
1847 explicit FixedArrayBuilder(int initial_capacity)
1848 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1849 length_(0) {
1850 // Require a non-zero initial size. Ensures that doubling the size to
1851 // extend the array will work.
1852 ASSERT(initial_capacity > 0);
1853 }
1854
1855 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1856 : array_(backing_store),
1857 length_(0) {
1858 // Require a non-zero initial size. Ensures that doubling the size to
1859 // extend the array will work.
1860 ASSERT(backing_store->length() > 0);
1861 }
1862
1863 bool HasCapacity(int elements) {
1864 int length = array_->length();
1865 int required_length = length_ + elements;
1866 return (length >= required_length);
1867 }
1868
1869 void EnsureCapacity(int elements) {
1870 int length = array_->length();
1871 int required_length = length_ + elements;
1872 if (length < required_length) {
1873 int new_length = length;
1874 do {
1875 new_length *= 2;
1876 } while (new_length < required_length);
1877 Handle<FixedArray> extended_array =
1878 Factory::NewFixedArrayWithHoles(new_length);
1879 array_->CopyTo(0, *extended_array, 0, length_);
1880 array_ = extended_array;
1881 }
1882 }
1883
1884 void Add(Object* value) {
1885 ASSERT(length_ < capacity());
1886 array_->set(length_, value);
1887 length_++;
1888 }
1889
1890 void Add(Smi* value) {
1891 ASSERT(length_ < capacity());
1892 array_->set(length_, value);
1893 length_++;
1894 }
1895
1896 Handle<FixedArray> array() {
1897 return array_;
1898 }
1899
1900 int length() {
1901 return length_;
1902 }
1903
1904 int capacity() {
1905 return array_->length();
1906 }
1907
1908 Handle<JSArray> ToJSArray() {
1909 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1910 result_array->set_length(Smi::FromInt(length_));
1911 return result_array;
1912 }
1913
1914 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1915 target_array->set_elements(*array_);
1916 target_array->set_length(Smi::FromInt(length_));
1917 return target_array;
1918 }
1919
1920 private:
1921 Handle<FixedArray> array_;
1922 int length_;
1923};
1924
1925
Steve Blocka7e24c12009-10-30 11:49:00 +00001926// Forward declarations.
Steve Block6ded16b2010-05-10 14:33:55 +01001927const int kStringBuilderConcatHelperLengthBits = 11;
1928const int kStringBuilderConcatHelperPositionBits = 19;
Steve Blocka7e24c12009-10-30 11:49:00 +00001929
1930template <typename schar>
1931static inline void StringBuilderConcatHelper(String*,
1932 schar*,
1933 FixedArray*,
1934 int);
1935
Steve Block6ded16b2010-05-10 14:33:55 +01001936typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1937 StringBuilderSubstringLength;
1938typedef BitField<int,
1939 kStringBuilderConcatHelperLengthBits,
1940 kStringBuilderConcatHelperPositionBits>
1941 StringBuilderSubstringPosition;
1942
Steve Blocka7e24c12009-10-30 11:49:00 +00001943
1944class ReplacementStringBuilder {
1945 public:
1946 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
Steve Block6ded16b2010-05-10 14:33:55 +01001947 : array_builder_(estimated_part_count),
1948 subject_(subject),
Steve Blocka7e24c12009-10-30 11:49:00 +00001949 character_count_(0),
1950 is_ascii_(subject->IsAsciiRepresentation()) {
1951 // Require a non-zero initial size. Ensures that doubling the size to
1952 // extend the array will work.
1953 ASSERT(estimated_part_count > 0);
1954 }
1955
Steve Block6ded16b2010-05-10 14:33:55 +01001956 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1957 int from,
1958 int to) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001959 ASSERT(from >= 0);
1960 int length = to - from;
1961 ASSERT(length > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 if (StringBuilderSubstringLength::is_valid(length) &&
1963 StringBuilderSubstringPosition::is_valid(from)) {
1964 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1965 StringBuilderSubstringPosition::encode(from);
Steve Block6ded16b2010-05-10 14:33:55 +01001966 builder->Add(Smi::FromInt(encoded_slice));
Steve Blocka7e24c12009-10-30 11:49:00 +00001967 } else {
Steve Blockd0582a62009-12-15 09:54:21 +00001968 // Otherwise encode as two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01001969 builder->Add(Smi::FromInt(-length));
1970 builder->Add(Smi::FromInt(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00001971 }
Steve Block6ded16b2010-05-10 14:33:55 +01001972 }
1973
1974
1975 void EnsureCapacity(int elements) {
1976 array_builder_.EnsureCapacity(elements);
1977 }
1978
1979
1980 void AddSubjectSlice(int from, int to) {
1981 AddSubjectSlice(&array_builder_, from, to);
1982 IncrementCharacterCount(to - from);
Steve Blocka7e24c12009-10-30 11:49:00 +00001983 }
1984
1985
1986 void AddString(Handle<String> string) {
1987 int length = string->length();
1988 ASSERT(length > 0);
1989 AddElement(*string);
1990 if (!string->IsAsciiRepresentation()) {
1991 is_ascii_ = false;
1992 }
1993 IncrementCharacterCount(length);
1994 }
1995
1996
1997 Handle<String> ToString() {
Steve Block6ded16b2010-05-10 14:33:55 +01001998 if (array_builder_.length() == 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001999 return Factory::empty_string();
2000 }
2001
2002 Handle<String> joined_string;
2003 if (is_ascii_) {
2004 joined_string = NewRawAsciiString(character_count_);
2005 AssertNoAllocation no_alloc;
2006 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2007 char* char_buffer = seq->GetChars();
2008 StringBuilderConcatHelper(*subject_,
2009 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002010 *array_builder_.array(),
2011 array_builder_.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 } else {
2013 // Non-ASCII.
2014 joined_string = NewRawTwoByteString(character_count_);
2015 AssertNoAllocation no_alloc;
2016 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2017 uc16* char_buffer = seq->GetChars();
2018 StringBuilderConcatHelper(*subject_,
2019 char_buffer,
Steve Block6ded16b2010-05-10 14:33:55 +01002020 *array_builder_.array(),
2021 array_builder_.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00002022 }
2023 return joined_string;
2024 }
2025
2026
2027 void IncrementCharacterCount(int by) {
Leon Clarkee46be812010-01-19 14:06:41 +00002028 if (character_count_ > String::kMaxLength - by) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002029 V8::FatalProcessOutOfMemory("String.replace result too large.");
2030 }
2031 character_count_ += by;
2032 }
2033
Steve Block6ded16b2010-05-10 14:33:55 +01002034 Handle<JSArray> GetParts() {
Ben Murdochb0fe1622011-05-05 13:52:32 +01002035 return array_builder_.ToJSArray();
Steve Block6ded16b2010-05-10 14:33:55 +01002036 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002037
Steve Block6ded16b2010-05-10 14:33:55 +01002038 private:
Steve Blocka7e24c12009-10-30 11:49:00 +00002039 Handle<String> NewRawAsciiString(int size) {
2040 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2041 }
2042
2043
2044 Handle<String> NewRawTwoByteString(int size) {
2045 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2046 }
2047
2048
2049 void AddElement(Object* element) {
2050 ASSERT(element->IsSmi() || element->IsString());
Steve Block6ded16b2010-05-10 14:33:55 +01002051 ASSERT(array_builder_.capacity() > array_builder_.length());
2052 array_builder_.Add(element);
Steve Blocka7e24c12009-10-30 11:49:00 +00002053 }
2054
Steve Block6ded16b2010-05-10 14:33:55 +01002055 FixedArrayBuilder array_builder_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002056 Handle<String> subject_;
Steve Blocka7e24c12009-10-30 11:49:00 +00002057 int character_count_;
2058 bool is_ascii_;
2059};
2060
2061
2062class CompiledReplacement {
2063 public:
2064 CompiledReplacement()
2065 : parts_(1), replacement_substrings_(0) {}
2066
2067 void Compile(Handle<String> replacement,
2068 int capture_count,
2069 int subject_length);
2070
2071 void Apply(ReplacementStringBuilder* builder,
2072 int match_from,
2073 int match_to,
2074 Handle<JSArray> last_match_info);
2075
2076 // Number of distinct parts of the replacement pattern.
2077 int parts() {
2078 return parts_.length();
2079 }
2080 private:
2081 enum PartType {
2082 SUBJECT_PREFIX = 1,
2083 SUBJECT_SUFFIX,
2084 SUBJECT_CAPTURE,
2085 REPLACEMENT_SUBSTRING,
2086 REPLACEMENT_STRING,
2087
2088 NUMBER_OF_PART_TYPES
2089 };
2090
2091 struct ReplacementPart {
2092 static inline ReplacementPart SubjectMatch() {
2093 return ReplacementPart(SUBJECT_CAPTURE, 0);
2094 }
2095 static inline ReplacementPart SubjectCapture(int capture_index) {
2096 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2097 }
2098 static inline ReplacementPart SubjectPrefix() {
2099 return ReplacementPart(SUBJECT_PREFIX, 0);
2100 }
2101 static inline ReplacementPart SubjectSuffix(int subject_length) {
2102 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2103 }
2104 static inline ReplacementPart ReplacementString() {
2105 return ReplacementPart(REPLACEMENT_STRING, 0);
2106 }
2107 static inline ReplacementPart ReplacementSubString(int from, int to) {
2108 ASSERT(from >= 0);
2109 ASSERT(to > from);
2110 return ReplacementPart(-from, to);
2111 }
2112
2113 // If tag <= 0 then it is the negation of a start index of a substring of
2114 // the replacement pattern, otherwise it's a value from PartType.
2115 ReplacementPart(int tag, int data)
2116 : tag(tag), data(data) {
2117 // Must be non-positive or a PartType value.
2118 ASSERT(tag < NUMBER_OF_PART_TYPES);
2119 }
2120 // Either a value of PartType or a non-positive number that is
2121 // the negation of an index into the replacement string.
2122 int tag;
2123 // The data value's interpretation depends on the value of tag:
2124 // tag == SUBJECT_PREFIX ||
2125 // tag == SUBJECT_SUFFIX: data is unused.
2126 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2127 // tag == REPLACEMENT_SUBSTRING ||
2128 // tag == REPLACEMENT_STRING: data is index into array of substrings
2129 // of the replacement string.
2130 // tag <= 0: Temporary representation of the substring of the replacement
2131 // string ranging over -tag .. data.
2132 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2133 // substring objects.
2134 int data;
2135 };
2136
2137 template<typename Char>
2138 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2139 Vector<Char> characters,
2140 int capture_count,
2141 int subject_length) {
2142 int length = characters.length();
2143 int last = 0;
2144 for (int i = 0; i < length; i++) {
2145 Char c = characters[i];
2146 if (c == '$') {
2147 int next_index = i + 1;
2148 if (next_index == length) { // No next character!
2149 break;
2150 }
2151 Char c2 = characters[next_index];
2152 switch (c2) {
2153 case '$':
2154 if (i > last) {
2155 // There is a substring before. Include the first "$".
2156 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2157 last = next_index + 1; // Continue after the second "$".
2158 } else {
2159 // Let the next substring start with the second "$".
2160 last = next_index;
2161 }
2162 i = next_index;
2163 break;
2164 case '`':
2165 if (i > last) {
2166 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2167 }
2168 parts->Add(ReplacementPart::SubjectPrefix());
2169 i = next_index;
2170 last = i + 1;
2171 break;
2172 case '\'':
2173 if (i > last) {
2174 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2175 }
2176 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2177 i = next_index;
2178 last = i + 1;
2179 break;
2180 case '&':
2181 if (i > last) {
2182 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2183 }
2184 parts->Add(ReplacementPart::SubjectMatch());
2185 i = next_index;
2186 last = i + 1;
2187 break;
2188 case '0':
2189 case '1':
2190 case '2':
2191 case '3':
2192 case '4':
2193 case '5':
2194 case '6':
2195 case '7':
2196 case '8':
2197 case '9': {
2198 int capture_ref = c2 - '0';
2199 if (capture_ref > capture_count) {
2200 i = next_index;
2201 continue;
2202 }
2203 int second_digit_index = next_index + 1;
2204 if (second_digit_index < length) {
2205 // Peek ahead to see if we have two digits.
2206 Char c3 = characters[second_digit_index];
2207 if ('0' <= c3 && c3 <= '9') { // Double digits.
2208 int double_digit_ref = capture_ref * 10 + c3 - '0';
2209 if (double_digit_ref <= capture_count) {
2210 next_index = second_digit_index;
2211 capture_ref = double_digit_ref;
2212 }
2213 }
2214 }
2215 if (capture_ref > 0) {
2216 if (i > last) {
2217 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2218 }
2219 ASSERT(capture_ref <= capture_count);
2220 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2221 last = next_index + 1;
2222 }
2223 i = next_index;
2224 break;
2225 }
2226 default:
2227 i = next_index;
2228 break;
2229 }
2230 }
2231 }
2232 if (length > last) {
2233 if (last == 0) {
2234 parts->Add(ReplacementPart::ReplacementString());
2235 } else {
2236 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2237 }
2238 }
2239 }
2240
2241 ZoneList<ReplacementPart> parts_;
2242 ZoneList<Handle<String> > replacement_substrings_;
2243};
2244
2245
2246void CompiledReplacement::Compile(Handle<String> replacement,
2247 int capture_count,
2248 int subject_length) {
2249 ASSERT(replacement->IsFlat());
2250 if (replacement->IsAsciiRepresentation()) {
2251 AssertNoAllocation no_alloc;
2252 ParseReplacementPattern(&parts_,
2253 replacement->ToAsciiVector(),
2254 capture_count,
2255 subject_length);
2256 } else {
2257 ASSERT(replacement->IsTwoByteRepresentation());
2258 AssertNoAllocation no_alloc;
2259
2260 ParseReplacementPattern(&parts_,
2261 replacement->ToUC16Vector(),
2262 capture_count,
2263 subject_length);
2264 }
Steve Blockd0582a62009-12-15 09:54:21 +00002265 // Find substrings of replacement string and create them as String objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 int substring_index = 0;
2267 for (int i = 0, n = parts_.length(); i < n; i++) {
2268 int tag = parts_[i].tag;
2269 if (tag <= 0) { // A replacement string slice.
2270 int from = -tag;
2271 int to = parts_[i].data;
Steve Blockd0582a62009-12-15 09:54:21 +00002272 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
Steve Blocka7e24c12009-10-30 11:49:00 +00002273 parts_[i].tag = REPLACEMENT_SUBSTRING;
2274 parts_[i].data = substring_index;
2275 substring_index++;
2276 } else if (tag == REPLACEMENT_STRING) {
2277 replacement_substrings_.Add(replacement);
2278 parts_[i].data = substring_index;
2279 substring_index++;
2280 }
2281 }
2282}
2283
2284
2285void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2286 int match_from,
2287 int match_to,
2288 Handle<JSArray> last_match_info) {
2289 for (int i = 0, n = parts_.length(); i < n; i++) {
2290 ReplacementPart part = parts_[i];
2291 switch (part.tag) {
2292 case SUBJECT_PREFIX:
2293 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2294 break;
2295 case SUBJECT_SUFFIX: {
2296 int subject_length = part.data;
2297 if (match_to < subject_length) {
2298 builder->AddSubjectSlice(match_to, subject_length);
2299 }
2300 break;
2301 }
2302 case SUBJECT_CAPTURE: {
2303 int capture = part.data;
2304 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2305 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2306 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2307 if (from >= 0 && to > from) {
2308 builder->AddSubjectSlice(from, to);
2309 }
2310 break;
2311 }
2312 case REPLACEMENT_SUBSTRING:
2313 case REPLACEMENT_STRING:
2314 builder->AddString(replacement_substrings_[part.data]);
2315 break;
2316 default:
2317 UNREACHABLE();
2318 }
2319 }
2320}
2321
2322
2323
John Reck59135872010-11-02 12:39:01 -07002324MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2325 String* subject,
2326 JSRegExp* regexp,
2327 String* replacement,
2328 JSArray* last_match_info) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002329 ASSERT(subject->IsFlat());
2330 ASSERT(replacement->IsFlat());
2331
2332 HandleScope handles;
2333
2334 int length = subject->length();
2335 Handle<String> subject_handle(subject);
2336 Handle<JSRegExp> regexp_handle(regexp);
2337 Handle<String> replacement_handle(replacement);
2338 Handle<JSArray> last_match_info_handle(last_match_info);
2339 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2340 subject_handle,
2341 0,
2342 last_match_info_handle);
2343 if (match.is_null()) {
2344 return Failure::Exception();
2345 }
2346 if (match->IsNull()) {
2347 return *subject_handle;
2348 }
2349
2350 int capture_count = regexp_handle->CaptureCount();
2351
2352 // CompiledReplacement uses zone allocation.
2353 CompilationZoneScope zone(DELETE_ON_EXIT);
2354 CompiledReplacement compiled_replacement;
2355 compiled_replacement.Compile(replacement_handle,
2356 capture_count,
2357 length);
2358
2359 bool is_global = regexp_handle->GetFlags().is_global();
2360
2361 // Guessing the number of parts that the final result string is built
2362 // from. Global regexps can match any number of times, so we guess
2363 // conservatively.
2364 int expected_parts =
2365 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2366 ReplacementStringBuilder builder(subject_handle, expected_parts);
2367
2368 // Index of end of last match.
2369 int prev = 0;
2370
Steve Blockd0582a62009-12-15 09:54:21 +00002371 // Number of parts added by compiled replacement plus preceeding
2372 // string and possibly suffix after last match. It is possible for
2373 // all components to use two elements when encoded as two smis.
2374 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002375 bool matched = true;
2376 do {
2377 ASSERT(last_match_info_handle->HasFastElements());
2378 // Increase the capacity of the builder before entering local handle-scope,
2379 // so its internal buffer can safely allocate a new handle if it grows.
2380 builder.EnsureCapacity(parts_added_per_loop);
2381
2382 HandleScope loop_scope;
2383 int start, end;
2384 {
2385 AssertNoAllocation match_info_array_is_not_in_a_handle;
2386 FixedArray* match_info_array =
2387 FixedArray::cast(last_match_info_handle->elements());
2388
2389 ASSERT_EQ(capture_count * 2 + 2,
2390 RegExpImpl::GetLastCaptureCount(match_info_array));
2391 start = RegExpImpl::GetCapture(match_info_array, 0);
2392 end = RegExpImpl::GetCapture(match_info_array, 1);
2393 }
2394
2395 if (prev < start) {
2396 builder.AddSubjectSlice(prev, start);
2397 }
2398 compiled_replacement.Apply(&builder,
2399 start,
2400 end,
2401 last_match_info_handle);
2402 prev = end;
2403
2404 // Only continue checking for global regexps.
2405 if (!is_global) break;
2406
2407 // Continue from where the match ended, unless it was an empty match.
2408 int next = end;
2409 if (start == end) {
2410 next = end + 1;
2411 if (next > length) break;
2412 }
2413
2414 match = RegExpImpl::Exec(regexp_handle,
2415 subject_handle,
2416 next,
2417 last_match_info_handle);
2418 if (match.is_null()) {
2419 return Failure::Exception();
2420 }
2421 matched = !match->IsNull();
2422 } while (matched);
2423
2424 if (prev < length) {
2425 builder.AddSubjectSlice(prev, length);
2426 }
2427
2428 return *(builder.ToString());
2429}
2430
2431
Leon Clarkeac952652010-07-15 11:15:24 +01002432template <typename ResultSeqString>
John Reck59135872010-11-02 12:39:01 -07002433MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2434 String* subject,
2435 JSRegExp* regexp,
2436 JSArray* last_match_info) {
Leon Clarkeac952652010-07-15 11:15:24 +01002437 ASSERT(subject->IsFlat());
2438
2439 HandleScope handles;
2440
2441 Handle<String> subject_handle(subject);
2442 Handle<JSRegExp> regexp_handle(regexp);
2443 Handle<JSArray> last_match_info_handle(last_match_info);
2444 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2445 subject_handle,
2446 0,
2447 last_match_info_handle);
2448 if (match.is_null()) return Failure::Exception();
2449 if (match->IsNull()) return *subject_handle;
2450
2451 ASSERT(last_match_info_handle->HasFastElements());
2452
2453 HandleScope loop_scope;
2454 int start, end;
2455 {
2456 AssertNoAllocation match_info_array_is_not_in_a_handle;
2457 FixedArray* match_info_array =
2458 FixedArray::cast(last_match_info_handle->elements());
2459
2460 start = RegExpImpl::GetCapture(match_info_array, 0);
2461 end = RegExpImpl::GetCapture(match_info_array, 1);
2462 }
2463
2464 int length = subject->length();
2465 int new_length = length - (end - start);
2466 if (new_length == 0) {
2467 return Heap::empty_string();
2468 }
2469 Handle<ResultSeqString> answer;
2470 if (ResultSeqString::kHasAsciiEncoding) {
2471 answer =
2472 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2473 } else {
2474 answer =
2475 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2476 }
2477
2478 // If the regexp isn't global, only match once.
2479 if (!regexp_handle->GetFlags().is_global()) {
2480 if (start > 0) {
2481 String::WriteToFlat(*subject_handle,
2482 answer->GetChars(),
2483 0,
2484 start);
2485 }
2486 if (end < length) {
2487 String::WriteToFlat(*subject_handle,
2488 answer->GetChars() + start,
2489 end,
2490 length);
2491 }
2492 return *answer;
2493 }
2494
2495 int prev = 0; // Index of end of last match.
2496 int next = 0; // Start of next search (prev unless last match was empty).
2497 int position = 0;
2498
2499 do {
2500 if (prev < start) {
2501 // Add substring subject[prev;start] to answer string.
2502 String::WriteToFlat(*subject_handle,
2503 answer->GetChars() + position,
2504 prev,
2505 start);
2506 position += start - prev;
2507 }
2508 prev = end;
2509 next = end;
2510 // Continue from where the match ended, unless it was an empty match.
2511 if (start == end) {
2512 next++;
2513 if (next > length) break;
2514 }
2515 match = RegExpImpl::Exec(regexp_handle,
2516 subject_handle,
2517 next,
2518 last_match_info_handle);
2519 if (match.is_null()) return Failure::Exception();
2520 if (match->IsNull()) break;
2521
2522 ASSERT(last_match_info_handle->HasFastElements());
2523 HandleScope loop_scope;
2524 {
2525 AssertNoAllocation match_info_array_is_not_in_a_handle;
2526 FixedArray* match_info_array =
2527 FixedArray::cast(last_match_info_handle->elements());
2528 start = RegExpImpl::GetCapture(match_info_array, 0);
2529 end = RegExpImpl::GetCapture(match_info_array, 1);
2530 }
2531 } while (true);
2532
2533 if (prev < length) {
2534 // Add substring subject[prev;length] to answer string.
2535 String::WriteToFlat(*subject_handle,
2536 answer->GetChars() + position,
2537 prev,
2538 length);
2539 position += length - prev;
2540 }
2541
2542 if (position == 0) {
2543 return Heap::empty_string();
2544 }
2545
2546 // Shorten string and fill
2547 int string_size = ResultSeqString::SizeFor(position);
2548 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2549 int delta = allocated_string_size - string_size;
2550
2551 answer->set_length(position);
2552 if (delta == 0) return *answer;
2553
2554 Address end_of_string = answer->address() + string_size;
2555 Heap::CreateFillerObjectAt(end_of_string, delta);
2556
2557 return *answer;
2558}
2559
2560
John Reck59135872010-11-02 12:39:01 -07002561static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002562 ASSERT(args.length() == 4);
2563
2564 CONVERT_CHECKED(String, subject, args[0]);
2565 if (!subject->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07002566 Object* flat_subject;
2567 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2568 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2569 return maybe_flat_subject;
2570 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002571 }
2572 subject = String::cast(flat_subject);
2573 }
2574
2575 CONVERT_CHECKED(String, replacement, args[2]);
2576 if (!replacement->IsFlat()) {
John Reck59135872010-11-02 12:39:01 -07002577 Object* flat_replacement;
2578 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2579 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2580 return maybe_flat_replacement;
2581 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002582 }
2583 replacement = String::cast(flat_replacement);
2584 }
2585
2586 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2587 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2588
2589 ASSERT(last_match_info->HasFastElements());
2590
Leon Clarkeac952652010-07-15 11:15:24 +01002591 if (replacement->length() == 0) {
2592 if (subject->HasOnlyAsciiChars()) {
2593 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2594 subject, regexp, last_match_info);
2595 } else {
2596 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2597 subject, regexp, last_match_info);
2598 }
2599 }
2600
Steve Blocka7e24c12009-10-30 11:49:00 +00002601 return StringReplaceRegExpWithString(subject,
2602 regexp,
2603 replacement,
2604 last_match_info);
2605}
2606
2607
Steve Blocka7e24c12009-10-30 11:49:00 +00002608// Perform string match of pattern on subject, starting at start index.
2609// Caller must ensure that 0 <= start_index <= sub->length(),
Ben Murdochb0fe1622011-05-05 13:52:32 +01002610// and should check that pat->length() + start_index <= sub->length().
Steve Blocka7e24c12009-10-30 11:49:00 +00002611int Runtime::StringMatch(Handle<String> sub,
2612 Handle<String> pat,
2613 int start_index) {
2614 ASSERT(0 <= start_index);
2615 ASSERT(start_index <= sub->length());
2616
2617 int pattern_length = pat->length();
2618 if (pattern_length == 0) return start_index;
2619
2620 int subject_length = sub->length();
2621 if (start_index + pattern_length > subject_length) return -1;
2622
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002623 if (!sub->IsFlat()) FlattenString(sub);
2624 if (!pat->IsFlat()) FlattenString(pat);
Steve Blocka7e24c12009-10-30 11:49:00 +00002625
2626 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
Steve Block8defd9f2010-07-08 12:39:36 +01002627 // Extract flattened substrings of cons strings before determining asciiness.
2628 String* seq_sub = *sub;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002629 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
Steve Block8defd9f2010-07-08 12:39:36 +01002630 String* seq_pat = *pat;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002631 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
Steve Block8defd9f2010-07-08 12:39:36 +01002632
Steve Blocka7e24c12009-10-30 11:49:00 +00002633 // dispatch on type of strings
Steve Block8defd9f2010-07-08 12:39:36 +01002634 if (seq_pat->IsAsciiRepresentation()) {
2635 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2636 if (seq_sub->IsAsciiRepresentation()) {
Ben Murdochf87a2032010-10-22 12:50:53 +01002637 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002638 }
Ben Murdochf87a2032010-10-22 12:50:53 +01002639 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002640 }
Steve Block8defd9f2010-07-08 12:39:36 +01002641 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2642 if (seq_sub->IsAsciiRepresentation()) {
Ben Murdochf87a2032010-10-22 12:50:53 +01002643 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002644 }
Ben Murdochf87a2032010-10-22 12:50:53 +01002645 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00002646}
2647
2648
John Reck59135872010-11-02 12:39:01 -07002649static MaybeObject* Runtime_StringIndexOf(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002650 HandleScope scope; // create a new handle scope
2651 ASSERT(args.length() == 3);
2652
2653 CONVERT_ARG_CHECKED(String, sub, 0);
2654 CONVERT_ARG_CHECKED(String, pat, 1);
2655
2656 Object* index = args[2];
2657 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002658 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002659
2660 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
2661 int position = Runtime::StringMatch(sub, pat, start_index);
2662 return Smi::FromInt(position);
2663}
2664
2665
Andrei Popescu402d9372010-02-26 13:31:12 +00002666template <typename schar, typename pchar>
Steve Block59151502010-09-22 15:07:15 +01002667static int StringMatchBackwards(Vector<const schar> subject,
2668 Vector<const pchar> pattern,
Andrei Popescu402d9372010-02-26 13:31:12 +00002669 int idx) {
Steve Block59151502010-09-22 15:07:15 +01002670 int pattern_length = pattern.length();
2671 ASSERT(pattern_length >= 1);
2672 ASSERT(idx + pattern_length <= subject.length());
Andrei Popescu402d9372010-02-26 13:31:12 +00002673
2674 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
Steve Block59151502010-09-22 15:07:15 +01002675 for (int i = 0; i < pattern_length; i++) {
2676 uc16 c = pattern[i];
Andrei Popescu402d9372010-02-26 13:31:12 +00002677 if (c > String::kMaxAsciiCharCode) {
2678 return -1;
2679 }
2680 }
2681 }
2682
Steve Block59151502010-09-22 15:07:15 +01002683 pchar pattern_first_char = pattern[0];
Andrei Popescu402d9372010-02-26 13:31:12 +00002684 for (int i = idx; i >= 0; i--) {
Steve Block59151502010-09-22 15:07:15 +01002685 if (subject[i] != pattern_first_char) continue;
Andrei Popescu402d9372010-02-26 13:31:12 +00002686 int j = 1;
Steve Block59151502010-09-22 15:07:15 +01002687 while (j < pattern_length) {
2688 if (pattern[j] != subject[i+j]) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002689 break;
2690 }
2691 j++;
2692 }
Steve Block59151502010-09-22 15:07:15 +01002693 if (j == pattern_length) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002694 return i;
2695 }
2696 }
2697 return -1;
2698}
2699
John Reck59135872010-11-02 12:39:01 -07002700static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00002701 HandleScope scope; // create a new handle scope
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 ASSERT(args.length() == 3);
2703
Andrei Popescu402d9372010-02-26 13:31:12 +00002704 CONVERT_ARG_CHECKED(String, sub, 0);
2705 CONVERT_ARG_CHECKED(String, pat, 1);
2706
Steve Blocka7e24c12009-10-30 11:49:00 +00002707 Object* index = args[2];
Steve Blocka7e24c12009-10-30 11:49:00 +00002708 uint32_t start_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002709 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002710
Andrei Popescu402d9372010-02-26 13:31:12 +00002711 uint32_t pat_length = pat->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 uint32_t sub_length = sub->length();
2713
Andrei Popescu402d9372010-02-26 13:31:12 +00002714 if (start_index + pat_length > sub_length) {
2715 start_index = sub_length - pat_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00002716 }
2717
Andrei Popescu402d9372010-02-26 13:31:12 +00002718 if (pat_length == 0) {
2719 return Smi::FromInt(start_index);
2720 }
2721
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002722 if (!sub->IsFlat()) FlattenString(sub);
2723 if (!pat->IsFlat()) FlattenString(pat);
Andrei Popescu402d9372010-02-26 13:31:12 +00002724
2725 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2726
2727 int position = -1;
2728
2729 if (pat->IsAsciiRepresentation()) {
2730 Vector<const char> pat_vector = pat->ToAsciiVector();
2731 if (sub->IsAsciiRepresentation()) {
2732 position = StringMatchBackwards(sub->ToAsciiVector(),
2733 pat_vector,
2734 start_index);
2735 } else {
2736 position = StringMatchBackwards(sub->ToUC16Vector(),
2737 pat_vector,
2738 start_index);
2739 }
2740 } else {
2741 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2742 if (sub->IsAsciiRepresentation()) {
2743 position = StringMatchBackwards(sub->ToAsciiVector(),
2744 pat_vector,
2745 start_index);
2746 } else {
2747 position = StringMatchBackwards(sub->ToUC16Vector(),
2748 pat_vector,
2749 start_index);
2750 }
2751 }
2752
2753 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +00002754}
2755
2756
John Reck59135872010-11-02 12:39:01 -07002757static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002758 NoHandleAllocation ha;
2759 ASSERT(args.length() == 2);
2760
2761 CONVERT_CHECKED(String, str1, args[0]);
2762 CONVERT_CHECKED(String, str2, args[1]);
2763
2764 if (str1 == str2) return Smi::FromInt(0); // Equal.
2765 int str1_length = str1->length();
2766 int str2_length = str2->length();
2767
2768 // Decide trivial cases without flattening.
2769 if (str1_length == 0) {
2770 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2771 return Smi::FromInt(-str2_length);
2772 } else {
2773 if (str2_length == 0) return Smi::FromInt(str1_length);
2774 }
2775
2776 int end = str1_length < str2_length ? str1_length : str2_length;
2777
2778 // No need to flatten if we are going to find the answer on the first
2779 // character. At this point we know there is at least one character
2780 // in each string, due to the trivial case handling above.
2781 int d = str1->Get(0) - str2->Get(0);
2782 if (d != 0) return Smi::FromInt(d);
2783
Steve Block6ded16b2010-05-10 14:33:55 +01002784 str1->TryFlatten();
2785 str2->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00002786
2787 static StringInputBuffer buf1;
2788 static StringInputBuffer buf2;
2789
2790 buf1.Reset(str1);
2791 buf2.Reset(str2);
2792
2793 for (int i = 0; i < end; i++) {
2794 uint16_t char1 = buf1.GetNext();
2795 uint16_t char2 = buf2.GetNext();
2796 if (char1 != char2) return Smi::FromInt(char1 - char2);
2797 }
2798
2799 return Smi::FromInt(str1_length - str2_length);
2800}
2801
2802
John Reck59135872010-11-02 12:39:01 -07002803static MaybeObject* Runtime_SubString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002804 NoHandleAllocation ha;
2805 ASSERT(args.length() == 3);
2806
2807 CONVERT_CHECKED(String, value, args[0]);
Steve Blockd0582a62009-12-15 09:54:21 +00002808 Object* from = args[1];
2809 Object* to = args[2];
2810 int start, end;
2811 // We have a fast integer-only case here to avoid a conversion to double in
2812 // the common case where from and to are Smis.
2813 if (from->IsSmi() && to->IsSmi()) {
2814 start = Smi::cast(from)->value();
2815 end = Smi::cast(to)->value();
2816 } else {
2817 CONVERT_DOUBLE_CHECKED(from_number, from);
2818 CONVERT_DOUBLE_CHECKED(to_number, to);
2819 start = FastD2I(from_number);
2820 end = FastD2I(to_number);
2821 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002822 RUNTIME_ASSERT(end >= start);
2823 RUNTIME_ASSERT(start >= 0);
2824 RUNTIME_ASSERT(end <= value->length());
Leon Clarkee46be812010-01-19 14:06:41 +00002825 Counters::sub_string_runtime.Increment();
Steve Blockd0582a62009-12-15 09:54:21 +00002826 return value->SubString(start, end);
Steve Blocka7e24c12009-10-30 11:49:00 +00002827}
2828
2829
John Reck59135872010-11-02 12:39:01 -07002830static MaybeObject* Runtime_StringMatch(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002831 ASSERT_EQ(3, args.length());
2832
2833 CONVERT_ARG_CHECKED(String, subject, 0);
2834 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2835 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2836 HandleScope handles;
2837
2838 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2839
2840 if (match.is_null()) {
2841 return Failure::Exception();
2842 }
2843 if (match->IsNull()) {
2844 return Heap::null_value();
2845 }
2846 int length = subject->length();
2847
2848 CompilationZoneScope zone_space(DELETE_ON_EXIT);
2849 ZoneList<int> offsets(8);
2850 do {
2851 int start;
2852 int end;
2853 {
2854 AssertNoAllocation no_alloc;
2855 FixedArray* elements = FixedArray::cast(regexp_info->elements());
2856 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2857 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2858 }
2859 offsets.Add(start);
2860 offsets.Add(end);
2861 int index = start < end ? end : end + 1;
2862 if (index > length) break;
2863 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2864 if (match.is_null()) {
2865 return Failure::Exception();
2866 }
2867 } while (!match->IsNull());
2868 int matches = offsets.length() / 2;
2869 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2870 for (int i = 0; i < matches ; i++) {
2871 int from = offsets.at(i * 2);
2872 int to = offsets.at(i * 2 + 1);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002873 Handle<String> match = Factory::NewSubString(subject, from, to);
2874 elements->set(i, *match);
Steve Blocka7e24c12009-10-30 11:49:00 +00002875 }
2876 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2877 result->set_length(Smi::FromInt(matches));
2878 return *result;
2879}
2880
2881
Steve Block6ded16b2010-05-10 14:33:55 +01002882// Two smis before and after the match, for very long strings.
2883const int kMaxBuilderEntriesPerRegExpMatch = 5;
2884
2885
2886static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2887 Handle<JSArray> last_match_info,
2888 int match_start,
2889 int match_end) {
2890 // Fill last_match_info with a single capture.
2891 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2892 AssertNoAllocation no_gc;
2893 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2894 RegExpImpl::SetLastCaptureCount(elements, 2);
2895 RegExpImpl::SetLastInput(elements, *subject);
2896 RegExpImpl::SetLastSubject(elements, *subject);
2897 RegExpImpl::SetCapture(elements, 0, match_start);
2898 RegExpImpl::SetCapture(elements, 1, match_end);
2899}
2900
2901
Ben Murdochf87a2032010-10-22 12:50:53 +01002902template <typename SubjectChar, typename PatternChar>
2903static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2904 Vector<const PatternChar> pattern,
2905 String* pattern_string,
Steve Block6ded16b2010-05-10 14:33:55 +01002906 FixedArrayBuilder* builder,
2907 int* match_pos) {
2908 int pos = *match_pos;
2909 int subject_length = subject.length();
Ben Murdochf87a2032010-10-22 12:50:53 +01002910 int pattern_length = pattern.length();
Steve Block6ded16b2010-05-10 14:33:55 +01002911 int max_search_start = subject_length - pattern_length;
Ben Murdochf87a2032010-10-22 12:50:53 +01002912 StringSearch<PatternChar, SubjectChar> search(pattern);
2913 while (pos <= max_search_start) {
2914 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2915 *match_pos = pos;
2916 return false;
2917 }
2918 // Position of end of previous match.
2919 int match_end = pos + pattern_length;
2920 int new_pos = search.Search(subject, match_end);
2921 if (new_pos >= 0) {
2922 // A match.
2923 if (new_pos > match_end) {
2924 ReplacementStringBuilder::AddSubjectSlice(builder,
2925 match_end,
2926 new_pos);
Steve Block6ded16b2010-05-10 14:33:55 +01002927 }
Ben Murdochf87a2032010-10-22 12:50:53 +01002928 pos = new_pos;
2929 builder->Add(pattern_string);
2930 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01002931 break;
Ben Murdochf87a2032010-10-22 12:50:53 +01002932 }
Steve Block6ded16b2010-05-10 14:33:55 +01002933 }
Ben Murdochf87a2032010-10-22 12:50:53 +01002934
Steve Block6ded16b2010-05-10 14:33:55 +01002935 if (pos < max_search_start) {
2936 ReplacementStringBuilder::AddSubjectSlice(builder,
2937 pos + pattern_length,
2938 subject_length);
2939 }
2940 *match_pos = pos;
2941 return true;
2942}
2943
2944
2945static bool SearchStringMultiple(Handle<String> subject,
2946 Handle<String> pattern,
2947 Handle<JSArray> last_match_info,
2948 FixedArrayBuilder* builder) {
2949 ASSERT(subject->IsFlat());
2950 ASSERT(pattern->IsFlat());
Steve Block6ded16b2010-05-10 14:33:55 +01002951
2952 // Treating as if a previous match was before first character.
2953 int match_pos = -pattern->length();
2954
2955 for (;;) { // Break when search complete.
2956 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2957 AssertNoAllocation no_gc;
2958 if (subject->IsAsciiRepresentation()) {
2959 Vector<const char> subject_vector = subject->ToAsciiVector();
2960 if (pattern->IsAsciiRepresentation()) {
2961 if (SearchStringMultiple(subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01002962 pattern->ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01002963 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01002964 builder,
2965 &match_pos)) break;
2966 } else {
2967 if (SearchStringMultiple(subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01002968 pattern->ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01002969 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01002970 builder,
2971 &match_pos)) break;
2972 }
2973 } else {
2974 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2975 if (pattern->IsAsciiRepresentation()) {
2976 if (SearchStringMultiple(subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01002977 pattern->ToAsciiVector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01002978 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01002979 builder,
2980 &match_pos)) break;
2981 } else {
2982 if (SearchStringMultiple(subject_vector,
Steve Block6ded16b2010-05-10 14:33:55 +01002983 pattern->ToUC16Vector(),
Ben Murdochf87a2032010-10-22 12:50:53 +01002984 *pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01002985 builder,
2986 &match_pos)) break;
2987 }
2988 }
2989 }
2990
2991 if (match_pos >= 0) {
2992 SetLastMatchInfoNoCaptures(subject,
2993 last_match_info,
2994 match_pos,
2995 match_pos + pattern->length());
2996 return true;
2997 }
2998 return false; // No matches at all.
2999}
3000
3001
3002static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3003 Handle<String> subject,
3004 Handle<JSRegExp> regexp,
3005 Handle<JSArray> last_match_array,
3006 FixedArrayBuilder* builder) {
3007 ASSERT(subject->IsFlat());
3008 int match_start = -1;
3009 int match_end = 0;
3010 int pos = 0;
3011 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3012 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3013
3014 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003015 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003016 int subject_length = subject->length();
3017
3018 for (;;) { // Break on failure, return on exception.
3019 RegExpImpl::IrregexpResult result =
3020 RegExpImpl::IrregexpExecOnce(regexp,
3021 subject,
3022 pos,
3023 register_vector);
3024 if (result == RegExpImpl::RE_SUCCESS) {
3025 match_start = register_vector[0];
3026 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3027 if (match_end < match_start) {
3028 ReplacementStringBuilder::AddSubjectSlice(builder,
3029 match_end,
3030 match_start);
3031 }
3032 match_end = register_vector[1];
3033 HandleScope loop_scope;
3034 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3035 if (match_start != match_end) {
3036 pos = match_end;
3037 } else {
3038 pos = match_end + 1;
3039 if (pos > subject_length) break;
3040 }
3041 } else if (result == RegExpImpl::RE_FAILURE) {
3042 break;
3043 } else {
3044 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3045 return result;
3046 }
3047 }
3048
3049 if (match_start >= 0) {
3050 if (match_end < subject_length) {
3051 ReplacementStringBuilder::AddSubjectSlice(builder,
3052 match_end,
3053 subject_length);
3054 }
3055 SetLastMatchInfoNoCaptures(subject,
3056 last_match_array,
3057 match_start,
3058 match_end);
3059 return RegExpImpl::RE_SUCCESS;
3060 } else {
3061 return RegExpImpl::RE_FAILURE; // No matches at all.
3062 }
3063}
3064
3065
3066static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3067 Handle<String> subject,
3068 Handle<JSRegExp> regexp,
3069 Handle<JSArray> last_match_array,
3070 FixedArrayBuilder* builder) {
3071
3072 ASSERT(subject->IsFlat());
3073 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3074 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3075
3076 OffsetsVector registers(required_registers);
Steve Block791712a2010-08-27 10:21:07 +01003077 Vector<int32_t> register_vector(registers.vector(), registers.length());
Steve Block6ded16b2010-05-10 14:33:55 +01003078
3079 RegExpImpl::IrregexpResult result =
3080 RegExpImpl::IrregexpExecOnce(regexp,
3081 subject,
3082 0,
3083 register_vector);
3084
3085 int capture_count = regexp->CaptureCount();
3086 int subject_length = subject->length();
3087
3088 // Position to search from.
3089 int pos = 0;
3090 // End of previous match. Differs from pos if match was empty.
3091 int match_end = 0;
3092 if (result == RegExpImpl::RE_SUCCESS) {
3093 // Need to keep a copy of the previous match for creating last_match_info
3094 // at the end, so we have two vectors that we swap between.
3095 OffsetsVector registers2(required_registers);
3096 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3097
3098 do {
3099 int match_start = register_vector[0];
3100 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3101 if (match_end < match_start) {
3102 ReplacementStringBuilder::AddSubjectSlice(builder,
3103 match_end,
3104 match_start);
3105 }
3106 match_end = register_vector[1];
3107
3108 {
3109 // Avoid accumulating new handles inside loop.
3110 HandleScope temp_scope;
3111 // Arguments array to replace function is match, captures, index and
3112 // subject, i.e., 3 + capture count in total.
3113 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003114 Handle<String> match = Factory::NewSubString(subject,
3115 match_start,
3116 match_end);
3117 elements->set(0, *match);
Steve Block6ded16b2010-05-10 14:33:55 +01003118 for (int i = 1; i <= capture_count; i++) {
3119 int start = register_vector[i * 2];
3120 if (start >= 0) {
3121 int end = register_vector[i * 2 + 1];
3122 ASSERT(start <= end);
3123 Handle<String> substring = Factory::NewSubString(subject,
3124 start,
3125 end);
3126 elements->set(i, *substring);
3127 } else {
3128 ASSERT(register_vector[i * 2 + 1] < 0);
3129 elements->set(i, Heap::undefined_value());
3130 }
3131 }
3132 elements->set(capture_count + 1, Smi::FromInt(match_start));
3133 elements->set(capture_count + 2, *subject);
3134 builder->Add(*Factory::NewJSArrayWithElements(elements));
3135 }
3136 // Swap register vectors, so the last successful match is in
3137 // prev_register_vector.
Steve Block791712a2010-08-27 10:21:07 +01003138 Vector<int32_t> tmp = prev_register_vector;
Steve Block6ded16b2010-05-10 14:33:55 +01003139 prev_register_vector = register_vector;
3140 register_vector = tmp;
3141
3142 if (match_end > match_start) {
3143 pos = match_end;
3144 } else {
3145 pos = match_end + 1;
3146 if (pos > subject_length) {
3147 break;
3148 }
3149 }
3150
3151 result = RegExpImpl::IrregexpExecOnce(regexp,
3152 subject,
3153 pos,
3154 register_vector);
3155 } while (result == RegExpImpl::RE_SUCCESS);
3156
3157 if (result != RegExpImpl::RE_EXCEPTION) {
3158 // Finished matching, with at least one match.
3159 if (match_end < subject_length) {
3160 ReplacementStringBuilder::AddSubjectSlice(builder,
3161 match_end,
3162 subject_length);
3163 }
3164
3165 int last_match_capture_count = (capture_count + 1) * 2;
3166 int last_match_array_size =
3167 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3168 last_match_array->EnsureSize(last_match_array_size);
3169 AssertNoAllocation no_gc;
3170 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3171 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3172 RegExpImpl::SetLastSubject(elements, *subject);
3173 RegExpImpl::SetLastInput(elements, *subject);
3174 for (int i = 0; i < last_match_capture_count; i++) {
3175 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3176 }
3177 return RegExpImpl::RE_SUCCESS;
3178 }
3179 }
3180 // No matches at all, return failure or exception result directly.
3181 return result;
3182}
3183
3184
John Reck59135872010-11-02 12:39:01 -07003185static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01003186 ASSERT(args.length() == 4);
3187 HandleScope handles;
3188
3189 CONVERT_ARG_CHECKED(String, subject, 1);
3190 if (!subject->IsFlat()) { FlattenString(subject); }
3191 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3192 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3193 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3194
3195 ASSERT(last_match_info->HasFastElements());
3196 ASSERT(regexp->GetFlags().is_global());
3197 Handle<FixedArray> result_elements;
3198 if (result_array->HasFastElements()) {
3199 result_elements =
3200 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3201 } else {
3202 result_elements = Factory::NewFixedArrayWithHoles(16);
3203 }
3204 FixedArrayBuilder builder(result_elements);
3205
3206 if (regexp->TypeTag() == JSRegExp::ATOM) {
3207 Handle<String> pattern(
3208 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003209 ASSERT(pattern->IsFlat());
Steve Block6ded16b2010-05-10 14:33:55 +01003210 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3211 return *builder.ToJSArray(result_array);
3212 }
3213 return Heap::null_value();
3214 }
3215
3216 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3217
3218 RegExpImpl::IrregexpResult result;
3219 if (regexp->CaptureCount() == 0) {
3220 result = SearchRegExpNoCaptureMultiple(subject,
3221 regexp,
3222 last_match_info,
3223 &builder);
3224 } else {
3225 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3226 }
3227 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3228 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3229 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3230 return Failure::Exception();
3231}
3232
3233
John Reck59135872010-11-02 12:39:01 -07003234static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003235 NoHandleAllocation ha;
3236 ASSERT(args.length() == 2);
3237
3238 // Fast case where the result is a one character string.
3239 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3240 int value = Smi::cast(args[0])->value();
3241 int radix = Smi::cast(args[1])->value();
3242 if (value >= 0 && value < radix) {
3243 RUNTIME_ASSERT(radix <= 36);
3244 // Character array used for conversion.
3245 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3246 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3247 }
3248 }
3249
3250 // Slow case.
3251 CONVERT_DOUBLE_CHECKED(value, args[0]);
3252 if (isnan(value)) {
3253 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3254 }
3255 if (isinf(value)) {
3256 if (value < 0) {
3257 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3258 }
3259 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3260 }
3261 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3262 int radix = FastD2I(radix_number);
3263 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3264 char* str = DoubleToRadixCString(value, radix);
John Reck59135872010-11-02 12:39:01 -07003265 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003266 DeleteArray(str);
3267 return result;
3268}
3269
3270
John Reck59135872010-11-02 12:39:01 -07003271static MaybeObject* Runtime_NumberToFixed(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003272 NoHandleAllocation ha;
3273 ASSERT(args.length() == 2);
3274
3275 CONVERT_DOUBLE_CHECKED(value, args[0]);
3276 if (isnan(value)) {
3277 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3278 }
3279 if (isinf(value)) {
3280 if (value < 0) {
3281 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3282 }
3283 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3284 }
3285 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3286 int f = FastD2I(f_number);
3287 RUNTIME_ASSERT(f >= 0);
3288 char* str = DoubleToFixedCString(value, f);
John Reck59135872010-11-02 12:39:01 -07003289 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003290 DeleteArray(str);
John Reck59135872010-11-02 12:39:01 -07003291 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003292}
3293
3294
John Reck59135872010-11-02 12:39:01 -07003295static MaybeObject* Runtime_NumberToExponential(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003296 NoHandleAllocation ha;
3297 ASSERT(args.length() == 2);
3298
3299 CONVERT_DOUBLE_CHECKED(value, args[0]);
3300 if (isnan(value)) {
3301 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3302 }
3303 if (isinf(value)) {
3304 if (value < 0) {
3305 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3306 }
3307 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3308 }
3309 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3310 int f = FastD2I(f_number);
3311 RUNTIME_ASSERT(f >= -1 && f <= 20);
3312 char* str = DoubleToExponentialCString(value, f);
John Reck59135872010-11-02 12:39:01 -07003313 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003314 DeleteArray(str);
John Reck59135872010-11-02 12:39:01 -07003315 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003316}
3317
3318
John Reck59135872010-11-02 12:39:01 -07003319static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003320 NoHandleAllocation ha;
3321 ASSERT(args.length() == 2);
3322
3323 CONVERT_DOUBLE_CHECKED(value, args[0]);
3324 if (isnan(value)) {
3325 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3326 }
3327 if (isinf(value)) {
3328 if (value < 0) {
3329 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3330 }
3331 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3332 }
3333 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3334 int f = FastD2I(f_number);
3335 RUNTIME_ASSERT(f >= 1 && f <= 21);
3336 char* str = DoubleToPrecisionCString(value, f);
John Reck59135872010-11-02 12:39:01 -07003337 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
Steve Blocka7e24c12009-10-30 11:49:00 +00003338 DeleteArray(str);
John Reck59135872010-11-02 12:39:01 -07003339 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003340}
3341
3342
3343// Returns a single character string where first character equals
3344// string->Get(index).
3345static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
3346 if (index < static_cast<uint32_t>(string->length())) {
Steve Block6ded16b2010-05-10 14:33:55 +01003347 string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003348 return LookupSingleCharacterStringFromCode(
3349 string->Get(index));
3350 }
3351 return Execution::CharAt(string, index);
3352}
3353
3354
John Reck59135872010-11-02 12:39:01 -07003355MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3356 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003357 // Handle [] indexing on Strings
3358 if (object->IsString()) {
3359 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3360 if (!result->IsUndefined()) return *result;
3361 }
3362
3363 // Handle [] indexing on String objects
3364 if (object->IsStringObjectWithCharacterAt(index)) {
3365 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3366 Handle<Object> result =
3367 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3368 if (!result->IsUndefined()) return *result;
3369 }
3370
3371 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
3372 Handle<Object> prototype = GetPrototype(object);
3373 return prototype->GetElement(index);
3374 }
3375
Steve Block6ded16b2010-05-10 14:33:55 +01003376 return GetElement(object, index);
3377}
3378
3379
John Reck59135872010-11-02 12:39:01 -07003380MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003381 return object->GetElement(index);
3382}
3383
3384
John Reck59135872010-11-02 12:39:01 -07003385MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3386 Handle<Object> key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003387 HandleScope scope;
3388
3389 if (object->IsUndefined() || object->IsNull()) {
3390 Handle<Object> args[2] = { key, object };
3391 Handle<Object> error =
3392 Factory::NewTypeError("non_object_property_load",
3393 HandleVector(args, 2));
3394 return Top::Throw(*error);
3395 }
3396
3397 // Check if the given key is an array index.
3398 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003399 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003400 return GetElementOrCharAt(object, index);
3401 }
3402
3403 // Convert the key to a string - possibly by calling back into JavaScript.
3404 Handle<String> name;
3405 if (key->IsString()) {
3406 name = Handle<String>::cast(key);
3407 } else {
3408 bool has_pending_exception = false;
3409 Handle<Object> converted =
3410 Execution::ToString(key, &has_pending_exception);
3411 if (has_pending_exception) return Failure::Exception();
3412 name = Handle<String>::cast(converted);
3413 }
3414
3415 // Check if the name is trivially convertible to an index and get
3416 // the element if so.
3417 if (name->AsArrayIndex(&index)) {
3418 return GetElementOrCharAt(object, index);
3419 } else {
3420 PropertyAttributes attr;
3421 return object->GetProperty(*name, &attr);
3422 }
3423}
3424
3425
John Reck59135872010-11-02 12:39:01 -07003426static MaybeObject* Runtime_GetProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003427 NoHandleAllocation ha;
3428 ASSERT(args.length() == 2);
3429
3430 Handle<Object> object = args.at<Object>(0);
3431 Handle<Object> key = args.at<Object>(1);
3432
3433 return Runtime::GetObjectProperty(object, key);
3434}
3435
3436
Steve Blocka7e24c12009-10-30 11:49:00 +00003437// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
John Reck59135872010-11-02 12:39:01 -07003438static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003439 NoHandleAllocation ha;
3440 ASSERT(args.length() == 2);
3441
3442 // Fast cases for getting named properties of the receiver JSObject
3443 // itself.
3444 //
3445 // The global proxy objects has to be excluded since LocalLookup on
3446 // the global proxy object can return a valid result even though the
3447 // global proxy object never has properties. This is the case
3448 // because the global proxy object forwards everything to its hidden
3449 // prototype including local lookups.
3450 //
3451 // Additionally, we need to make sure that we do not cache results
3452 // for objects that require access checks.
3453 if (args[0]->IsJSObject() &&
3454 !args[0]->IsJSGlobalProxy() &&
3455 !args[0]->IsAccessCheckNeeded() &&
3456 args[1]->IsString()) {
3457 JSObject* receiver = JSObject::cast(args[0]);
3458 String* key = String::cast(args[1]);
3459 if (receiver->HasFastProperties()) {
3460 // Attempt to use lookup cache.
3461 Map* receiver_map = receiver->map();
3462 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3463 if (offset != -1) {
3464 Object* value = receiver->FastPropertyAt(offset);
3465 return value->IsTheHole() ? Heap::undefined_value() : value;
3466 }
3467 // Lookup cache miss. Perform lookup and update the cache if appropriate.
3468 LookupResult result;
3469 receiver->LocalLookup(key, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00003470 if (result.IsProperty() && result.type() == FIELD) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003471 int offset = result.GetFieldIndex();
3472 KeyedLookupCache::Update(receiver_map, key, offset);
3473 return receiver->FastPropertyAt(offset);
3474 }
3475 } else {
3476 // Attempt dictionary lookup.
3477 StringDictionary* dictionary = receiver->property_dictionary();
3478 int entry = dictionary->FindEntry(key);
3479 if ((entry != StringDictionary::kNotFound) &&
3480 (dictionary->DetailsAt(entry).type() == NORMAL)) {
3481 Object* value = dictionary->ValueAt(entry);
3482 if (!receiver->IsGlobalObject()) return value;
3483 value = JSGlobalPropertyCell::cast(value)->value();
3484 if (!value->IsTheHole()) return value;
3485 // If value is the hole do the general lookup.
3486 }
3487 }
Leon Clarkee46be812010-01-19 14:06:41 +00003488 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3489 // Fast case for string indexing using [] with a smi index.
3490 HandleScope scope;
3491 Handle<String> str = args.at<String>(0);
3492 int index = Smi::cast(args[1])->value();
3493 Handle<Object> result = GetCharAt(str, index);
3494 return *result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003495 }
3496
3497 // Fall back to GetObjectProperty.
3498 return Runtime::GetObjectProperty(args.at<Object>(0),
3499 args.at<Object>(1));
3500}
3501
3502
John Reck59135872010-11-02 12:39:01 -07003503static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
Andrei Popescu31002712010-02-23 13:46:05 +00003504 ASSERT(args.length() == 5);
3505 HandleScope scope;
3506 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3507 CONVERT_CHECKED(String, name, args[1]);
3508 CONVERT_CHECKED(Smi, flag_setter, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003509 Object* fun = args[3];
3510 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Andrei Popescu31002712010-02-23 13:46:05 +00003511 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3512 int unchecked = flag_attr->value();
3513 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3514 RUNTIME_ASSERT(!obj->IsNull());
3515 LookupResult result;
3516 obj->LocalLookupRealNamedProperty(name, &result);
3517
3518 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3519 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3520 // delete it to avoid running into trouble in DefineAccessor, which
3521 // handles this incorrectly if the property is readonly (does nothing)
Andrei Popescu402d9372010-02-26 13:31:12 +00003522 if (result.IsProperty() &&
Andrei Popescu31002712010-02-23 13:46:05 +00003523 (result.type() == FIELD || result.type() == NORMAL
3524 || result.type() == CONSTANT_FUNCTION)) {
John Reck59135872010-11-02 12:39:01 -07003525 Object* ok;
3526 { MaybeObject* maybe_ok =
3527 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3528 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3529 }
Andrei Popescu31002712010-02-23 13:46:05 +00003530 }
3531 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3532}
3533
John Reck59135872010-11-02 12:39:01 -07003534static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
Andrei Popescu31002712010-02-23 13:46:05 +00003535 ASSERT(args.length() == 4);
3536 HandleScope scope;
3537 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3538 CONVERT_ARG_CHECKED(String, name, 1);
3539 Handle<Object> obj_value = args.at<Object>(2);
3540
3541 CONVERT_CHECKED(Smi, flag, args[3]);
3542 int unchecked = flag->value();
3543 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3544
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003545 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3546
3547 // Check if this is an element.
3548 uint32_t index;
3549 bool is_element = name->AsArrayIndex(&index);
3550
3551 // Special case for elements if any of the flags are true.
3552 // If elements are in fast case we always implicitly assume that:
3553 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3554 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3555 is_element) {
3556 // Normalize the elements to enable attributes on the property.
John Reck59135872010-11-02 12:39:01 -07003557 NormalizeElements(js_object);
3558 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003559 // Make sure that we never go back to fast case.
3560 dictionary->set_requires_slow_elements();
3561 PropertyDetails details = PropertyDetails(attr, NORMAL);
John Reck59135872010-11-02 12:39:01 -07003562 NumberDictionarySet(dictionary, index, obj_value, details);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003563 }
3564
Andrei Popescu31002712010-02-23 13:46:05 +00003565 LookupResult result;
Ben Murdochb0fe1622011-05-05 13:52:32 +01003566 js_object->LookupRealNamedProperty(*name, &result);
Andrei Popescu31002712010-02-23 13:46:05 +00003567
Andrei Popescu31002712010-02-23 13:46:05 +00003568 // Take special care when attributes are different and there is already
3569 // a property. For simplicity we normalize the property which enables us
3570 // to not worry about changing the instance_descriptor and creating a new
3571 // map. The current version of SetObjectProperty does not handle attributes
3572 // correctly in the case where a property is a field and is reset with
3573 // new attributes.
Ben Murdochb0fe1622011-05-05 13:52:32 +01003574 if (result.IsProperty() &&
3575 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
Andrei Popescu31002712010-02-23 13:46:05 +00003576 // New attributes - normalize to avoid writing to instance descriptor
John Reck59135872010-11-02 12:39:01 -07003577 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Andrei Popescu402d9372010-02-26 13:31:12 +00003578 // Use IgnoreAttributes version since a readonly property may be
3579 // overridden and SetProperty does not allow this.
Ben Murdoch086aeea2011-05-13 15:57:08 +01003580 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3581 *obj_value,
3582 attr);
Andrei Popescu31002712010-02-23 13:46:05 +00003583 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003584
Andrei Popescu31002712010-02-23 13:46:05 +00003585 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3586}
3587
3588
John Reck59135872010-11-02 12:39:01 -07003589MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3590 Handle<Object> key,
3591 Handle<Object> value,
3592 PropertyAttributes attr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003593 HandleScope scope;
3594
3595 if (object->IsUndefined() || object->IsNull()) {
3596 Handle<Object> args[2] = { key, object };
3597 Handle<Object> error =
3598 Factory::NewTypeError("non_object_property_store",
3599 HandleVector(args, 2));
3600 return Top::Throw(*error);
3601 }
3602
3603 // If the object isn't a JavaScript object, we ignore the store.
3604 if (!object->IsJSObject()) return *value;
3605
3606 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3607
3608 // Check if the given key is an array index.
3609 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003610 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003611 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3612 // of a string using [] notation. We need to support this too in
3613 // JavaScript.
3614 // In the case of a String object we just need to redirect the assignment to
3615 // the underlying string if the index is in range. Since the underlying
3616 // string does nothing with the assignment then we can ignore such
3617 // assignments.
3618 if (js_object->IsStringObjectWithCharacterAt(index)) {
3619 return *value;
3620 }
3621
3622 Handle<Object> result = SetElement(js_object, index, value);
3623 if (result.is_null()) return Failure::Exception();
3624 return *value;
3625 }
3626
3627 if (key->IsString()) {
3628 Handle<Object> result;
3629 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003630 result = SetElement(js_object, index, value);
3631 } else {
3632 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01003633 key_string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003634 result = SetProperty(js_object, key_string, value, attr);
3635 }
3636 if (result.is_null()) return Failure::Exception();
3637 return *value;
3638 }
3639
3640 // Call-back into JavaScript to convert the key to a string.
3641 bool has_pending_exception = false;
3642 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3643 if (has_pending_exception) return Failure::Exception();
3644 Handle<String> name = Handle<String>::cast(converted);
3645
3646 if (name->AsArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003647 return js_object->SetElement(index, *value);
3648 } else {
3649 return js_object->SetProperty(*name, *value, attr);
3650 }
3651}
3652
3653
John Reck59135872010-11-02 12:39:01 -07003654MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3655 Handle<Object> key,
3656 Handle<Object> value,
3657 PropertyAttributes attr) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003658 HandleScope scope;
3659
3660 // Check if the given key is an array index.
3661 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003662 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003663 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3664 // of a string using [] notation. We need to support this too in
3665 // JavaScript.
3666 // In the case of a String object we just need to redirect the assignment to
3667 // the underlying string if the index is in range. Since the underlying
3668 // string does nothing with the assignment then we can ignore such
3669 // assignments.
3670 if (js_object->IsStringObjectWithCharacterAt(index)) {
3671 return *value;
3672 }
3673
3674 return js_object->SetElement(index, *value);
3675 }
3676
3677 if (key->IsString()) {
3678 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003679 return js_object->SetElement(index, *value);
3680 } else {
3681 Handle<String> key_string = Handle<String>::cast(key);
Steve Block6ded16b2010-05-10 14:33:55 +01003682 key_string->TryFlatten();
Ben Murdoch086aeea2011-05-13 15:57:08 +01003683 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3684 *value,
3685 attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003686 }
3687 }
3688
3689 // Call-back into JavaScript to convert the key to a string.
3690 bool has_pending_exception = false;
3691 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3692 if (has_pending_exception) return Failure::Exception();
3693 Handle<String> name = Handle<String>::cast(converted);
3694
3695 if (name->AsArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003696 return js_object->SetElement(index, *value);
3697 } else {
Ben Murdoch086aeea2011-05-13 15:57:08 +01003698 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
Steve Blocka7e24c12009-10-30 11:49:00 +00003699 }
3700}
3701
3702
John Reck59135872010-11-02 12:39:01 -07003703MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3704 Handle<Object> key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003705 HandleScope scope;
3706
3707 // Check if the given key is an array index.
3708 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003709 if (key->ToArrayIndex(&index)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003710 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3711 // characters of a string using [] notation. In the case of a
3712 // String object we just need to redirect the deletion to the
3713 // underlying string if the index is in range. Since the
3714 // underlying string does nothing with the deletion, we can ignore
3715 // such deletions.
3716 if (js_object->IsStringObjectWithCharacterAt(index)) {
3717 return Heap::true_value();
3718 }
3719
3720 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3721 }
3722
3723 Handle<String> key_string;
3724 if (key->IsString()) {
3725 key_string = Handle<String>::cast(key);
3726 } else {
3727 // Call-back into JavaScript to convert the key to a string.
3728 bool has_pending_exception = false;
3729 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3730 if (has_pending_exception) return Failure::Exception();
3731 key_string = Handle<String>::cast(converted);
3732 }
3733
Steve Block6ded16b2010-05-10 14:33:55 +01003734 key_string->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003735 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3736}
3737
3738
John Reck59135872010-11-02 12:39:01 -07003739static MaybeObject* Runtime_SetProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003740 NoHandleAllocation ha;
3741 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3742
3743 Handle<Object> object = args.at<Object>(0);
3744 Handle<Object> key = args.at<Object>(1);
3745 Handle<Object> value = args.at<Object>(2);
3746
3747 // Compute attributes.
3748 PropertyAttributes attributes = NONE;
3749 if (args.length() == 4) {
3750 CONVERT_CHECKED(Smi, value_obj, args[3]);
3751 int unchecked_value = value_obj->value();
3752 // Only attribute bits should be set.
3753 RUNTIME_ASSERT(
3754 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3755 attributes = static_cast<PropertyAttributes>(unchecked_value);
3756 }
3757 return Runtime::SetObjectProperty(object, key, value, attributes);
3758}
3759
3760
3761// Set a local property, even if it is READ_ONLY. If the property does not
3762// exist, it will be added with attributes NONE.
John Reck59135872010-11-02 12:39:01 -07003763static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003764 NoHandleAllocation ha;
3765 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3766 CONVERT_CHECKED(JSObject, object, args[0]);
3767 CONVERT_CHECKED(String, name, args[1]);
3768 // Compute attributes.
3769 PropertyAttributes attributes = NONE;
3770 if (args.length() == 4) {
3771 CONVERT_CHECKED(Smi, value_obj, args[3]);
3772 int unchecked_value = value_obj->value();
3773 // Only attribute bits should be set.
3774 RUNTIME_ASSERT(
3775 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3776 attributes = static_cast<PropertyAttributes>(unchecked_value);
3777 }
3778
3779 return object->
Ben Murdoch086aeea2011-05-13 15:57:08 +01003780 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003781}
3782
3783
John Reck59135872010-11-02 12:39:01 -07003784static MaybeObject* Runtime_DeleteProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003785 NoHandleAllocation ha;
3786 ASSERT(args.length() == 2);
3787
3788 CONVERT_CHECKED(JSObject, object, args[0]);
3789 CONVERT_CHECKED(String, key, args[1]);
3790 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
3791}
3792
3793
3794static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3795 Handle<String> key) {
3796 if (object->HasLocalProperty(*key)) return Heap::true_value();
3797 // Handle hidden prototypes. If there's a hidden prototype above this thing
3798 // then we have to check it for properties, because they are supposed to
3799 // look like they are on this object.
3800 Handle<Object> proto(object->GetPrototype());
3801 if (proto->IsJSObject() &&
3802 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3803 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3804 }
3805 return Heap::false_value();
3806}
3807
3808
John Reck59135872010-11-02 12:39:01 -07003809static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003810 NoHandleAllocation ha;
3811 ASSERT(args.length() == 2);
3812 CONVERT_CHECKED(String, key, args[1]);
3813
3814 Object* obj = args[0];
3815 // Only JS objects can have properties.
3816 if (obj->IsJSObject()) {
3817 JSObject* object = JSObject::cast(obj);
3818 // Fast case - no interceptors.
3819 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3820 // Slow case. Either it's not there or we have an interceptor. We should
3821 // have handles for this kind of deal.
3822 HandleScope scope;
3823 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3824 Handle<String>(key));
3825 } else if (obj->IsString()) {
3826 // Well, there is one exception: Handle [] on strings.
3827 uint32_t index;
3828 if (key->AsArrayIndex(&index)) {
3829 String* string = String::cast(obj);
3830 if (index < static_cast<uint32_t>(string->length()))
3831 return Heap::true_value();
3832 }
3833 }
3834 return Heap::false_value();
3835}
3836
3837
John Reck59135872010-11-02 12:39:01 -07003838static MaybeObject* Runtime_HasProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003839 NoHandleAllocation na;
3840 ASSERT(args.length() == 2);
3841
3842 // Only JS objects can have properties.
3843 if (args[0]->IsJSObject()) {
3844 JSObject* object = JSObject::cast(args[0]);
3845 CONVERT_CHECKED(String, key, args[1]);
3846 if (object->HasProperty(key)) return Heap::true_value();
3847 }
3848 return Heap::false_value();
3849}
3850
3851
John Reck59135872010-11-02 12:39:01 -07003852static MaybeObject* Runtime_HasElement(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003853 NoHandleAllocation na;
3854 ASSERT(args.length() == 2);
3855
3856 // Only JS objects can have elements.
3857 if (args[0]->IsJSObject()) {
3858 JSObject* object = JSObject::cast(args[0]);
3859 CONVERT_CHECKED(Smi, index_obj, args[1]);
3860 uint32_t index = index_obj->value();
3861 if (object->HasElement(index)) return Heap::true_value();
3862 }
3863 return Heap::false_value();
3864}
3865
3866
John Reck59135872010-11-02 12:39:01 -07003867static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003868 NoHandleAllocation ha;
3869 ASSERT(args.length() == 2);
3870
3871 CONVERT_CHECKED(JSObject, object, args[0]);
3872 CONVERT_CHECKED(String, key, args[1]);
3873
3874 uint32_t index;
3875 if (key->AsArrayIndex(&index)) {
3876 return Heap::ToBoolean(object->HasElement(index));
3877 }
3878
3879 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3880 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
3881}
3882
3883
John Reck59135872010-11-02 12:39:01 -07003884static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003885 HandleScope scope;
3886 ASSERT(args.length() == 1);
3887 CONVERT_ARG_CHECKED(JSObject, object, 0);
3888 return *GetKeysFor(object);
3889}
3890
3891
3892// Returns either a FixedArray as Runtime_GetPropertyNames,
3893// or, if the given object has an enum cache that contains
3894// all enumerable properties of the object and its prototypes
3895// have none, the map of the object. This is used to speed up
3896// the check for deletions during a for-in.
John Reck59135872010-11-02 12:39:01 -07003897static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003898 ASSERT(args.length() == 1);
3899
3900 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3901
3902 if (raw_object->IsSimpleEnum()) return raw_object->map();
3903
3904 HandleScope scope;
3905 Handle<JSObject> object(raw_object);
3906 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3907 INCLUDE_PROTOS);
3908
3909 // Test again, since cache may have been built by preceding call.
3910 if (object->IsSimpleEnum()) return object->map();
3911
3912 return *content;
3913}
3914
3915
Leon Clarkee46be812010-01-19 14:06:41 +00003916// Find the length of the prototype chain that is to to handled as one. If a
3917// prototype object is hidden it is to be viewed as part of the the object it
3918// is prototype for.
3919static int LocalPrototypeChainLength(JSObject* obj) {
3920 int count = 1;
3921 Object* proto = obj->GetPrototype();
3922 while (proto->IsJSObject() &&
3923 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3924 count++;
3925 proto = JSObject::cast(proto)->GetPrototype();
3926 }
3927 return count;
3928}
3929
3930
3931// Return the names of the local named properties.
3932// args[0]: object
John Reck59135872010-11-02 12:39:01 -07003933static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +00003934 HandleScope scope;
3935 ASSERT(args.length() == 1);
3936 if (!args[0]->IsJSObject()) {
3937 return Heap::undefined_value();
3938 }
3939 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3940
3941 // Skip the global proxy as it has no properties and always delegates to the
3942 // real global object.
3943 if (obj->IsJSGlobalProxy()) {
Leon Clarke4515c472010-02-03 11:58:03 +00003944 // Only collect names if access is permitted.
3945 if (obj->IsAccessCheckNeeded() &&
3946 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3947 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3948 return *Factory::NewJSArray(0);
3949 }
Leon Clarkee46be812010-01-19 14:06:41 +00003950 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3951 }
3952
3953 // Find the number of objects making up this.
3954 int length = LocalPrototypeChainLength(*obj);
3955
3956 // Find the number of local properties for each of the objects.
Steve Block6ded16b2010-05-10 14:33:55 +01003957 ScopedVector<int> local_property_count(length);
Leon Clarkee46be812010-01-19 14:06:41 +00003958 int total_property_count = 0;
3959 Handle<JSObject> jsproto = obj;
3960 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00003961 // Only collect names if access is permitted.
3962 if (jsproto->IsAccessCheckNeeded() &&
3963 !Top::MayNamedAccess(*jsproto,
3964 Heap::undefined_value(),
3965 v8::ACCESS_KEYS)) {
3966 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3967 return *Factory::NewJSArray(0);
3968 }
Leon Clarkee46be812010-01-19 14:06:41 +00003969 int n;
3970 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3971 local_property_count[i] = n;
3972 total_property_count += n;
3973 if (i < length - 1) {
3974 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3975 }
3976 }
3977
3978 // Allocate an array with storage for all the property names.
3979 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3980
3981 // Get the property names.
3982 jsproto = obj;
3983 int proto_with_hidden_properties = 0;
3984 for (int i = 0; i < length; i++) {
3985 jsproto->GetLocalPropertyNames(*names,
3986 i == 0 ? 0 : local_property_count[i - 1]);
3987 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3988 proto_with_hidden_properties++;
3989 }
3990 if (i < length - 1) {
3991 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3992 }
3993 }
3994
3995 // Filter out name of hidden propeties object.
3996 if (proto_with_hidden_properties > 0) {
3997 Handle<FixedArray> old_names = names;
3998 names = Factory::NewFixedArray(
3999 names->length() - proto_with_hidden_properties);
4000 int dest_pos = 0;
4001 for (int i = 0; i < total_property_count; i++) {
4002 Object* name = old_names->get(i);
4003 if (name == Heap::hidden_symbol()) {
4004 continue;
4005 }
4006 names->set(dest_pos++, name);
4007 }
4008 }
4009
Leon Clarkee46be812010-01-19 14:06:41 +00004010 return *Factory::NewJSArrayWithElements(names);
4011}
4012
4013
4014// Return the names of the local indexed properties.
4015// args[0]: object
John Reck59135872010-11-02 12:39:01 -07004016static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +00004017 HandleScope scope;
4018 ASSERT(args.length() == 1);
4019 if (!args[0]->IsJSObject()) {
4020 return Heap::undefined_value();
4021 }
4022 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4023
4024 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4025 Handle<FixedArray> names = Factory::NewFixedArray(n);
4026 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4027 return *Factory::NewJSArrayWithElements(names);
4028}
4029
4030
4031// Return information on whether an object has a named or indexed interceptor.
4032// args[0]: object
John Reck59135872010-11-02 12:39:01 -07004033static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +00004034 HandleScope scope;
4035 ASSERT(args.length() == 1);
4036 if (!args[0]->IsJSObject()) {
4037 return Smi::FromInt(0);
4038 }
4039 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4040
4041 int result = 0;
4042 if (obj->HasNamedInterceptor()) result |= 2;
4043 if (obj->HasIndexedInterceptor()) result |= 1;
4044
4045 return Smi::FromInt(result);
4046}
4047
4048
4049// Return property names from named interceptor.
4050// args[0]: object
John Reck59135872010-11-02 12:39:01 -07004051static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +00004052 HandleScope scope;
4053 ASSERT(args.length() == 1);
4054 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4055
4056 if (obj->HasNamedInterceptor()) {
4057 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4058 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4059 }
4060 return Heap::undefined_value();
4061}
4062
4063
4064// Return element names from indexed interceptor.
4065// args[0]: object
John Reck59135872010-11-02 12:39:01 -07004066static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
Leon Clarkee46be812010-01-19 14:06:41 +00004067 HandleScope scope;
4068 ASSERT(args.length() == 1);
4069 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4070
4071 if (obj->HasIndexedInterceptor()) {
4072 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4073 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4074 }
4075 return Heap::undefined_value();
4076}
4077
4078
John Reck59135872010-11-02 12:39:01 -07004079static MaybeObject* Runtime_LocalKeys(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004080 ASSERT_EQ(args.length(), 1);
4081 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4082 HandleScope scope;
4083 Handle<JSObject> object(raw_object);
4084 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4085 LOCAL_ONLY);
4086 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4087 // property array and since the result is mutable we have to create
4088 // a fresh clone on each invocation.
4089 int length = contents->length();
4090 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4091 for (int i = 0; i < length; i++) {
4092 Object* entry = contents->get(i);
4093 if (entry->IsString()) {
4094 copy->set(i, entry);
4095 } else {
4096 ASSERT(entry->IsNumber());
4097 HandleScope scope;
4098 Handle<Object> entry_handle(entry);
4099 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4100 copy->set(i, *entry_str);
4101 }
4102 }
4103 return *Factory::NewJSArrayWithElements(copy);
4104}
4105
4106
John Reck59135872010-11-02 12:39:01 -07004107static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004108 NoHandleAllocation ha;
4109 ASSERT(args.length() == 1);
4110
4111 // Compute the frame holding the arguments.
4112 JavaScriptFrameIterator it;
4113 it.AdvanceToArgumentsFrame();
4114 JavaScriptFrame* frame = it.frame();
4115
4116 // Get the actual number of provided arguments.
4117 const uint32_t n = frame->GetProvidedParametersCount();
4118
4119 // Try to convert the key to an index. If successful and within
4120 // index return the the argument from the frame.
4121 uint32_t index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004122 if (args[0]->ToArrayIndex(&index) && index < n) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004123 return frame->GetParameter(index);
4124 }
4125
4126 // Convert the key to a string.
4127 HandleScope scope;
4128 bool exception = false;
4129 Handle<Object> converted =
4130 Execution::ToString(args.at<Object>(0), &exception);
4131 if (exception) return Failure::Exception();
4132 Handle<String> key = Handle<String>::cast(converted);
4133
4134 // Try to convert the string key into an array index.
4135 if (key->AsArrayIndex(&index)) {
4136 if (index < n) {
4137 return frame->GetParameter(index);
4138 } else {
4139 return Top::initial_object_prototype()->GetElement(index);
4140 }
4141 }
4142
4143 // Handle special arguments properties.
4144 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4145 if (key->Equals(Heap::callee_symbol())) return frame->function();
4146
4147 // Lookup in the initial Object.prototype object.
4148 return Top::initial_object_prototype()->GetProperty(*key);
4149}
4150
4151
John Reck59135872010-11-02 12:39:01 -07004152static MaybeObject* Runtime_ToFastProperties(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00004153 HandleScope scope;
4154
Steve Blocka7e24c12009-10-30 11:49:00 +00004155 ASSERT(args.length() == 1);
4156 Handle<Object> object = args.at<Object>(0);
4157 if (object->IsJSObject()) {
4158 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
Andrei Popescu402d9372010-02-26 13:31:12 +00004159 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07004160 MaybeObject* ok = js_object->TransformToFastProperties(0);
4161 if (ok->IsRetryAfterGC()) return ok;
Andrei Popescu402d9372010-02-26 13:31:12 +00004162 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004163 }
4164 return *object;
4165}
4166
4167
John Reck59135872010-11-02 12:39:01 -07004168static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
Andrei Popescu402d9372010-02-26 13:31:12 +00004169 HandleScope scope;
4170
Steve Blocka7e24c12009-10-30 11:49:00 +00004171 ASSERT(args.length() == 1);
4172 Handle<Object> object = args.at<Object>(0);
4173 if (object->IsJSObject()) {
4174 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
John Reck59135872010-11-02 12:39:01 -07004175 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00004176 }
4177 return *object;
4178}
4179
4180
John Reck59135872010-11-02 12:39:01 -07004181static MaybeObject* Runtime_ToBool(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004182 NoHandleAllocation ha;
4183 ASSERT(args.length() == 1);
4184
4185 return args[0]->ToBoolean();
4186}
4187
4188
4189// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4190// Possible optimizations: put the type string into the oddballs.
John Reck59135872010-11-02 12:39:01 -07004191static MaybeObject* Runtime_Typeof(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004192 NoHandleAllocation ha;
4193
4194 Object* obj = args[0];
4195 if (obj->IsNumber()) return Heap::number_symbol();
4196 HeapObject* heap_obj = HeapObject::cast(obj);
4197
4198 // typeof an undetectable object is 'undefined'
4199 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
4200
4201 InstanceType instance_type = heap_obj->map()->instance_type();
4202 if (instance_type < FIRST_NONSTRING_TYPE) {
4203 return Heap::string_symbol();
4204 }
4205
4206 switch (instance_type) {
4207 case ODDBALL_TYPE:
4208 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4209 return Heap::boolean_symbol();
4210 }
4211 if (heap_obj->IsNull()) {
4212 return Heap::object_symbol();
4213 }
4214 ASSERT(heap_obj->IsUndefined());
4215 return Heap::undefined_symbol();
4216 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
4217 return Heap::function_symbol();
4218 default:
4219 // For any kind of object not handled above, the spec rule for
4220 // host objects gives that it is okay to return "object"
4221 return Heap::object_symbol();
4222 }
4223}
4224
4225
Steve Block6ded16b2010-05-10 14:33:55 +01004226static bool AreDigits(const char*s, int from, int to) {
4227 for (int i = from; i < to; i++) {
4228 if (s[i] < '0' || s[i] > '9') return false;
4229 }
4230
4231 return true;
4232}
4233
4234
4235static int ParseDecimalInteger(const char*s, int from, int to) {
4236 ASSERT(to - from < 10); // Overflow is not possible.
4237 ASSERT(from < to);
4238 int d = s[from] - '0';
4239
4240 for (int i = from + 1; i < to; i++) {
4241 d = 10 * d + (s[i] - '0');
4242 }
4243
4244 return d;
4245}
4246
4247
John Reck59135872010-11-02 12:39:01 -07004248static MaybeObject* Runtime_StringToNumber(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004249 NoHandleAllocation ha;
4250 ASSERT(args.length() == 1);
4251 CONVERT_CHECKED(String, subject, args[0]);
Steve Block6ded16b2010-05-10 14:33:55 +01004252 subject->TryFlatten();
4253
4254 // Fast case: short integer or some sorts of junk values.
4255 int len = subject->length();
4256 if (subject->IsSeqAsciiString()) {
4257 if (len == 0) return Smi::FromInt(0);
4258
4259 char const* data = SeqAsciiString::cast(subject)->GetChars();
4260 bool minus = (data[0] == '-');
4261 int start_pos = (minus ? 1 : 0);
4262
4263 if (start_pos == len) {
4264 return Heap::nan_value();
4265 } else if (data[start_pos] > '9') {
4266 // Fast check for a junk value. A valid string may start from a
4267 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4268 // the 'I' character ('Infinity'). All of that have codes not greater than
4269 // '9' except 'I'.
4270 if (data[start_pos] != 'I') {
4271 return Heap::nan_value();
4272 }
4273 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4274 // The maximal/minimal smi has 10 digits. If the string has less digits we
4275 // know it will fit into the smi-data type.
4276 int d = ParseDecimalInteger(data, start_pos, len);
4277 if (minus) {
4278 if (d == 0) return Heap::minus_zero_value();
4279 d = -d;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004280 } else if (!subject->HasHashCode() &&
4281 len <= String::kMaxArrayIndexSize &&
4282 (len == 1 || data[0] != '0')) {
4283 // String hash is not calculated yet but all the data are present.
4284 // Update the hash field to speed up sequential convertions.
Iain Merrick9ac36c92010-09-13 15:29:50 +01004285 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004286#ifdef DEBUG
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004287 subject->Hash(); // Force hash calculation.
4288 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4289 static_cast<int>(hash));
4290#endif
4291 subject->set_hash_field(hash);
Steve Block6ded16b2010-05-10 14:33:55 +01004292 }
4293 return Smi::FromInt(d);
4294 }
4295 }
4296
4297 // Slower case.
Steve Blocka7e24c12009-10-30 11:49:00 +00004298 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4299}
4300
4301
John Reck59135872010-11-02 12:39:01 -07004302static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004303 NoHandleAllocation ha;
4304 ASSERT(args.length() == 1);
4305
4306 CONVERT_CHECKED(JSArray, codes, args[0]);
4307 int length = Smi::cast(codes->length())->value();
4308
4309 // Check if the string can be ASCII.
4310 int i;
4311 for (i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07004312 Object* element;
4313 { MaybeObject* maybe_element = codes->GetElement(i);
4314 // We probably can't get an exception here, but just in order to enforce
4315 // the checking of inputs in the runtime calls we check here.
4316 if (!maybe_element->ToObject(&element)) return maybe_element;
4317 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004318 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4319 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4320 break;
4321 }
4322
John Reck59135872010-11-02 12:39:01 -07004323 MaybeObject* maybe_object = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00004324 if (i == length) { // The string is ASCII.
John Reck59135872010-11-02 12:39:01 -07004325 maybe_object = Heap::AllocateRawAsciiString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00004326 } else { // The string is not ASCII.
John Reck59135872010-11-02 12:39:01 -07004327 maybe_object = Heap::AllocateRawTwoByteString(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00004328 }
4329
John Reck59135872010-11-02 12:39:01 -07004330 Object* object = NULL;
4331 if (!maybe_object->ToObject(&object)) return maybe_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00004332 String* result = String::cast(object);
4333 for (int i = 0; i < length; i++) {
John Reck59135872010-11-02 12:39:01 -07004334 Object* element;
4335 { MaybeObject* maybe_element = codes->GetElement(i);
4336 if (!maybe_element->ToObject(&element)) return maybe_element;
4337 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4339 result->Set(i, chr & 0xffff);
4340 }
4341 return result;
4342}
4343
4344
4345// kNotEscaped is generated by the following:
4346//
4347// #!/bin/perl
4348// for (my $i = 0; $i < 256; $i++) {
4349// print "\n" if $i % 16 == 0;
4350// my $c = chr($i);
4351// my $escaped = 1;
4352// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4353// print $escaped ? "0, " : "1, ";
4354// }
4355
4356
4357static bool IsNotEscaped(uint16_t character) {
4358 // Only for 8 bit characters, the rest are always escaped (in a different way)
4359 ASSERT(character < 256);
4360 static const char kNotEscaped[256] = {
4361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4367 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4377 };
4378 return kNotEscaped[character] != 0;
4379}
4380
4381
John Reck59135872010-11-02 12:39:01 -07004382static MaybeObject* Runtime_URIEscape(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004383 const char hex_chars[] = "0123456789ABCDEF";
4384 NoHandleAllocation ha;
4385 ASSERT(args.length() == 1);
4386 CONVERT_CHECKED(String, source, args[0]);
4387
Steve Block6ded16b2010-05-10 14:33:55 +01004388 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004389
4390 int escaped_length = 0;
4391 int length = source->length();
4392 {
4393 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
4394 buffer->Reset(source);
4395 while (buffer->has_more()) {
4396 uint16_t character = buffer->GetNext();
4397 if (character >= 256) {
4398 escaped_length += 6;
4399 } else if (IsNotEscaped(character)) {
4400 escaped_length++;
4401 } else {
4402 escaped_length += 3;
4403 }
Steve Block3ce2e202009-11-05 08:53:23 +00004404 // We don't allow strings that are longer than a maximal length.
Leon Clarkee46be812010-01-19 14:06:41 +00004405 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
Steve Block3ce2e202009-11-05 08:53:23 +00004406 if (escaped_length > String::kMaxLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004407 Top::context()->mark_out_of_memory();
4408 return Failure::OutOfMemoryException();
4409 }
4410 }
4411 }
4412 // No length change implies no change. Return original string if no change.
4413 if (escaped_length == length) {
4414 return source;
4415 }
John Reck59135872010-11-02 12:39:01 -07004416 Object* o;
4417 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4418 if (!maybe_o->ToObject(&o)) return maybe_o;
4419 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004420 String* destination = String::cast(o);
4421 int dest_position = 0;
4422
4423 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
4424 buffer->Rewind();
4425 while (buffer->has_more()) {
4426 uint16_t chr = buffer->GetNext();
4427 if (chr >= 256) {
4428 destination->Set(dest_position, '%');
4429 destination->Set(dest_position+1, 'u');
4430 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4431 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4432 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4433 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
4434 dest_position += 6;
4435 } else if (IsNotEscaped(chr)) {
4436 destination->Set(dest_position, chr);
4437 dest_position++;
4438 } else {
4439 destination->Set(dest_position, '%');
4440 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4441 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
4442 dest_position += 3;
4443 }
4444 }
4445 return destination;
4446}
4447
4448
4449static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4450 static const signed char kHexValue['g'] = {
4451 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4452 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4453 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4454 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4455 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4456 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4457 -1, 10, 11, 12, 13, 14, 15 };
4458
4459 if (character1 > 'f') return -1;
4460 int hi = kHexValue[character1];
4461 if (hi == -1) return -1;
4462 if (character2 > 'f') return -1;
4463 int lo = kHexValue[character2];
4464 if (lo == -1) return -1;
4465 return (hi << 4) + lo;
4466}
4467
4468
4469static inline int Unescape(String* source,
4470 int i,
4471 int length,
4472 int* step) {
4473 uint16_t character = source->Get(i);
4474 int32_t hi = 0;
4475 int32_t lo = 0;
4476 if (character == '%' &&
4477 i <= length - 6 &&
4478 source->Get(i + 1) == 'u' &&
4479 (hi = TwoDigitHex(source->Get(i + 2),
4480 source->Get(i + 3))) != -1 &&
4481 (lo = TwoDigitHex(source->Get(i + 4),
4482 source->Get(i + 5))) != -1) {
4483 *step = 6;
4484 return (hi << 8) + lo;
4485 } else if (character == '%' &&
4486 i <= length - 3 &&
4487 (lo = TwoDigitHex(source->Get(i + 1),
4488 source->Get(i + 2))) != -1) {
4489 *step = 3;
4490 return lo;
4491 } else {
4492 *step = 1;
4493 return character;
4494 }
4495}
4496
4497
John Reck59135872010-11-02 12:39:01 -07004498static MaybeObject* Runtime_URIUnescape(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004499 NoHandleAllocation ha;
4500 ASSERT(args.length() == 1);
4501 CONVERT_CHECKED(String, source, args[0]);
4502
Steve Block6ded16b2010-05-10 14:33:55 +01004503 source->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004504
4505 bool ascii = true;
4506 int length = source->length();
4507
4508 int unescaped_length = 0;
4509 for (int i = 0; i < length; unescaped_length++) {
4510 int step;
4511 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
4512 ascii = false;
4513 }
4514 i += step;
4515 }
4516
4517 // No length change implies no change. Return original string if no change.
4518 if (unescaped_length == length)
4519 return source;
4520
John Reck59135872010-11-02 12:39:01 -07004521 Object* o;
4522 { MaybeObject* maybe_o = ascii ?
4523 Heap::AllocateRawAsciiString(unescaped_length) :
4524 Heap::AllocateRawTwoByteString(unescaped_length);
4525 if (!maybe_o->ToObject(&o)) return maybe_o;
4526 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004527 String* destination = String::cast(o);
4528
4529 int dest_position = 0;
4530 for (int i = 0; i < length; dest_position++) {
4531 int step;
4532 destination->Set(dest_position, Unescape(source, i, length, &step));
4533 i += step;
4534 }
4535 return destination;
4536}
4537
4538
Ben Murdochb0fe1622011-05-05 13:52:32 +01004539static const unsigned int kQuoteTableLength = 128u;
4540
4541static const int kJsonQuotesCharactersPerEntry = 8;
4542static const char* const JsonQuotes =
4543 "\\u0000 \\u0001 \\u0002 \\u0003 "
4544 "\\u0004 \\u0005 \\u0006 \\u0007 "
4545 "\\b \\t \\n \\u000b "
4546 "\\f \\r \\u000e \\u000f "
4547 "\\u0010 \\u0011 \\u0012 \\u0013 "
4548 "\\u0014 \\u0015 \\u0016 \\u0017 "
4549 "\\u0018 \\u0019 \\u001a \\u001b "
4550 "\\u001c \\u001d \\u001e \\u001f "
4551 " ! \\\" # "
4552 "$ % & ' "
4553 "( ) * + "
4554 ", - . / "
4555 "0 1 2 3 "
4556 "4 5 6 7 "
4557 "8 9 : ; "
4558 "< = > ? "
4559 "@ A B C "
4560 "D E F G "
4561 "H I J K "
4562 "L M N O "
4563 "P Q R S "
4564 "T U V W "
4565 "X Y Z [ "
4566 "\\\\ ] ^ _ "
4567 "` a b c "
4568 "d e f g "
4569 "h i j k "
4570 "l m n o "
4571 "p q r s "
4572 "t u v w "
4573 "x y z { "
4574 "| } ~ \177 ";
4575
4576
4577// For a string that is less than 32k characters it should always be
4578// possible to allocate it in new space.
4579static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4580
4581
4582// Doing JSON quoting cannot make the string more than this many times larger.
4583static const int kJsonQuoteWorstCaseBlowup = 6;
4584
4585
4586// Covers the entire ASCII range (all other characters are unchanged by JSON
4587// quoting).
4588static const byte JsonQuoteLengths[kQuoteTableLength] = {
4589 6, 6, 6, 6, 6, 6, 6, 6,
4590 2, 2, 2, 6, 2, 2, 6, 6,
4591 6, 6, 6, 6, 6, 6, 6, 6,
4592 6, 6, 6, 6, 6, 6, 6, 6,
4593 1, 1, 2, 1, 1, 1, 1, 1,
4594 1, 1, 1, 1, 1, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 1, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1,
4599 1, 1, 1, 1, 1, 1, 1, 1,
4600 1, 1, 1, 1, 2, 1, 1, 1,
4601 1, 1, 1, 1, 1, 1, 1, 1,
4602 1, 1, 1, 1, 1, 1, 1, 1,
4603 1, 1, 1, 1, 1, 1, 1, 1,
4604 1, 1, 1, 1, 1, 1, 1, 1,
4605};
4606
4607
4608template <typename StringType>
4609MaybeObject* AllocateRawString(int length);
4610
4611
4612template <>
4613MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4614 return Heap::AllocateRawTwoByteString(length);
4615}
4616
4617
4618template <>
4619MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4620 return Heap::AllocateRawAsciiString(length);
4621}
4622
4623
4624template <typename Char, typename StringType>
4625static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
4626 int length = characters.length();
4627 const Char* read_cursor = characters.start();
4628 const Char* end = read_cursor + length;
4629 const int kSpaceForQuotes = 2;
4630 int quoted_length = kSpaceForQuotes;
4631 while (read_cursor < end) {
4632 Char c = *(read_cursor++);
4633 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4634 quoted_length++;
4635 } else {
4636 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
4637 }
4638 }
4639 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4640 Object* new_object;
4641 if (!new_alloc->ToObject(&new_object)) {
4642 return new_alloc;
4643 }
4644 StringType* new_string = StringType::cast(new_object);
4645
4646 Char* write_cursor = reinterpret_cast<Char*>(
4647 new_string->address() + SeqAsciiString::kHeaderSize);
4648 *(write_cursor++) = '"';
4649
4650 read_cursor = characters.start();
4651 while (read_cursor < end) {
4652 Char c = *(read_cursor++);
4653 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4654 *(write_cursor++) = c;
4655 } else {
4656 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4657 const char* replacement = JsonQuotes +
4658 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4659 for (int i = 0; i < len; i++) {
4660 *write_cursor++ = *replacement++;
4661 }
4662 }
4663 }
4664 *(write_cursor++) = '"';
4665 return new_string;
4666}
4667
4668
4669template <typename Char, typename StringType>
4670static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4671 int length = characters.length();
4672 Counters::quote_json_char_count.Increment(length);
4673 const int kSpaceForQuotes = 2;
4674 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4675 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
4676 return SlowQuoteJsonString<Char, StringType>(characters);
4677 }
4678
4679 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4680 Object* new_object;
4681 if (!new_alloc->ToObject(&new_object)) {
4682 return new_alloc;
4683 }
4684 if (!Heap::new_space()->Contains(new_object)) {
4685 // Even if our string is small enough to fit in new space we still have to
4686 // handle it being allocated in old space as may happen in the third
4687 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4688 // CEntryStub::GenerateCore.
4689 return SlowQuoteJsonString<Char, StringType>(characters);
4690 }
4691 StringType* new_string = StringType::cast(new_object);
4692 ASSERT(Heap::new_space()->Contains(new_string));
4693
4694 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4695 Char* write_cursor = reinterpret_cast<Char*>(
4696 new_string->address() + SeqAsciiString::kHeaderSize);
4697 *(write_cursor++) = '"';
4698
4699 const Char* read_cursor = characters.start();
4700 const Char* end = read_cursor + length;
4701 while (read_cursor < end) {
4702 Char c = *(read_cursor++);
4703 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4704 *(write_cursor++) = c;
4705 } else {
4706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4707 const char* replacement = JsonQuotes +
4708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4709 write_cursor[0] = replacement[0];
4710 if (len > 1) {
4711 write_cursor[1] = replacement[1];
4712 if (len > 2) {
4713 ASSERT(len == 6);
4714 write_cursor[2] = replacement[2];
4715 write_cursor[3] = replacement[3];
4716 write_cursor[4] = replacement[4];
4717 write_cursor[5] = replacement[5];
4718 }
4719 }
4720 write_cursor += len;
4721 }
4722 }
4723 *(write_cursor++) = '"';
4724
4725 int final_length = static_cast<int>(
4726 write_cursor - reinterpret_cast<Char*>(
4727 new_string->address() + SeqAsciiString::kHeaderSize));
4728 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4729 final_length);
4730 return new_string;
4731}
4732
4733
4734static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4735 NoHandleAllocation ha;
4736 CONVERT_CHECKED(String, str, args[0]);
4737 if (!str->IsFlat()) {
4738 MaybeObject* try_flatten = str->TryFlatten();
4739 Object* flat;
4740 if (!try_flatten->ToObject(&flat)) {
4741 return try_flatten;
4742 }
4743 str = String::cast(flat);
4744 ASSERT(str->IsFlat());
4745 }
4746 if (str->IsTwoByteRepresentation()) {
4747 return QuoteJsonString<uc16, SeqTwoByteString>(str->ToUC16Vector());
4748 } else {
4749 return QuoteJsonString<char, SeqAsciiString>(str->ToAsciiVector());
4750 }
4751}
4752
4753
4754
John Reck59135872010-11-02 12:39:01 -07004755static MaybeObject* Runtime_StringParseInt(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004756 NoHandleAllocation ha;
4757
4758 CONVERT_CHECKED(String, s, args[0]);
Steve Blockd0582a62009-12-15 09:54:21 +00004759 CONVERT_SMI_CHECKED(radix, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00004760
Steve Block6ded16b2010-05-10 14:33:55 +01004761 s->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004762
Steve Block6ded16b2010-05-10 14:33:55 +01004763 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4764 double value = StringToInt(s, radix);
4765 return Heap::NumberFromDouble(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00004766}
4767
4768
John Reck59135872010-11-02 12:39:01 -07004769static MaybeObject* Runtime_StringParseFloat(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004770 NoHandleAllocation ha;
4771 CONVERT_CHECKED(String, str, args[0]);
4772
4773 // ECMA-262 section 15.1.2.3, empty string is NaN
4774 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4775
4776 // Create a number object from the value.
4777 return Heap::NumberFromDouble(value);
4778}
4779
4780
4781static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4782static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4783
4784
4785template <class Converter>
John Reck59135872010-11-02 12:39:01 -07004786MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4787 String* s,
4788 int length,
4789 int input_string_length,
4790 unibrow::Mapping<Converter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004791 // We try this twice, once with the assumption that the result is no longer
4792 // than the input and, if that assumption breaks, again with the exact
4793 // length. This may not be pretty, but it is nicer than what was here before
4794 // and I hereby claim my vaffel-is.
4795 //
4796 // Allocate the resulting string.
4797 //
4798 // NOTE: This assumes that the upper/lower case of an ascii
4799 // character is also ascii. This is currently the case, but it
4800 // might break in the future if we implement more context and locale
4801 // dependent upper/lower conversions.
John Reck59135872010-11-02 12:39:01 -07004802 Object* o;
4803 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4804 ? Heap::AllocateRawAsciiString(length)
4805 : Heap::AllocateRawTwoByteString(length);
4806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004808 String* result = String::cast(o);
4809 bool has_changed_character = false;
4810
4811 // Convert all characters to upper case, assuming that they will fit
4812 // in the buffer
4813 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
4814 buffer->Reset(s);
4815 unibrow::uchar chars[Converter::kMaxWidth];
4816 // We can assume that the string is not empty
4817 uc32 current = buffer->GetNext();
4818 for (int i = 0; i < length;) {
4819 bool has_next = buffer->has_more();
4820 uc32 next = has_next ? buffer->GetNext() : 0;
4821 int char_length = mapping->get(current, next, chars);
4822 if (char_length == 0) {
4823 // The case conversion of this character is the character itself.
4824 result->Set(i, current);
4825 i++;
4826 } else if (char_length == 1) {
4827 // Common case: converting the letter resulted in one character.
4828 ASSERT(static_cast<uc32>(chars[0]) != current);
4829 result->Set(i, chars[0]);
4830 has_changed_character = true;
4831 i++;
4832 } else if (length == input_string_length) {
4833 // We've assumed that the result would be as long as the
4834 // input but here is a character that converts to several
4835 // characters. No matter, we calculate the exact length
4836 // of the result and try the whole thing again.
4837 //
4838 // Note that this leaves room for optimization. We could just
4839 // memcpy what we already have to the result string. Also,
4840 // the result string is the last object allocated we could
4841 // "realloc" it and probably, in the vast majority of cases,
4842 // extend the existing string to be able to hold the full
4843 // result.
4844 int next_length = 0;
4845 if (has_next) {
4846 next_length = mapping->get(next, 0, chars);
4847 if (next_length == 0) next_length = 1;
4848 }
4849 int current_length = i + char_length + next_length;
4850 while (buffer->has_more()) {
4851 current = buffer->GetNext();
4852 // NOTE: we use 0 as the next character here because, while
4853 // the next character may affect what a character converts to,
4854 // it does not in any case affect the length of what it convert
4855 // to.
4856 int char_length = mapping->get(current, 0, chars);
4857 if (char_length == 0) char_length = 1;
4858 current_length += char_length;
4859 if (current_length > Smi::kMaxValue) {
4860 Top::context()->mark_out_of_memory();
4861 return Failure::OutOfMemoryException();
4862 }
4863 }
4864 // Try again with the real length.
4865 return Smi::FromInt(current_length);
4866 } else {
4867 for (int j = 0; j < char_length; j++) {
4868 result->Set(i, chars[j]);
4869 i++;
4870 }
4871 has_changed_character = true;
4872 }
4873 current = next;
4874 }
4875 if (has_changed_character) {
4876 return result;
4877 } else {
4878 // If we didn't actually change anything in doing the conversion
4879 // we simple return the result and let the converted string
4880 // become garbage; there is no reason to keep two identical strings
4881 // alive.
4882 return s;
4883 }
4884}
4885
4886
Steve Block6ded16b2010-05-10 14:33:55 +01004887namespace {
4888
John Reck59135872010-11-02 12:39:01 -07004889static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4890
4891
4892// Given a word and two range boundaries returns a word with high bit
4893// set in every byte iff the corresponding input byte was strictly in
4894// the range (m, n). All the other bits in the result are cleared.
4895// This function is only useful when it can be inlined and the
4896// boundaries are statically known.
4897// Requires: all bytes in the input word and the boundaries must be
4898// ascii (less than 0x7F).
4899static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4900 // Every byte in an ascii string is less than or equal to 0x7F.
4901 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4902 // Use strict inequalities since in edge cases the function could be
4903 // further simplified.
4904 ASSERT(0 < m && m < n && n < 0x7F);
4905 // Has high bit set in every w byte less than n.
4906 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4907 // Has high bit set in every w byte greater than m.
4908 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4909 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4910}
4911
4912
4913enum AsciiCaseConversion {
4914 ASCII_TO_LOWER,
4915 ASCII_TO_UPPER
4916};
4917
4918
4919template <AsciiCaseConversion dir>
4920struct FastAsciiConverter {
4921 static bool Convert(char* dst, char* src, int length) {
4922#ifdef DEBUG
4923 char* saved_dst = dst;
4924 char* saved_src = src;
4925#endif
4926 // We rely on the distance between upper and lower case letters
4927 // being a known power of 2.
4928 ASSERT('a' - 'A' == (1 << 5));
4929 // Boundaries for the range of input characters than require conversion.
4930 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4931 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4932 bool changed = false;
4933 char* const limit = src + length;
4934#ifdef V8_HOST_CAN_READ_UNALIGNED
4935 // Process the prefix of the input that requires no conversion one
4936 // (machine) word at a time.
4937 while (src <= limit - sizeof(uintptr_t)) {
4938 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4939 if (AsciiRangeMask(w, lo, hi) != 0) {
4940 changed = true;
4941 break;
4942 }
4943 *reinterpret_cast<uintptr_t*>(dst) = w;
4944 src += sizeof(uintptr_t);
4945 dst += sizeof(uintptr_t);
4946 }
4947 // Process the remainder of the input performing conversion when
4948 // required one word at a time.
4949 while (src <= limit - sizeof(uintptr_t)) {
4950 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4951 uintptr_t m = AsciiRangeMask(w, lo, hi);
4952 // The mask has high (7th) bit set in every byte that needs
4953 // conversion and we know that the distance between cases is
4954 // 1 << 5.
4955 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4956 src += sizeof(uintptr_t);
4957 dst += sizeof(uintptr_t);
4958 }
4959#endif
4960 // Process the last few bytes of the input (or the whole input if
4961 // unaligned access is not supported).
4962 while (src < limit) {
4963 char c = *src;
4964 if (lo < c && c < hi) {
4965 c ^= (1 << 5);
4966 changed = true;
4967 }
4968 *dst = c;
4969 ++src;
4970 ++dst;
4971 }
4972#ifdef DEBUG
4973 CheckConvert(saved_dst, saved_src, length, changed);
4974#endif
4975 return changed;
4976 }
4977
4978#ifdef DEBUG
4979 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4980 bool expected_changed = false;
4981 for (int i = 0; i < length; i++) {
4982 if (dst[i] == src[i]) continue;
4983 expected_changed = true;
4984 if (dir == ASCII_TO_LOWER) {
4985 ASSERT('A' <= src[i] && src[i] <= 'Z');
4986 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4987 } else {
4988 ASSERT(dir == ASCII_TO_UPPER);
4989 ASSERT('a' <= src[i] && src[i] <= 'z');
4990 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4991 }
4992 }
4993 ASSERT(expected_changed == changed);
4994 }
4995#endif
4996};
4997
4998
Steve Block6ded16b2010-05-10 14:33:55 +01004999struct ToLowerTraits {
5000 typedef unibrow::ToLowercase UnibrowConverter;
5001
John Reck59135872010-11-02 12:39:01 -07005002 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01005003};
5004
5005
5006struct ToUpperTraits {
5007 typedef unibrow::ToUppercase UnibrowConverter;
5008
John Reck59135872010-11-02 12:39:01 -07005009 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
Steve Block6ded16b2010-05-10 14:33:55 +01005010};
5011
5012} // namespace
5013
5014
5015template <typename ConvertTraits>
John Reck59135872010-11-02 12:39:01 -07005016MUST_USE_RESULT static MaybeObject* ConvertCase(
Steve Block6ded16b2010-05-10 14:33:55 +01005017 Arguments args,
5018 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005019 NoHandleAllocation ha;
Steve Blocka7e24c12009-10-30 11:49:00 +00005020 CONVERT_CHECKED(String, s, args[0]);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005021 s = s->TryFlattenGetString();
Steve Blocka7e24c12009-10-30 11:49:00 +00005022
Steve Block6ded16b2010-05-10 14:33:55 +01005023 const int length = s->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00005024 // Assume that the string is not empty; we need this assumption later
Steve Block6ded16b2010-05-10 14:33:55 +01005025 if (length == 0) return s;
5026
5027 // Simpler handling of ascii strings.
5028 //
5029 // NOTE: This assumes that the upper/lower case of an ascii
5030 // character is also ascii. This is currently the case, but it
5031 // might break in the future if we implement more context and locale
5032 // dependent upper/lower conversions.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005033 if (s->IsSeqAsciiString()) {
John Reck59135872010-11-02 12:39:01 -07005034 Object* o;
5035 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5036 if (!maybe_o->ToObject(&o)) return maybe_o;
5037 }
Steve Block6ded16b2010-05-10 14:33:55 +01005038 SeqAsciiString* result = SeqAsciiString::cast(o);
John Reck59135872010-11-02 12:39:01 -07005039 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005040 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
Steve Block6ded16b2010-05-10 14:33:55 +01005041 return has_changed_character ? result : s;
5042 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005043
John Reck59135872010-11-02 12:39:01 -07005044 Object* answer;
5045 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5046 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5047 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005048 if (answer->IsSmi()) {
5049 // Retry with correct length.
John Reck59135872010-11-02 12:39:01 -07005050 { MaybeObject* maybe_answer =
5051 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5052 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5053 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005054 }
John Reck59135872010-11-02 12:39:01 -07005055 return answer;
Steve Blocka7e24c12009-10-30 11:49:00 +00005056}
5057
5058
John Reck59135872010-11-02 12:39:01 -07005059static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01005060 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
Steve Blocka7e24c12009-10-30 11:49:00 +00005061}
5062
5063
John Reck59135872010-11-02 12:39:01 -07005064static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01005065 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
Steve Blocka7e24c12009-10-30 11:49:00 +00005066}
5067
Steve Block6ded16b2010-05-10 14:33:55 +01005068
Steve Block3ce2e202009-11-05 08:53:23 +00005069static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5070 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5071}
5072
Steve Block6ded16b2010-05-10 14:33:55 +01005073
John Reck59135872010-11-02 12:39:01 -07005074static MaybeObject* Runtime_StringTrim(Arguments args) {
Steve Block3ce2e202009-11-05 08:53:23 +00005075 NoHandleAllocation ha;
5076 ASSERT(args.length() == 3);
5077
5078 CONVERT_CHECKED(String, s, args[0]);
5079 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5080 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5081
Steve Block6ded16b2010-05-10 14:33:55 +01005082 s->TryFlatten();
Steve Block3ce2e202009-11-05 08:53:23 +00005083 int length = s->length();
5084
5085 int left = 0;
5086 if (trimLeft) {
5087 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5088 left++;
5089 }
5090 }
5091
5092 int right = length;
5093 if (trimRight) {
5094 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5095 right--;
5096 }
5097 }
Steve Blockd0582a62009-12-15 09:54:21 +00005098 return s->SubString(left, right);
Steve Block3ce2e202009-11-05 08:53:23 +00005099}
Steve Blocka7e24c12009-10-30 11:49:00 +00005100
Steve Block6ded16b2010-05-10 14:33:55 +01005101
Ben Murdochf87a2032010-10-22 12:50:53 +01005102template <typename SubjectChar, typename PatternChar>
5103void FindStringIndices(Vector<const SubjectChar> subject,
5104 Vector<const PatternChar> pattern,
Steve Block6ded16b2010-05-10 14:33:55 +01005105 ZoneList<int>* indices,
5106 unsigned int limit) {
5107 ASSERT(limit > 0);
5108 // Collect indices of pattern in subject, and the end-of-string index.
5109 // Stop after finding at most limit values.
Ben Murdochf87a2032010-10-22 12:50:53 +01005110 StringSearch<PatternChar, SubjectChar> search(pattern);
5111 int pattern_length = pattern.length();
5112 int index = 0;
5113 while (limit > 0) {
5114 index = search.Search(subject, index);
5115 if (index < 0) return;
5116 indices->Add(index);
5117 index += pattern_length;
5118 limit--;
Steve Block6ded16b2010-05-10 14:33:55 +01005119 }
5120}
5121
Steve Block6ded16b2010-05-10 14:33:55 +01005122
John Reck59135872010-11-02 12:39:01 -07005123static MaybeObject* Runtime_StringSplit(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01005124 ASSERT(args.length() == 3);
5125 HandleScope handle_scope;
5126 CONVERT_ARG_CHECKED(String, subject, 0);
5127 CONVERT_ARG_CHECKED(String, pattern, 1);
5128 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5129
5130 int subject_length = subject->length();
5131 int pattern_length = pattern->length();
5132 RUNTIME_ASSERT(pattern_length > 0);
5133
5134 // The limit can be very large (0xffffffffu), but since the pattern
5135 // isn't empty, we can never create more parts than ~half the length
5136 // of the subject.
5137
5138 if (!subject->IsFlat()) FlattenString(subject);
5139
5140 static const int kMaxInitialListCapacity = 16;
5141
5142 ZoneScope scope(DELETE_ON_EXIT);
5143
5144 // Find (up to limit) indices of separator and end-of-string in subject
5145 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5146 ZoneList<int> indices(initial_capacity);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005147 if (!pattern->IsFlat()) FlattenString(pattern);
5148
5149 // No allocation block.
5150 {
Steve Block6ded16b2010-05-10 14:33:55 +01005151 AssertNoAllocation nogc;
5152 if (subject->IsAsciiRepresentation()) {
5153 Vector<const char> subject_vector = subject->ToAsciiVector();
5154 if (pattern->IsAsciiRepresentation()) {
5155 FindStringIndices(subject_vector,
5156 pattern->ToAsciiVector(),
5157 &indices,
5158 limit);
5159 } else {
5160 FindStringIndices(subject_vector,
5161 pattern->ToUC16Vector(),
5162 &indices,
5163 limit);
5164 }
5165 } else {
5166 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5167 if (pattern->IsAsciiRepresentation()) {
5168 FindStringIndices(subject_vector,
5169 pattern->ToAsciiVector(),
5170 &indices,
5171 limit);
5172 } else {
5173 FindStringIndices(subject_vector,
5174 pattern->ToUC16Vector(),
5175 &indices,
5176 limit);
5177 }
5178 }
5179 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005180
Steve Block6ded16b2010-05-10 14:33:55 +01005181 if (static_cast<uint32_t>(indices.length()) < limit) {
5182 indices.Add(subject_length);
5183 }
Steve Block6ded16b2010-05-10 14:33:55 +01005184
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005185 // The list indices now contains the end of each part to create.
Steve Block6ded16b2010-05-10 14:33:55 +01005186
5187 // Create JSArray of substrings separated by separator.
5188 int part_count = indices.length();
5189
5190 Handle<JSArray> result = Factory::NewJSArray(part_count);
5191 result->set_length(Smi::FromInt(part_count));
5192
5193 ASSERT(result->HasFastElements());
5194
5195 if (part_count == 1 && indices.at(0) == subject_length) {
5196 FixedArray::cast(result->elements())->set(0, *subject);
5197 return *result;
5198 }
5199
5200 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5201 int part_start = 0;
5202 for (int i = 0; i < part_count; i++) {
5203 HandleScope local_loop_handle;
5204 int part_end = indices.at(i);
5205 Handle<String> substring =
5206 Factory::NewSubString(subject, part_start, part_end);
5207 elements->set(i, *substring);
5208 part_start = part_end + pattern_length;
5209 }
5210
5211 return *result;
5212}
5213
5214
5215// Copies ascii characters to the given fixed array looking up
5216// one-char strings in the cache. Gives up on the first char that is
5217// not in the cache and fills the remainder with smi zeros. Returns
5218// the length of the successfully copied prefix.
5219static int CopyCachedAsciiCharsToArray(const char* chars,
5220 FixedArray* elements,
5221 int length) {
5222 AssertNoAllocation nogc;
5223 FixedArray* ascii_cache = Heap::single_character_string_cache();
5224 Object* undefined = Heap::undefined_value();
5225 int i;
5226 for (i = 0; i < length; ++i) {
5227 Object* value = ascii_cache->get(chars[i]);
5228 if (value == undefined) break;
5229 ASSERT(!Heap::InNewSpace(value));
5230 elements->set(i, value, SKIP_WRITE_BARRIER);
5231 }
5232 if (i < length) {
5233 ASSERT(Smi::FromInt(0) == 0);
5234 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5235 }
5236#ifdef DEBUG
5237 for (int j = 0; j < length; ++j) {
5238 Object* element = elements->get(j);
5239 ASSERT(element == Smi::FromInt(0) ||
5240 (element->IsString() && String::cast(element)->LooksValid()));
5241 }
5242#endif
5243 return i;
5244}
5245
5246
5247// Converts a String to JSArray.
5248// For example, "foo" => ["f", "o", "o"].
John Reck59135872010-11-02 12:39:01 -07005249static MaybeObject* Runtime_StringToArray(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01005250 HandleScope scope;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005251 ASSERT(args.length() == 2);
Steve Block6ded16b2010-05-10 14:33:55 +01005252 CONVERT_ARG_CHECKED(String, s, 0);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005253 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Steve Block6ded16b2010-05-10 14:33:55 +01005254
5255 s->TryFlatten();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005256 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
Steve Block6ded16b2010-05-10 14:33:55 +01005257
5258 Handle<FixedArray> elements;
5259 if (s->IsFlat() && s->IsAsciiRepresentation()) {
John Reck59135872010-11-02 12:39:01 -07005260 Object* obj;
5261 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5262 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5263 }
Steve Block6ded16b2010-05-10 14:33:55 +01005264 elements = Handle<FixedArray>(FixedArray::cast(obj));
5265
5266 Vector<const char> chars = s->ToAsciiVector();
5267 // Note, this will initialize all elements (not only the prefix)
5268 // to prevent GC from seeing partially initialized array.
5269 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5270 *elements,
5271 length);
5272
5273 for (int i = num_copied_from_cache; i < length; ++i) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005274 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5275 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01005276 }
5277 } else {
5278 elements = Factory::NewFixedArray(length);
5279 for (int i = 0; i < length; ++i) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005280 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5281 elements->set(i, *str);
Steve Block6ded16b2010-05-10 14:33:55 +01005282 }
5283 }
5284
5285#ifdef DEBUG
5286 for (int i = 0; i < length; ++i) {
5287 ASSERT(String::cast(elements->get(i))->length() == 1);
5288 }
5289#endif
5290
5291 return *Factory::NewJSArrayWithElements(elements);
5292}
5293
5294
John Reck59135872010-11-02 12:39:01 -07005295static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005296 NoHandleAllocation ha;
5297 ASSERT(args.length() == 1);
5298 CONVERT_CHECKED(String, value, args[0]);
5299 return value->ToObject();
5300}
5301
5302
Steve Blocka7e24c12009-10-30 11:49:00 +00005303bool Runtime::IsUpperCaseChar(uint16_t ch) {
5304 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5305 int char_length = to_upper_mapping.get(ch, 0, chars);
5306 return char_length == 0;
5307}
5308
5309
John Reck59135872010-11-02 12:39:01 -07005310static MaybeObject* Runtime_NumberToString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005311 NoHandleAllocation ha;
5312 ASSERT(args.length() == 1);
5313
5314 Object* number = args[0];
5315 RUNTIME_ASSERT(number->IsNumber());
5316
5317 return Heap::NumberToString(number);
5318}
5319
5320
John Reck59135872010-11-02 12:39:01 -07005321static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01005322 NoHandleAllocation ha;
5323 ASSERT(args.length() == 1);
5324
5325 Object* number = args[0];
5326 RUNTIME_ASSERT(number->IsNumber());
5327
5328 return Heap::NumberToString(number, false);
5329}
5330
5331
John Reck59135872010-11-02 12:39:01 -07005332static MaybeObject* Runtime_NumberToInteger(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005333 NoHandleAllocation ha;
5334 ASSERT(args.length() == 1);
5335
Steve Block6ded16b2010-05-10 14:33:55 +01005336 CONVERT_DOUBLE_CHECKED(number, args[0]);
5337
5338 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5339 if (number > 0 && number <= Smi::kMaxValue) {
5340 return Smi::FromInt(static_cast<int>(number));
5341 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005342 return Heap::NumberFromDouble(DoubleToInteger(number));
5343}
5344
5345
John Reck59135872010-11-02 12:39:01 -07005346static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005347 NoHandleAllocation ha;
5348 ASSERT(args.length() == 1);
5349
5350 CONVERT_DOUBLE_CHECKED(number, args[0]);
5351
5352 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5353 if (number > 0 && number <= Smi::kMaxValue) {
5354 return Smi::FromInt(static_cast<int>(number));
5355 }
5356
5357 double double_value = DoubleToInteger(number);
5358 // Map both -0 and +0 to +0.
5359 if (double_value == 0) double_value = 0;
5360
5361 return Heap::NumberFromDouble(double_value);
5362}
5363
5364
John Reck59135872010-11-02 12:39:01 -07005365static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005366 NoHandleAllocation ha;
5367 ASSERT(args.length() == 1);
5368
Steve Block6ded16b2010-05-10 14:33:55 +01005369 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
Steve Blocka7e24c12009-10-30 11:49:00 +00005370 return Heap::NumberFromUint32(number);
5371}
5372
5373
John Reck59135872010-11-02 12:39:01 -07005374static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005375 NoHandleAllocation ha;
5376 ASSERT(args.length() == 1);
5377
Steve Block6ded16b2010-05-10 14:33:55 +01005378 CONVERT_DOUBLE_CHECKED(number, args[0]);
5379
5380 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5381 if (number > 0 && number <= Smi::kMaxValue) {
5382 return Smi::FromInt(static_cast<int>(number));
5383 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005384 return Heap::NumberFromInt32(DoubleToInt32(number));
5385}
5386
5387
5388// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5389// a small integer.
John Reck59135872010-11-02 12:39:01 -07005390static MaybeObject* Runtime_NumberToSmi(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005391 NoHandleAllocation ha;
5392 ASSERT(args.length() == 1);
5393
5394 Object* obj = args[0];
5395 if (obj->IsSmi()) {
5396 return obj;
5397 }
5398 if (obj->IsHeapNumber()) {
5399 double value = HeapNumber::cast(obj)->value();
5400 int int_value = FastD2I(value);
5401 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5402 return Smi::FromInt(int_value);
5403 }
5404 }
5405 return Heap::nan_value();
5406}
5407
5408
Ben Murdochb0fe1622011-05-05 13:52:32 +01005409static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5410 NoHandleAllocation ha;
5411 ASSERT(args.length() == 0);
5412 return Heap::AllocateHeapNumber(0);
5413}
5414
5415
John Reck59135872010-11-02 12:39:01 -07005416static MaybeObject* Runtime_NumberAdd(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005417 NoHandleAllocation ha;
5418 ASSERT(args.length() == 2);
5419
5420 CONVERT_DOUBLE_CHECKED(x, args[0]);
5421 CONVERT_DOUBLE_CHECKED(y, args[1]);
Leon Clarkeac952652010-07-15 11:15:24 +01005422 return Heap::NumberFromDouble(x + y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005423}
5424
5425
John Reck59135872010-11-02 12:39:01 -07005426static MaybeObject* Runtime_NumberSub(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005427 NoHandleAllocation ha;
5428 ASSERT(args.length() == 2);
5429
5430 CONVERT_DOUBLE_CHECKED(x, args[0]);
5431 CONVERT_DOUBLE_CHECKED(y, args[1]);
Leon Clarkeac952652010-07-15 11:15:24 +01005432 return Heap::NumberFromDouble(x - y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005433}
5434
5435
John Reck59135872010-11-02 12:39:01 -07005436static MaybeObject* Runtime_NumberMul(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005437 NoHandleAllocation ha;
5438 ASSERT(args.length() == 2);
5439
5440 CONVERT_DOUBLE_CHECKED(x, args[0]);
5441 CONVERT_DOUBLE_CHECKED(y, args[1]);
Leon Clarkeac952652010-07-15 11:15:24 +01005442 return Heap::NumberFromDouble(x * y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005443}
5444
5445
John Reck59135872010-11-02 12:39:01 -07005446static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005447 NoHandleAllocation ha;
5448 ASSERT(args.length() == 1);
5449
5450 CONVERT_DOUBLE_CHECKED(x, args[0]);
Leon Clarkeac952652010-07-15 11:15:24 +01005451 return Heap::NumberFromDouble(-x);
Steve Blocka7e24c12009-10-30 11:49:00 +00005452}
5453
5454
John Reck59135872010-11-02 12:39:01 -07005455static MaybeObject* Runtime_NumberAlloc(Arguments args) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01005456 NoHandleAllocation ha;
5457 ASSERT(args.length() == 0);
5458
5459 return Heap::NumberFromDouble(9876543210.0);
5460}
5461
5462
John Reck59135872010-11-02 12:39:01 -07005463static MaybeObject* Runtime_NumberDiv(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005464 NoHandleAllocation ha;
5465 ASSERT(args.length() == 2);
5466
5467 CONVERT_DOUBLE_CHECKED(x, args[0]);
5468 CONVERT_DOUBLE_CHECKED(y, args[1]);
Steve Block6ded16b2010-05-10 14:33:55 +01005469 return Heap::NumberFromDouble(x / y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005470}
5471
5472
John Reck59135872010-11-02 12:39:01 -07005473static MaybeObject* Runtime_NumberMod(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005474 NoHandleAllocation ha;
5475 ASSERT(args.length() == 2);
5476
5477 CONVERT_DOUBLE_CHECKED(x, args[0]);
5478 CONVERT_DOUBLE_CHECKED(y, args[1]);
5479
Steve Block3ce2e202009-11-05 08:53:23 +00005480 x = modulo(x, y);
Steve Block6ded16b2010-05-10 14:33:55 +01005481 // NumberFromDouble may return a Smi instead of a Number object
5482 return Heap::NumberFromDouble(x);
Steve Blocka7e24c12009-10-30 11:49:00 +00005483}
5484
5485
John Reck59135872010-11-02 12:39:01 -07005486static MaybeObject* Runtime_StringAdd(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005487 NoHandleAllocation ha;
5488 ASSERT(args.length() == 2);
5489 CONVERT_CHECKED(String, str1, args[0]);
5490 CONVERT_CHECKED(String, str2, args[1]);
Steve Blockd0582a62009-12-15 09:54:21 +00005491 Counters::string_add_runtime.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005492 return Heap::AllocateConsString(str1, str2);
5493}
5494
5495
Steve Block6ded16b2010-05-10 14:33:55 +01005496template <typename sinkchar>
Steve Blocka7e24c12009-10-30 11:49:00 +00005497static inline void StringBuilderConcatHelper(String* special,
5498 sinkchar* sink,
5499 FixedArray* fixed_array,
5500 int array_length) {
5501 int position = 0;
5502 for (int i = 0; i < array_length; i++) {
5503 Object* element = fixed_array->get(i);
5504 if (element->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005505 // Smi encoding of position and length.
Steve Blocka7e24c12009-10-30 11:49:00 +00005506 int encoded_slice = Smi::cast(element)->value();
Steve Blockd0582a62009-12-15 09:54:21 +00005507 int pos;
5508 int len;
5509 if (encoded_slice > 0) {
5510 // Position and length encoded in one smi.
5511 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5512 len = StringBuilderSubstringLength::decode(encoded_slice);
5513 } else {
5514 // Position and length encoded in two smis.
5515 Object* obj = fixed_array->get(++i);
5516 ASSERT(obj->IsSmi());
5517 pos = Smi::cast(obj)->value();
5518 len = -encoded_slice;
5519 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005520 String::WriteToFlat(special,
5521 sink + position,
5522 pos,
5523 pos + len);
5524 position += len;
5525 } else {
5526 String* string = String::cast(element);
5527 int element_length = string->length();
5528 String::WriteToFlat(string, sink + position, 0, element_length);
5529 position += element_length;
5530 }
5531 }
5532}
5533
5534
John Reck59135872010-11-02 12:39:01 -07005535static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005536 NoHandleAllocation ha;
Leon Clarkee46be812010-01-19 14:06:41 +00005537 ASSERT(args.length() == 3);
Steve Blocka7e24c12009-10-30 11:49:00 +00005538 CONVERT_CHECKED(JSArray, array, args[0]);
Leon Clarkee46be812010-01-19 14:06:41 +00005539 if (!args[1]->IsSmi()) {
5540 Top::context()->mark_out_of_memory();
5541 return Failure::OutOfMemoryException();
5542 }
5543 int array_length = Smi::cast(args[1])->value();
5544 CONVERT_CHECKED(String, special, args[2]);
Steve Blockd0582a62009-12-15 09:54:21 +00005545
5546 // This assumption is used by the slice encoding in one or two smis.
5547 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5548
Steve Blocka7e24c12009-10-30 11:49:00 +00005549 int special_length = special->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00005550 if (!array->HasFastElements()) {
5551 return Top::Throw(Heap::illegal_argument_symbol());
5552 }
5553 FixedArray* fixed_array = FixedArray::cast(array->elements());
5554 if (fixed_array->length() < array_length) {
5555 array_length = fixed_array->length();
5556 }
5557
5558 if (array_length == 0) {
5559 return Heap::empty_string();
5560 } else if (array_length == 1) {
5561 Object* first = fixed_array->get(0);
5562 if (first->IsString()) return first;
5563 }
5564
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005565 bool ascii = special->HasOnlyAsciiChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005566 int position = 0;
5567 for (int i = 0; i < array_length; i++) {
Steve Block6ded16b2010-05-10 14:33:55 +01005568 int increment = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00005569 Object* elt = fixed_array->get(i);
5570 if (elt->IsSmi()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005571 // Smi encoding of position and length.
Steve Block6ded16b2010-05-10 14:33:55 +01005572 int smi_value = Smi::cast(elt)->value();
5573 int pos;
5574 int len;
5575 if (smi_value > 0) {
Steve Blockd0582a62009-12-15 09:54:21 +00005576 // Position and length encoded in one smi.
Steve Block6ded16b2010-05-10 14:33:55 +01005577 pos = StringBuilderSubstringPosition::decode(smi_value);
5578 len = StringBuilderSubstringLength::decode(smi_value);
Steve Blockd0582a62009-12-15 09:54:21 +00005579 } else {
5580 // Position and length encoded in two smis.
Steve Block6ded16b2010-05-10 14:33:55 +01005581 len = -smi_value;
5582 // Get the position and check that it is a positive smi.
Steve Blockd0582a62009-12-15 09:54:21 +00005583 i++;
5584 if (i >= array_length) {
5585 return Top::Throw(Heap::illegal_argument_symbol());
5586 }
Steve Block6ded16b2010-05-10 14:33:55 +01005587 Object* next_smi = fixed_array->get(i);
5588 if (!next_smi->IsSmi()) {
5589 return Top::Throw(Heap::illegal_argument_symbol());
5590 }
5591 pos = Smi::cast(next_smi)->value();
5592 if (pos < 0) {
Steve Blockd0582a62009-12-15 09:54:21 +00005593 return Top::Throw(Heap::illegal_argument_symbol());
5594 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005595 }
Steve Block6ded16b2010-05-10 14:33:55 +01005596 ASSERT(pos >= 0);
5597 ASSERT(len >= 0);
5598 if (pos > special_length || len > special_length - pos) {
5599 return Top::Throw(Heap::illegal_argument_symbol());
5600 }
5601 increment = len;
Steve Blocka7e24c12009-10-30 11:49:00 +00005602 } else if (elt->IsString()) {
5603 String* element = String::cast(elt);
5604 int element_length = element->length();
Leon Clarkee46be812010-01-19 14:06:41 +00005605 increment = element_length;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01005606 if (ascii && !element->HasOnlyAsciiChars()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005607 ascii = false;
5608 }
5609 } else {
5610 return Top::Throw(Heap::illegal_argument_symbol());
5611 }
Leon Clarkee46be812010-01-19 14:06:41 +00005612 if (increment > String::kMaxLength - position) {
Steve Block3ce2e202009-11-05 08:53:23 +00005613 Top::context()->mark_out_of_memory();
5614 return Failure::OutOfMemoryException();
5615 }
Leon Clarkee46be812010-01-19 14:06:41 +00005616 position += increment;
Steve Blocka7e24c12009-10-30 11:49:00 +00005617 }
5618
5619 int length = position;
5620 Object* object;
5621
5622 if (ascii) {
John Reck59135872010-11-02 12:39:01 -07005623 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5624 if (!maybe_object->ToObject(&object)) return maybe_object;
5625 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005626 SeqAsciiString* answer = SeqAsciiString::cast(object);
5627 StringBuilderConcatHelper(special,
5628 answer->GetChars(),
5629 fixed_array,
5630 array_length);
5631 return answer;
5632 } else {
John Reck59135872010-11-02 12:39:01 -07005633 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5634 if (!maybe_object->ToObject(&object)) return maybe_object;
5635 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005636 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5637 StringBuilderConcatHelper(special,
5638 answer->GetChars(),
5639 fixed_array,
5640 array_length);
5641 return answer;
5642 }
5643}
5644
5645
John Reck59135872010-11-02 12:39:01 -07005646static MaybeObject* Runtime_NumberOr(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005647 NoHandleAllocation ha;
5648 ASSERT(args.length() == 2);
5649
5650 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5651 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5652 return Heap::NumberFromInt32(x | y);
5653}
5654
5655
John Reck59135872010-11-02 12:39:01 -07005656static MaybeObject* Runtime_NumberAnd(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005657 NoHandleAllocation ha;
5658 ASSERT(args.length() == 2);
5659
5660 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5661 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5662 return Heap::NumberFromInt32(x & y);
5663}
5664
5665
John Reck59135872010-11-02 12:39:01 -07005666static MaybeObject* Runtime_NumberXor(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005667 NoHandleAllocation ha;
5668 ASSERT(args.length() == 2);
5669
5670 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5671 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5672 return Heap::NumberFromInt32(x ^ y);
5673}
5674
5675
John Reck59135872010-11-02 12:39:01 -07005676static MaybeObject* Runtime_NumberNot(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005677 NoHandleAllocation ha;
5678 ASSERT(args.length() == 1);
5679
5680 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5681 return Heap::NumberFromInt32(~x);
5682}
5683
5684
John Reck59135872010-11-02 12:39:01 -07005685static MaybeObject* Runtime_NumberShl(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005686 NoHandleAllocation ha;
5687 ASSERT(args.length() == 2);
5688
5689 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5690 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5691 return Heap::NumberFromInt32(x << (y & 0x1f));
5692}
5693
5694
John Reck59135872010-11-02 12:39:01 -07005695static MaybeObject* Runtime_NumberShr(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005696 NoHandleAllocation ha;
5697 ASSERT(args.length() == 2);
5698
5699 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5700 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5701 return Heap::NumberFromUint32(x >> (y & 0x1f));
5702}
5703
5704
John Reck59135872010-11-02 12:39:01 -07005705static MaybeObject* Runtime_NumberSar(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005706 NoHandleAllocation ha;
5707 ASSERT(args.length() == 2);
5708
5709 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5710 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5711 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5712}
5713
5714
John Reck59135872010-11-02 12:39:01 -07005715static MaybeObject* Runtime_NumberEquals(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005716 NoHandleAllocation ha;
5717 ASSERT(args.length() == 2);
5718
5719 CONVERT_DOUBLE_CHECKED(x, args[0]);
5720 CONVERT_DOUBLE_CHECKED(y, args[1]);
5721 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5722 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5723 if (x == y) return Smi::FromInt(EQUAL);
5724 Object* result;
5725 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5726 result = Smi::FromInt(EQUAL);
5727 } else {
5728 result = Smi::FromInt(NOT_EQUAL);
5729 }
5730 return result;
5731}
5732
5733
John Reck59135872010-11-02 12:39:01 -07005734static MaybeObject* Runtime_StringEquals(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005735 NoHandleAllocation ha;
5736 ASSERT(args.length() == 2);
5737
5738 CONVERT_CHECKED(String, x, args[0]);
5739 CONVERT_CHECKED(String, y, args[1]);
5740
5741 bool not_equal = !x->Equals(y);
5742 // This is slightly convoluted because the value that signifies
5743 // equality is 0 and inequality is 1 so we have to negate the result
5744 // from String::Equals.
5745 ASSERT(not_equal == 0 || not_equal == 1);
5746 STATIC_CHECK(EQUAL == 0);
5747 STATIC_CHECK(NOT_EQUAL == 1);
5748 return Smi::FromInt(not_equal);
5749}
5750
5751
John Reck59135872010-11-02 12:39:01 -07005752static MaybeObject* Runtime_NumberCompare(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 3);
5755
5756 CONVERT_DOUBLE_CHECKED(x, args[0]);
5757 CONVERT_DOUBLE_CHECKED(y, args[1]);
5758 if (isnan(x) || isnan(y)) return args[2];
5759 if (x == y) return Smi::FromInt(EQUAL);
5760 if (isless(x, y)) return Smi::FromInt(LESS);
5761 return Smi::FromInt(GREATER);
5762}
5763
5764
5765// Compare two Smis as if they were converted to strings and then
5766// compared lexicographically.
John Reck59135872010-11-02 12:39:01 -07005767static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005768 NoHandleAllocation ha;
5769 ASSERT(args.length() == 2);
5770
5771 // Arrays for the individual characters of the two Smis. Smis are
5772 // 31 bit integers and 10 decimal digits are therefore enough.
5773 static int x_elms[10];
5774 static int y_elms[10];
5775
5776 // Extract the integer values from the Smis.
5777 CONVERT_CHECKED(Smi, x, args[0]);
5778 CONVERT_CHECKED(Smi, y, args[1]);
5779 int x_value = x->value();
5780 int y_value = y->value();
5781
5782 // If the integers are equal so are the string representations.
5783 if (x_value == y_value) return Smi::FromInt(EQUAL);
5784
5785 // If one of the integers are zero the normal integer order is the
5786 // same as the lexicographic order of the string representations.
5787 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5788
5789 // If only one of the integers is negative the negative number is
5790 // smallest because the char code of '-' is less than the char code
5791 // of any digit. Otherwise, we make both values positive.
5792 if (x_value < 0 || y_value < 0) {
5793 if (y_value >= 0) return Smi::FromInt(LESS);
5794 if (x_value >= 0) return Smi::FromInt(GREATER);
5795 x_value = -x_value;
5796 y_value = -y_value;
5797 }
5798
5799 // Convert the integers to arrays of their decimal digits.
5800 int x_index = 0;
5801 int y_index = 0;
5802 while (x_value > 0) {
5803 x_elms[x_index++] = x_value % 10;
5804 x_value /= 10;
5805 }
5806 while (y_value > 0) {
5807 y_elms[y_index++] = y_value % 10;
5808 y_value /= 10;
5809 }
5810
5811 // Loop through the arrays of decimal digits finding the first place
5812 // where they differ.
5813 while (--x_index >= 0 && --y_index >= 0) {
5814 int diff = x_elms[x_index] - y_elms[y_index];
5815 if (diff != 0) return Smi::FromInt(diff);
5816 }
5817
5818 // If one array is a suffix of the other array, the longest array is
5819 // the representation of the largest of the Smis in the
5820 // lexicographic ordering.
5821 return Smi::FromInt(x_index - y_index);
5822}
5823
5824
Steve Block6ded16b2010-05-10 14:33:55 +01005825static Object* StringInputBufferCompare(String* x, String* y) {
5826 static StringInputBuffer bufx;
5827 static StringInputBuffer bufy;
5828 bufx.Reset(x);
5829 bufy.Reset(y);
5830 while (bufx.has_more() && bufy.has_more()) {
5831 int d = bufx.GetNext() - bufy.GetNext();
5832 if (d < 0) return Smi::FromInt(LESS);
5833 else if (d > 0) return Smi::FromInt(GREATER);
5834 }
5835
5836 // x is (non-trivial) prefix of y:
5837 if (bufy.has_more()) return Smi::FromInt(LESS);
5838 // y is prefix of x:
5839 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5840}
5841
5842
5843static Object* FlatStringCompare(String* x, String* y) {
5844 ASSERT(x->IsFlat());
5845 ASSERT(y->IsFlat());
5846 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5847 int prefix_length = x->length();
5848 if (y->length() < prefix_length) {
5849 prefix_length = y->length();
5850 equal_prefix_result = Smi::FromInt(GREATER);
5851 } else if (y->length() > prefix_length) {
5852 equal_prefix_result = Smi::FromInt(LESS);
5853 }
5854 int r;
5855 if (x->IsAsciiRepresentation()) {
5856 Vector<const char> x_chars = x->ToAsciiVector();
5857 if (y->IsAsciiRepresentation()) {
5858 Vector<const char> y_chars = y->ToAsciiVector();
5859 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5860 } else {
5861 Vector<const uc16> y_chars = y->ToUC16Vector();
5862 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5863 }
5864 } else {
5865 Vector<const uc16> x_chars = x->ToUC16Vector();
5866 if (y->IsAsciiRepresentation()) {
5867 Vector<const char> y_chars = y->ToAsciiVector();
5868 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5869 } else {
5870 Vector<const uc16> y_chars = y->ToUC16Vector();
5871 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5872 }
5873 }
5874 Object* result;
5875 if (r == 0) {
5876 result = equal_prefix_result;
5877 } else {
5878 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5879 }
5880 ASSERT(result == StringInputBufferCompare(x, y));
5881 return result;
5882}
5883
5884
John Reck59135872010-11-02 12:39:01 -07005885static MaybeObject* Runtime_StringCompare(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 2);
5888
5889 CONVERT_CHECKED(String, x, args[0]);
5890 CONVERT_CHECKED(String, y, args[1]);
5891
Leon Clarkee46be812010-01-19 14:06:41 +00005892 Counters::string_compare_runtime.Increment();
5893
Steve Blocka7e24c12009-10-30 11:49:00 +00005894 // A few fast case tests before we flatten.
5895 if (x == y) return Smi::FromInt(EQUAL);
5896 if (y->length() == 0) {
5897 if (x->length() == 0) return Smi::FromInt(EQUAL);
5898 return Smi::FromInt(GREATER);
5899 } else if (x->length() == 0) {
5900 return Smi::FromInt(LESS);
5901 }
5902
5903 int d = x->Get(0) - y->Get(0);
5904 if (d < 0) return Smi::FromInt(LESS);
5905 else if (d > 0) return Smi::FromInt(GREATER);
5906
John Reck59135872010-11-02 12:39:01 -07005907 Object* obj;
5908 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5909 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5910 }
5911 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5912 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5913 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005914
Steve Block6ded16b2010-05-10 14:33:55 +01005915 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5916 : StringInputBufferCompare(x, y);
Steve Blocka7e24c12009-10-30 11:49:00 +00005917}
5918
5919
John Reck59135872010-11-02 12:39:01 -07005920static MaybeObject* Runtime_Math_acos(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005921 NoHandleAllocation ha;
5922 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005923 Counters::math_acos.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005924
5925 CONVERT_DOUBLE_CHECKED(x, args[0]);
5926 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
5927}
5928
5929
John Reck59135872010-11-02 12:39:01 -07005930static MaybeObject* Runtime_Math_asin(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005933 Counters::math_asin.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005934
5935 CONVERT_DOUBLE_CHECKED(x, args[0]);
5936 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
5937}
5938
5939
John Reck59135872010-11-02 12:39:01 -07005940static MaybeObject* Runtime_Math_atan(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005943 Counters::math_atan.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005944
5945 CONVERT_DOUBLE_CHECKED(x, args[0]);
5946 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
5947}
5948
5949
John Reck59135872010-11-02 12:39:01 -07005950static MaybeObject* Runtime_Math_atan2(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005951 NoHandleAllocation ha;
5952 ASSERT(args.length() == 2);
Andrei Popescu402d9372010-02-26 13:31:12 +00005953 Counters::math_atan2.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005954
5955 CONVERT_DOUBLE_CHECKED(x, args[0]);
5956 CONVERT_DOUBLE_CHECKED(y, args[1]);
5957 double result;
5958 if (isinf(x) && isinf(y)) {
5959 // Make sure that the result in case of two infinite arguments
5960 // is a multiple of Pi / 4. The sign of the result is determined
5961 // by the first argument (x) and the sign of the second argument
5962 // determines the multiplier: one or three.
5963 static double kPiDividedBy4 = 0.78539816339744830962;
5964 int multiplier = (x < 0) ? -1 : 1;
5965 if (y < 0) multiplier *= 3;
5966 result = multiplier * kPiDividedBy4;
5967 } else {
5968 result = atan2(x, y);
5969 }
5970 return Heap::AllocateHeapNumber(result);
5971}
5972
5973
John Reck59135872010-11-02 12:39:01 -07005974static MaybeObject* Runtime_Math_ceil(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005975 NoHandleAllocation ha;
5976 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005977 Counters::math_ceil.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005978
5979 CONVERT_DOUBLE_CHECKED(x, args[0]);
5980 return Heap::NumberFromDouble(ceiling(x));
5981}
5982
5983
John Reck59135872010-11-02 12:39:01 -07005984static MaybeObject* Runtime_Math_cos(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005985 NoHandleAllocation ha;
5986 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005987 Counters::math_cos.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005988
5989 CONVERT_DOUBLE_CHECKED(x, args[0]);
5990 return TranscendentalCache::Get(TranscendentalCache::COS, x);
5991}
5992
5993
John Reck59135872010-11-02 12:39:01 -07005994static MaybeObject* Runtime_Math_exp(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005995 NoHandleAllocation ha;
5996 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00005997 Counters::math_exp.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00005998
5999 CONVERT_DOUBLE_CHECKED(x, args[0]);
6000 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
6001}
6002
6003
John Reck59135872010-11-02 12:39:01 -07006004static MaybeObject* Runtime_Math_floor(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006005 NoHandleAllocation ha;
6006 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006007 Counters::math_floor.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006008
6009 CONVERT_DOUBLE_CHECKED(x, args[0]);
6010 return Heap::NumberFromDouble(floor(x));
6011}
6012
6013
John Reck59135872010-11-02 12:39:01 -07006014static MaybeObject* Runtime_Math_log(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006015 NoHandleAllocation ha;
6016 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006017 Counters::math_log.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006018
6019 CONVERT_DOUBLE_CHECKED(x, args[0]);
6020 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
6021}
6022
6023
John Reck59135872010-11-02 12:39:01 -07006024static MaybeObject* Runtime_Math_pow(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006025 NoHandleAllocation ha;
6026 ASSERT(args.length() == 2);
Andrei Popescu402d9372010-02-26 13:31:12 +00006027 Counters::math_pow.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006028
6029 CONVERT_DOUBLE_CHECKED(x, args[0]);
6030
6031 // If the second argument is a smi, it is much faster to call the
6032 // custom powi() function than the generic pow().
6033 if (args[1]->IsSmi()) {
6034 int y = Smi::cast(args[1])->value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006035 return Heap::NumberFromDouble(power_double_int(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00006036 }
6037
6038 CONVERT_DOUBLE_CHECKED(y, args[1]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006039 return Heap::AllocateHeapNumber(power_double_double(x, y));
Steve Blocka7e24c12009-10-30 11:49:00 +00006040}
6041
Steve Block6ded16b2010-05-10 14:33:55 +01006042// Fast version of Math.pow if we know that y is not an integer and
6043// y is not -0.5 or 0.5. Used as slowcase from codegen.
John Reck59135872010-11-02 12:39:01 -07006044static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01006045 NoHandleAllocation ha;
6046 ASSERT(args.length() == 2);
6047 CONVERT_DOUBLE_CHECKED(x, args[0]);
6048 CONVERT_DOUBLE_CHECKED(y, args[1]);
6049 if (y == 0) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006050 return Smi::FromInt(1);
Steve Block6ded16b2010-05-10 14:33:55 +01006051 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006052 return Heap::nan_value();
Steve Block6ded16b2010-05-10 14:33:55 +01006053 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006054 return Heap::AllocateHeapNumber(pow(x, y));
Steve Block6ded16b2010-05-10 14:33:55 +01006055 }
6056}
Steve Blocka7e24c12009-10-30 11:49:00 +00006057
Steve Block6ded16b2010-05-10 14:33:55 +01006058
John Reck59135872010-11-02 12:39:01 -07006059static MaybeObject* Runtime_RoundNumber(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006060 NoHandleAllocation ha;
6061 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006062 Counters::math_round.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006063
Steve Block6ded16b2010-05-10 14:33:55 +01006064 if (!args[0]->IsHeapNumber()) {
6065 // Must be smi. Return the argument unchanged for all the other types
6066 // to make fuzz-natives test happy.
6067 return args[0];
6068 }
6069
6070 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6071
6072 double value = number->value();
6073 int exponent = number->get_exponent();
6074 int sign = number->get_sign();
6075
6076 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6077 // should be rounded to 2^30, which is not smi.
6078 if (!sign && exponent <= kSmiValueSize - 3) {
6079 return Smi::FromInt(static_cast<int>(value + 0.5));
6080 }
6081
6082 // If the magnitude is big enough, there's no place for fraction part. If we
6083 // try to add 0.5 to this number, 1.0 will be added instead.
6084 if (exponent >= 52) {
6085 return number;
6086 }
6087
6088 if (sign && value >= -0.5) return Heap::minus_zero_value();
6089
6090 // Do not call NumberFromDouble() to avoid extra checks.
6091 return Heap::AllocateHeapNumber(floor(value + 0.5));
Steve Blocka7e24c12009-10-30 11:49:00 +00006092}
6093
6094
John Reck59135872010-11-02 12:39:01 -07006095static MaybeObject* Runtime_Math_sin(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006096 NoHandleAllocation ha;
6097 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006098 Counters::math_sin.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006099
6100 CONVERT_DOUBLE_CHECKED(x, args[0]);
6101 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
6102}
6103
6104
John Reck59135872010-11-02 12:39:01 -07006105static MaybeObject* Runtime_Math_sqrt(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006106 NoHandleAllocation ha;
6107 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006108 Counters::math_sqrt.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006109
6110 CONVERT_DOUBLE_CHECKED(x, args[0]);
6111 return Heap::AllocateHeapNumber(sqrt(x));
6112}
6113
6114
John Reck59135872010-11-02 12:39:01 -07006115static MaybeObject* Runtime_Math_tan(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006116 NoHandleAllocation ha;
6117 ASSERT(args.length() == 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00006118 Counters::math_tan.Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00006119
6120 CONVERT_DOUBLE_CHECKED(x, args[0]);
6121 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
6122}
6123
6124
Steve Block6ded16b2010-05-10 14:33:55 +01006125static int MakeDay(int year, int month, int day) {
6126 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6127 181, 212, 243, 273, 304, 334};
6128 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6129 182, 213, 244, 274, 305, 335};
6130
6131 year += month / 12;
6132 month %= 12;
6133 if (month < 0) {
6134 year--;
6135 month += 12;
6136 }
6137
6138 ASSERT(month >= 0);
6139 ASSERT(month < 12);
6140
6141 // year_delta is an arbitrary number such that:
6142 // a) year_delta = -1 (mod 400)
6143 // b) year + year_delta > 0 for years in the range defined by
6144 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6145 // Jan 1 1970. This is required so that we don't run into integer
6146 // division of negative numbers.
6147 // c) there shouldn't be an overflow for 32-bit integers in the following
6148 // operations.
6149 static const int year_delta = 399999;
6150 static const int base_day = 365 * (1970 + year_delta) +
6151 (1970 + year_delta) / 4 -
6152 (1970 + year_delta) / 100 +
6153 (1970 + year_delta) / 400;
6154
6155 int year1 = year + year_delta;
6156 int day_from_year = 365 * year1 +
6157 year1 / 4 -
6158 year1 / 100 +
6159 year1 / 400 -
6160 base_day;
6161
6162 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
6163 return day_from_year + day_from_month[month] + day - 1;
6164 }
6165
6166 return day_from_year + day_from_month_leap[month] + day - 1;
6167}
6168
6169
John Reck59135872010-11-02 12:39:01 -07006170static MaybeObject* Runtime_DateMakeDay(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01006171 NoHandleAllocation ha;
6172 ASSERT(args.length() == 3);
6173
6174 CONVERT_SMI_CHECKED(year, args[0]);
6175 CONVERT_SMI_CHECKED(month, args[1]);
6176 CONVERT_SMI_CHECKED(date, args[2]);
6177
6178 return Smi::FromInt(MakeDay(year, month, date));
6179}
6180
6181
6182static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6183static const int kDaysIn4Years = 4 * 365 + 1;
6184static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6185static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6186static const int kDays1970to2000 = 30 * 365 + 7;
6187static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6188 kDays1970to2000;
6189static const int kYearsOffset = 400000;
6190
6191static const char kDayInYear[] = {
6192 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6193 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6194 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6195 22, 23, 24, 25, 26, 27, 28,
6196 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6197 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6198 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6199 22, 23, 24, 25, 26, 27, 28, 29, 30,
6200 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6201 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6202 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6203 22, 23, 24, 25, 26, 27, 28, 29, 30,
6204 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6205 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6206 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6207 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6208 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6209 22, 23, 24, 25, 26, 27, 28, 29, 30,
6210 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6211 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6212 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6213 22, 23, 24, 25, 26, 27, 28, 29, 30,
6214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6216
6217 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6218 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6220 22, 23, 24, 25, 26, 27, 28,
6221 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6222 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6223 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6224 22, 23, 24, 25, 26, 27, 28, 29, 30,
6225 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6226 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6227 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6228 22, 23, 24, 25, 26, 27, 28, 29, 30,
6229 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6230 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6231 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6232 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6233 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6234 22, 23, 24, 25, 26, 27, 28, 29, 30,
6235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6236 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6237 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6238 22, 23, 24, 25, 26, 27, 28, 29, 30,
6239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6241
6242 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6243 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6244 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6245 22, 23, 24, 25, 26, 27, 28, 29,
6246 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6247 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6248 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6249 22, 23, 24, 25, 26, 27, 28, 29, 30,
6250 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6251 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6252 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6253 22, 23, 24, 25, 26, 27, 28, 29, 30,
6254 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6255 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6256 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6257 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6258 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6259 22, 23, 24, 25, 26, 27, 28, 29, 30,
6260 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6261 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6262 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6263 22, 23, 24, 25, 26, 27, 28, 29, 30,
6264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6266
6267 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6268 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6269 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6270 22, 23, 24, 25, 26, 27, 28,
6271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6272 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6273 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6274 22, 23, 24, 25, 26, 27, 28, 29, 30,
6275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6278 22, 23, 24, 25, 26, 27, 28, 29, 30,
6279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6282 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6284 22, 23, 24, 25, 26, 27, 28, 29, 30,
6285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6286 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6288 22, 23, 24, 25, 26, 27, 28, 29, 30,
6289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6291
6292static const char kMonthInYear[] = {
6293 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,
6294 0, 0, 0, 0, 0, 0,
6295 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,
6296 1, 1, 1,
6297 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,
6298 2, 2, 2, 2, 2, 2,
6299 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,
6300 3, 3, 3, 3, 3,
6301 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,
6302 4, 4, 4, 4, 4, 4,
6303 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,
6304 5, 5, 5, 5, 5,
6305 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,
6306 6, 6, 6, 6, 6, 6,
6307 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,
6308 7, 7, 7, 7, 7, 7,
6309 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,
6310 8, 8, 8, 8, 8,
6311 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,
6312 9, 9, 9, 9, 9, 9,
6313 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6314 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6315 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6316 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6317
6318 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,
6319 0, 0, 0, 0, 0, 0,
6320 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,
6321 1, 1, 1,
6322 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,
6323 2, 2, 2, 2, 2, 2,
6324 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,
6325 3, 3, 3, 3, 3,
6326 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,
6327 4, 4, 4, 4, 4, 4,
6328 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,
6329 5, 5, 5, 5, 5,
6330 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,
6331 6, 6, 6, 6, 6, 6,
6332 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,
6333 7, 7, 7, 7, 7, 7,
6334 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,
6335 8, 8, 8, 8, 8,
6336 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,
6337 9, 9, 9, 9, 9, 9,
6338 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6339 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6340 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6341 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6342
6343 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,
6344 0, 0, 0, 0, 0, 0,
6345 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,
6346 1, 1, 1, 1,
6347 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,
6348 2, 2, 2, 2, 2, 2,
6349 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,
6350 3, 3, 3, 3, 3,
6351 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,
6352 4, 4, 4, 4, 4, 4,
6353 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,
6354 5, 5, 5, 5, 5,
6355 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,
6356 6, 6, 6, 6, 6, 6,
6357 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,
6358 7, 7, 7, 7, 7, 7,
6359 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,
6360 8, 8, 8, 8, 8,
6361 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,
6362 9, 9, 9, 9, 9, 9,
6363 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6364 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6365 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6366 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6367
6368 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,
6369 0, 0, 0, 0, 0, 0,
6370 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,
6371 1, 1, 1,
6372 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,
6373 2, 2, 2, 2, 2, 2,
6374 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,
6375 3, 3, 3, 3, 3,
6376 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,
6377 4, 4, 4, 4, 4, 4,
6378 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,
6379 5, 5, 5, 5, 5,
6380 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,
6381 6, 6, 6, 6, 6, 6,
6382 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,
6383 7, 7, 7, 7, 7, 7,
6384 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,
6385 8, 8, 8, 8, 8,
6386 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,
6387 9, 9, 9, 9, 9, 9,
6388 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6389 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6390 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6391 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6392
6393
6394// This function works for dates from 1970 to 2099.
6395static inline void DateYMDFromTimeAfter1970(int date,
6396 int& year, int& month, int& day) {
6397#ifdef DEBUG
6398 int save_date = date; // Need this for ASSERT in the end.
6399#endif
6400
6401 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6402 date %= kDaysIn4Years;
6403
6404 month = kMonthInYear[date];
6405 day = kDayInYear[date];
6406
6407 ASSERT(MakeDay(year, month, day) == save_date);
6408}
6409
6410
6411static inline void DateYMDFromTimeSlow(int date,
6412 int& year, int& month, int& day) {
6413#ifdef DEBUG
6414 int save_date = date; // Need this for ASSERT in the end.
6415#endif
6416
6417 date += kDaysOffset;
6418 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6419 date %= kDaysIn400Years;
6420
6421 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6422
6423 date--;
6424 int yd1 = date / kDaysIn100Years;
6425 date %= kDaysIn100Years;
6426 year += 100 * yd1;
6427
6428 date++;
6429 int yd2 = date / kDaysIn4Years;
6430 date %= kDaysIn4Years;
6431 year += 4 * yd2;
6432
6433 date--;
6434 int yd3 = date / 365;
6435 date %= 365;
6436 year += yd3;
6437
6438 bool is_leap = (!yd1 || yd2) && !yd3;
6439
6440 ASSERT(date >= -1);
6441 ASSERT(is_leap || (date >= 0));
6442 ASSERT((date < 365) || (is_leap && (date < 366)));
6443 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6444 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6445 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
6446
6447 if (is_leap) {
6448 day = kDayInYear[2*365 + 1 + date];
6449 month = kMonthInYear[2*365 + 1 + date];
6450 } else {
6451 day = kDayInYear[date];
6452 month = kMonthInYear[date];
6453 }
6454
6455 ASSERT(MakeDay(year, month, day) == save_date);
6456}
6457
6458
6459static inline void DateYMDFromTime(int date,
6460 int& year, int& month, int& day) {
6461 if (date >= 0 && date < 32 * kDaysIn4Years) {
6462 DateYMDFromTimeAfter1970(date, year, month, day);
6463 } else {
6464 DateYMDFromTimeSlow(date, year, month, day);
6465 }
6466}
6467
6468
John Reck59135872010-11-02 12:39:01 -07006469static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01006470 NoHandleAllocation ha;
6471 ASSERT(args.length() == 2);
6472
6473 CONVERT_DOUBLE_CHECKED(t, args[0]);
6474 CONVERT_CHECKED(JSArray, res_array, args[1]);
6475
6476 int year, month, day;
6477 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6478
Iain Merrick75681382010-08-19 15:07:18 +01006479 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6480 FixedArray* elms = FixedArray::cast(res_array->elements());
6481 RUNTIME_ASSERT(elms->length() == 3);
6482
6483 elms->set(0, Smi::FromInt(year));
6484 elms->set(1, Smi::FromInt(month));
6485 elms->set(2, Smi::FromInt(day));
Steve Block6ded16b2010-05-10 14:33:55 +01006486
6487 return Heap::undefined_value();
6488}
6489
6490
John Reck59135872010-11-02 12:39:01 -07006491static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 3);
6494
6495 JSFunction* callee = JSFunction::cast(args[0]);
6496 Object** parameters = reinterpret_cast<Object**>(args[1]);
6497 const int length = Smi::cast(args[2])->value();
6498
John Reck59135872010-11-02 12:39:01 -07006499 Object* result;
6500 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6501 if (!maybe_result->ToObject(&result)) return maybe_result;
6502 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006503 // Allocate the elements if needed.
6504 if (length > 0) {
6505 // Allocate the fixed array.
John Reck59135872010-11-02 12:39:01 -07006506 Object* obj;
6507 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6508 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6509 }
Leon Clarke4515c472010-02-03 11:58:03 +00006510
6511 AssertNoAllocation no_gc;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006512 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6513 array->set_map(Heap::fixed_array_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006514 array->set_length(length);
Leon Clarke4515c472010-02-03 11:58:03 +00006515
6516 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00006517 for (int i = 0; i < length; i++) {
6518 array->set(i, *--parameters, mode);
6519 }
Steve Blockd0582a62009-12-15 09:54:21 +00006520 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00006521 }
6522 return result;
6523}
6524
6525
John Reck59135872010-11-02 12:39:01 -07006526static MaybeObject* Runtime_NewClosure(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006527 HandleScope scope;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006528 ASSERT(args.length() == 3);
Steve Block3ce2e202009-11-05 08:53:23 +00006529 CONVERT_ARG_CHECKED(Context, context, 0);
Steve Block6ded16b2010-05-10 14:33:55 +01006530 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006531 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
Steve Blocka7e24c12009-10-30 11:49:00 +00006532
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006533 // Allocate global closures in old space and allocate local closures
6534 // in new space. Additionally pretenure closures that are assigned
6535 // directly to properties.
6536 pretenure = pretenure || (context->global_context() == *context);
6537 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +00006538 Handle<JSFunction> result =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006539 Factory::NewFunctionFromSharedFunctionInfo(shared,
6540 context,
6541 pretenure_flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00006542 return *result;
6543}
6544
John Reck59135872010-11-02 12:39:01 -07006545static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01006546 HandleScope scope;
6547 ASSERT(args.length() == 2);
6548 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6549 CONVERT_ARG_CHECKED(JSArray, params, 1);
6550
Ben Murdochbb769b22010-08-11 14:56:33 +01006551 RUNTIME_ASSERT(params->HasFastElements());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01006552 FixedArray* fixed = FixedArray::cast(params->elements());
6553
Ben Murdochbb769b22010-08-11 14:56:33 +01006554 int fixed_length = Smi::cast(params->length())->value();
6555 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6556 for (int i = 0; i < fixed_length; i++) {
Kristian Monsen50ef84f2010-07-29 15:18:00 +01006557 Handle<Object> val = Handle<Object>(fixed->get(i));
6558 param_data[i] = val.location();
6559 }
6560
Ben Murdochbb769b22010-08-11 14:56:33 +01006561 bool exception = false;
Kristian Monsen50ef84f2010-07-29 15:18:00 +01006562 Handle<Object> result = Execution::New(
Ben Murdochbb769b22010-08-11 14:56:33 +01006563 function, fixed_length, *param_data, &exception);
6564 if (exception) {
6565 return Failure::Exception();
6566 }
6567 ASSERT(!result.is_null());
Kristian Monsen50ef84f2010-07-29 15:18:00 +01006568 return *result;
6569}
6570
Steve Blocka7e24c12009-10-30 11:49:00 +00006571
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006572static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006573 Handle<Object> prototype = Factory::null_value();
6574 if (function->has_instance_prototype()) {
6575 prototype = Handle<Object>(function->instance_prototype());
6576 }
6577 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006578 ConstructStubCompiler compiler;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08006579 MaybeObject* code = compiler.CompileConstructStub(*function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006580 if (!code->IsFailure()) {
John Reck59135872010-11-02 12:39:01 -07006581 function->shared()->set_construct_stub(
6582 Code::cast(code->ToObjectUnchecked()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006583 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006584 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006585}
6586
6587
John Reck59135872010-11-02 12:39:01 -07006588static MaybeObject* Runtime_NewObject(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006589 HandleScope scope;
6590 ASSERT(args.length() == 1);
6591
6592 Handle<Object> constructor = args.at<Object>(0);
6593
6594 // If the constructor isn't a proper function we throw a type error.
6595 if (!constructor->IsJSFunction()) {
6596 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6597 Handle<Object> type_error =
6598 Factory::NewTypeError("not_constructor", arguments);
6599 return Top::Throw(*type_error);
6600 }
6601
6602 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
Steve Block6ded16b2010-05-10 14:33:55 +01006603
6604 // If function should not have prototype, construction is not allowed. In this
6605 // case generated code bailouts here, since function has no initial_map.
6606 if (!function->should_have_prototype()) {
6607 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6608 Handle<Object> type_error =
6609 Factory::NewTypeError("not_constructor", arguments);
6610 return Top::Throw(*type_error);
6611 }
6612
Steve Blocka7e24c12009-10-30 11:49:00 +00006613#ifdef ENABLE_DEBUGGER_SUPPORT
6614 // Handle stepping into constructors if step into is active.
6615 if (Debug::StepInActive()) {
6616 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
6617 }
6618#endif
6619
6620 if (function->has_initial_map()) {
6621 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
6622 // The 'Function' function ignores the receiver object when
6623 // called using 'new' and creates a new JSFunction object that
6624 // is returned. The receiver object is only used for error
6625 // reporting if an error occurs when constructing the new
6626 // JSFunction. Factory::NewJSObject() should not be used to
6627 // allocate JSFunctions since it does not properly initialize
6628 // the shared part of the function. Since the receiver is
6629 // ignored anyway, we use the global object as the receiver
6630 // instead of a new JSFunction object. This way, errors are
6631 // reported the same way whether or not 'Function' is called
6632 // using 'new'.
6633 return Top::context()->global();
6634 }
6635 }
6636
Ben Murdochb0fe1622011-05-05 13:52:32 +01006637 // The function should be compiled for the optimization hints to be
6638 // available. We cannot use EnsureCompiled because that forces a
6639 // compilation through the shared function info which makes it
6640 // impossible for us to optimize.
Leon Clarke4515c472010-02-03 11:58:03 +00006641 Handle<SharedFunctionInfo> shared(function->shared());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006642 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +00006643
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006644 if (!function->has_initial_map() &&
6645 shared->IsInobjectSlackTrackingInProgress()) {
6646 // The tracking is already in progress for another function. We can only
6647 // track one initial_map at a time, so we force the completion before the
6648 // function is called as a constructor for the first time.
6649 shared->CompleteInobjectSlackTracking();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006650 }
6651
6652 bool first_allocation = !shared->live_objects_may_exist();
Steve Blocka7e24c12009-10-30 11:49:00 +00006653 Handle<JSObject> result = Factory::NewJSObject(function);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006654 // Delay setting the stub if inobject slack tracking is in progress.
6655 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6656 TrySettingInlineConstructStub(function);
Steve Blocka7e24c12009-10-30 11:49:00 +00006657 }
6658
6659 Counters::constructed_objects.Increment();
6660 Counters::constructed_objects_runtime.Increment();
6661
6662 return *result;
6663}
6664
6665
John Reck59135872010-11-02 12:39:01 -07006666static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006667 HandleScope scope;
6668 ASSERT(args.length() == 1);
6669
6670 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6671 function->shared()->CompleteInobjectSlackTracking();
6672 TrySettingInlineConstructStub(function);
6673
6674 return Heap::undefined_value();
6675}
6676
6677
John Reck59135872010-11-02 12:39:01 -07006678static MaybeObject* Runtime_LazyCompile(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006679 HandleScope scope;
6680 ASSERT(args.length() == 1);
6681
6682 Handle<JSFunction> function = args.at<JSFunction>(0);
6683#ifdef DEBUG
Iain Merrick75681382010-08-19 15:07:18 +01006684 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006685 PrintF("[lazy: ");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006686 function->PrintName();
Steve Blocka7e24c12009-10-30 11:49:00 +00006687 PrintF("]\n");
6688 }
6689#endif
6690
6691 // Compile the target function. Here we compile using CompileLazyInLoop in
6692 // order to get the optimized version. This helps code like delta-blue
6693 // that calls performance-critical routines through constructors. A
6694 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6695 // direct call. Since the in-loop tracking takes place through CallICs
6696 // this means that things called through constructors are never known to
6697 // be in loops. We compile them as if they are in loops here just in case.
6698 ASSERT(!function->is_compiled());
Ben Murdochf87a2032010-10-22 12:50:53 +01006699 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006700 return Failure::Exception();
6701 }
6702
Ben Murdochb0fe1622011-05-05 13:52:32 +01006703 // All done. Return the compiled code.
6704 ASSERT(function->is_compiled());
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 return function->code();
6706}
6707
6708
Ben Murdochb0fe1622011-05-05 13:52:32 +01006709static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6710 HandleScope scope;
6711 ASSERT(args.length() == 1);
6712 Handle<JSFunction> function = args.at<JSFunction>(0);
6713 // If the function is not optimizable or debugger is active continue using the
6714 // code from the full compiler.
6715 if (!function->shared()->code()->optimizable() ||
6716 Debug::has_break_points()) {
6717 function->ReplaceCode(function->shared()->code());
6718 return function->code();
6719 }
6720 if (CompileOptimized(function, AstNode::kNoNumber)) {
6721 return function->code();
6722 }
6723 function->ReplaceCode(function->shared()->code());
6724 return Failure::Exception();
6725}
6726
6727
6728static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6729 HandleScope scope;
6730 ASSERT(args.length() == 1);
6731 RUNTIME_ASSERT(args[0]->IsSmi());
6732 Deoptimizer::BailoutType type =
6733 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6734 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6735 ASSERT(Heap::IsAllocationAllowed());
6736 int frames = deoptimizer->output_count();
6737
6738 JavaScriptFrameIterator it;
6739 JavaScriptFrame* frame = NULL;
6740 for (int i = 0; i < frames; i++) {
6741 if (i != 0) it.Advance();
6742 frame = it.frame();
6743 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6744 }
6745 delete deoptimizer;
6746
6747 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6748 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6749 Handle<Object> arguments;
6750 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01006751 if (frame->GetExpression(i) == Heap::arguments_marker()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006752 if (arguments.is_null()) {
6753 // FunctionGetArguments can't throw an exception, so cast away the
6754 // doubt with an assert.
6755 arguments = Handle<Object>(
6756 Accessors::FunctionGetArguments(*function,
6757 NULL)->ToObjectUnchecked());
6758 ASSERT(*arguments != Heap::null_value());
6759 ASSERT(*arguments != Heap::undefined_value());
6760 }
6761 frame->SetExpression(i, *arguments);
6762 }
6763 }
6764
6765 CompilationCache::MarkForLazyOptimizing(function);
6766 if (type == Deoptimizer::EAGER) {
6767 RUNTIME_ASSERT(function->IsOptimized());
6768 } else {
6769 RUNTIME_ASSERT(!function->IsOptimized());
6770 }
6771
6772 // Avoid doing too much work when running with --always-opt and keep
6773 // the optimized code around.
6774 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6775 return Heap::undefined_value();
6776 }
6777
6778 // Count the number of optimized activations of the function.
6779 int activations = 0;
6780 while (!it.done()) {
6781 JavaScriptFrame* frame = it.frame();
6782 if (frame->is_optimized() && frame->function() == *function) {
6783 activations++;
6784 }
6785 it.Advance();
6786 }
6787
6788 // TODO(kasperl): For now, we cannot support removing the optimized
6789 // code when we have recursive invocations of the same function.
6790 if (activations == 0) {
6791 if (FLAG_trace_deopt) {
6792 PrintF("[removing optimized code for: ");
6793 function->PrintName();
6794 PrintF("]\n");
6795 }
6796 function->ReplaceCode(function->shared()->code());
6797 }
6798 return Heap::undefined_value();
6799}
6800
6801
6802static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6803 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6804 delete deoptimizer;
6805 return Heap::undefined_value();
6806}
6807
6808
6809static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6810 HandleScope scope;
6811 ASSERT(args.length() == 1);
6812 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6813 if (!function->IsOptimized()) return Heap::undefined_value();
6814
6815 Deoptimizer::DeoptimizeFunction(*function);
6816
6817 return Heap::undefined_value();
6818}
6819
6820
6821static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6822 HandleScope scope;
6823 ASSERT(args.length() == 1);
6824 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6825
6826 // We're not prepared to handle a function with arguments object.
6827 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6828
6829 // We have hit a back edge in an unoptimized frame for a function that was
6830 // selected for on-stack replacement. Find the unoptimized code object.
6831 Handle<Code> unoptimized(function->shared()->code());
6832 // Keep track of whether we've succeeded in optimizing.
6833 bool succeeded = unoptimized->optimizable();
6834 if (succeeded) {
6835 // If we are trying to do OSR when there are already optimized
6836 // activations of the function, it means (a) the function is directly or
6837 // indirectly recursive and (b) an optimized invocation has been
6838 // deoptimized so that we are currently in an unoptimized activation.
6839 // Check for optimized activations of this function.
6840 JavaScriptFrameIterator it;
6841 while (succeeded && !it.done()) {
6842 JavaScriptFrame* frame = it.frame();
6843 succeeded = !frame->is_optimized() || frame->function() != *function;
6844 it.Advance();
6845 }
6846 }
6847
6848 int ast_id = AstNode::kNoNumber;
6849 if (succeeded) {
6850 // The top JS function is this one, the PC is somewhere in the
6851 // unoptimized code.
6852 JavaScriptFrameIterator it;
6853 JavaScriptFrame* frame = it.frame();
6854 ASSERT(frame->function() == *function);
6855 ASSERT(frame->code() == *unoptimized);
6856 ASSERT(unoptimized->contains(frame->pc()));
6857
6858 // Use linear search of the unoptimized code's stack check table to find
6859 // the AST id matching the PC.
6860 Address start = unoptimized->instruction_start();
6861 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6862 Address table_cursor = start + unoptimized->stack_check_table_start();
6863 uint32_t table_length = Memory::uint32_at(table_cursor);
6864 table_cursor += kIntSize;
6865 for (unsigned i = 0; i < table_length; ++i) {
6866 // Table entries are (AST id, pc offset) pairs.
6867 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6868 if (pc_offset == target_pc_offset) {
6869 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6870 break;
6871 }
6872 table_cursor += 2 * kIntSize;
6873 }
6874 ASSERT(ast_id != AstNode::kNoNumber);
6875 if (FLAG_trace_osr) {
6876 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6877 function->PrintName();
6878 PrintF("]\n");
6879 }
6880
6881 // Try to compile the optimized code. A true return value from
6882 // CompileOptimized means that compilation succeeded, not necessarily
6883 // that optimization succeeded.
6884 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6885 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6886 function->code()->deoptimization_data());
6887 if (data->OsrPcOffset()->value() >= 0) {
6888 if (FLAG_trace_osr) {
6889 PrintF("[on-stack replacement offset %d in optimized code]\n",
6890 data->OsrPcOffset()->value());
6891 }
6892 ASSERT(data->OsrAstId()->value() == ast_id);
6893 } else {
6894 // We may never generate the desired OSR entry if we emit an
6895 // early deoptimize.
6896 succeeded = false;
6897 }
6898 } else {
6899 succeeded = false;
6900 }
6901 }
6902
6903 // Revert to the original stack checks in the original unoptimized code.
6904 if (FLAG_trace_osr) {
6905 PrintF("[restoring original stack checks in ");
6906 function->PrintName();
6907 PrintF("]\n");
6908 }
6909 StackCheckStub check_stub;
6910 Handle<Code> check_code = check_stub.GetCode();
6911 Handle<Code> replacement_code(
6912 Builtins::builtin(Builtins::OnStackReplacement));
6913 // Iterate the unoptimized code and revert all the patched stack checks.
6914 for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
6915 !it.done();
6916 it.next()) {
6917 RelocInfo* rinfo = it.rinfo();
6918 if (rinfo->target_address() == replacement_code->entry()) {
6919 Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
6920 }
6921 }
6922
6923 // Allow OSR only at nesting level zero again.
6924 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6925
6926 // If the optimization attempt succeeded, return the AST id tagged as a
6927 // smi. This tells the builtin that we need to translate the unoptimized
6928 // frame to an optimized one.
6929 if (succeeded) {
6930 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6931 return Smi::FromInt(ast_id);
6932 } else {
6933 return Smi::FromInt(-1);
6934 }
6935}
6936
6937
John Reck59135872010-11-02 12:39:01 -07006938static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006939 HandleScope scope;
6940 ASSERT(args.length() == 1);
6941 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6942 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6943}
6944
6945
John Reck59135872010-11-02 12:39:01 -07006946static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006947 HandleScope scope;
6948 ASSERT(args.length() == 1);
6949 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6950 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6951}
6952
6953
John Reck59135872010-11-02 12:39:01 -07006954static MaybeObject* Runtime_NewContext(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006955 NoHandleAllocation ha;
6956 ASSERT(args.length() == 1);
6957
6958 CONVERT_CHECKED(JSFunction, function, args[0]);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006959 int length = function->shared()->scope_info()->NumberOfContextSlots();
John Reck59135872010-11-02 12:39:01 -07006960 Object* result;
6961 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6962 if (!maybe_result->ToObject(&result)) return maybe_result;
6963 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006964
6965 Top::set_context(Context::cast(result));
6966
6967 return result; // non-failure
6968}
6969
John Reck59135872010-11-02 12:39:01 -07006970
6971MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6972 bool is_catch_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006973 // Convert the object to a proper JavaScript object.
6974 Object* js_object = object;
6975 if (!js_object->IsJSObject()) {
John Reck59135872010-11-02 12:39:01 -07006976 MaybeObject* maybe_js_object = js_object->ToObject();
6977 if (!maybe_js_object->ToObject(&js_object)) {
6978 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6979 return maybe_js_object;
6980 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006981 HandleScope scope;
6982 Handle<Object> handle(object);
6983 Handle<Object> result =
6984 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6985 return Top::Throw(*result);
6986 }
6987 }
6988
John Reck59135872010-11-02 12:39:01 -07006989 Object* result;
6990 { MaybeObject* maybe_result =
6991 Heap::AllocateWithContext(Top::context(),
6992 JSObject::cast(js_object),
6993 is_catch_context);
6994 if (!maybe_result->ToObject(&result)) return maybe_result;
6995 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006996
6997 Context* context = Context::cast(result);
6998 Top::set_context(context);
6999
7000 return result;
7001}
7002
7003
John Reck59135872010-11-02 12:39:01 -07007004static MaybeObject* Runtime_PushContext(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007005 NoHandleAllocation ha;
7006 ASSERT(args.length() == 1);
7007 return PushContextHelper(args[0], false);
7008}
7009
7010
John Reck59135872010-11-02 12:39:01 -07007011static MaybeObject* Runtime_PushCatchContext(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007012 NoHandleAllocation ha;
7013 ASSERT(args.length() == 1);
7014 return PushContextHelper(args[0], true);
7015}
7016
7017
John Reck59135872010-11-02 12:39:01 -07007018static MaybeObject* Runtime_LookupContext(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007019 HandleScope scope;
7020 ASSERT(args.length() == 2);
7021
7022 CONVERT_ARG_CHECKED(Context, context, 0);
7023 CONVERT_ARG_CHECKED(String, name, 1);
7024
7025 int index;
7026 PropertyAttributes attributes;
7027 ContextLookupFlags flags = FOLLOW_CHAINS;
7028 Handle<Object> holder =
7029 context->Lookup(name, flags, &index, &attributes);
7030
7031 if (index < 0 && !holder.is_null()) {
7032 ASSERT(holder->IsJSObject());
7033 return *holder;
7034 }
7035
7036 // No intermediate context found. Use global object by default.
7037 return Top::context()->global();
7038}
7039
7040
7041// A mechanism to return a pair of Object pointers in registers (if possible).
7042// How this is achieved is calling convention-dependent.
7043// All currently supported x86 compiles uses calling conventions that are cdecl
7044// variants where a 64-bit value is returned in two 32-bit registers
7045// (edx:eax on ia32, r1:r0 on ARM).
7046// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7047// In Win64 calling convention, a struct of two pointers is returned in memory,
7048// allocated by the caller, and passed as a pointer in a hidden first parameter.
7049#ifdef V8_HOST_ARCH_64_BIT
7050struct ObjectPair {
John Reck59135872010-11-02 12:39:01 -07007051 MaybeObject* x;
7052 MaybeObject* y;
Steve Blocka7e24c12009-10-30 11:49:00 +00007053};
7054
John Reck59135872010-11-02 12:39:01 -07007055static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007056 ObjectPair result = {x, y};
7057 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7058 // In Win64 they are assigned to a hidden first argument.
7059 return result;
7060}
7061#else
7062typedef uint64_t ObjectPair;
John Reck59135872010-11-02 12:39:01 -07007063static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007064 return reinterpret_cast<uint32_t>(x) |
7065 (reinterpret_cast<ObjectPair>(y) << 32);
7066}
7067#endif
7068
7069
John Reck59135872010-11-02 12:39:01 -07007070static inline MaybeObject* Unhole(MaybeObject* x,
7071 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007072 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7073 USE(attributes);
7074 return x->IsTheHole() ? Heap::undefined_value() : x;
7075}
7076
7077
7078static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7079 ASSERT(!holder->IsGlobalObject());
7080 Context* top = Top::context();
7081 // Get the context extension function.
7082 JSFunction* context_extension_function =
7083 top->global_context()->context_extension_function();
7084 // If the holder isn't a context extension object, we just return it
7085 // as the receiver. This allows arguments objects to be used as
7086 // receivers, but only if they are put in the context scope chain
7087 // explicitly via a with-statement.
7088 Object* constructor = holder->map()->constructor();
7089 if (constructor != context_extension_function) return holder;
7090 // Fall back to using the global object as the receiver if the
7091 // property turns out to be a local variable allocated in a context
7092 // extension object - introduced via eval.
7093 return top->global()->global_receiver();
7094}
7095
7096
7097static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
7098 HandleScope scope;
7099 ASSERT_EQ(2, args.length());
7100
7101 if (!args[0]->IsContext() || !args[1]->IsString()) {
7102 return MakePair(Top::ThrowIllegalOperation(), NULL);
7103 }
7104 Handle<Context> context = args.at<Context>(0);
7105 Handle<String> name = args.at<String>(1);
7106
7107 int index;
7108 PropertyAttributes attributes;
7109 ContextLookupFlags flags = FOLLOW_CHAINS;
7110 Handle<Object> holder =
7111 context->Lookup(name, flags, &index, &attributes);
7112
7113 // If the index is non-negative, the slot has been found in a local
7114 // variable or a parameter. Read it from the context object or the
7115 // arguments object.
7116 if (index >= 0) {
7117 // If the "property" we were looking for is a local variable or an
7118 // argument in a context, the receiver is the global object; see
7119 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7120 JSObject* receiver = Top::context()->global()->global_receiver();
John Reck59135872010-11-02 12:39:01 -07007121 MaybeObject* value = (holder->IsContext())
Steve Blocka7e24c12009-10-30 11:49:00 +00007122 ? Context::cast(*holder)->get(index)
7123 : JSObject::cast(*holder)->GetElement(index);
7124 return MakePair(Unhole(value, attributes), receiver);
7125 }
7126
7127 // If the holder is found, we read the property from it.
7128 if (!holder.is_null() && holder->IsJSObject()) {
7129 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
7130 JSObject* object = JSObject::cast(*holder);
7131 JSObject* receiver;
7132 if (object->IsGlobalObject()) {
7133 receiver = GlobalObject::cast(object)->global_receiver();
7134 } else if (context->is_exception_holder(*holder)) {
7135 receiver = Top::context()->global()->global_receiver();
7136 } else {
7137 receiver = ComputeReceiverForNonGlobal(object);
7138 }
7139 // No need to unhole the value here. This is taken care of by the
7140 // GetProperty function.
John Reck59135872010-11-02 12:39:01 -07007141 MaybeObject* value = object->GetProperty(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +00007142 return MakePair(value, receiver);
7143 }
7144
7145 if (throw_error) {
7146 // The property doesn't exist - throw exception.
7147 Handle<Object> reference_error =
7148 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7149 return MakePair(Top::Throw(*reference_error), NULL);
7150 } else {
7151 // The property doesn't exist - return undefined
7152 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7153 }
7154}
7155
7156
7157static ObjectPair Runtime_LoadContextSlot(Arguments args) {
7158 return LoadContextSlotHelper(args, true);
7159}
7160
7161
7162static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
7163 return LoadContextSlotHelper(args, false);
7164}
7165
7166
John Reck59135872010-11-02 12:39:01 -07007167static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007168 HandleScope scope;
7169 ASSERT(args.length() == 3);
7170
7171 Handle<Object> value(args[0]);
7172 CONVERT_ARG_CHECKED(Context, context, 1);
7173 CONVERT_ARG_CHECKED(String, name, 2);
7174
7175 int index;
7176 PropertyAttributes attributes;
7177 ContextLookupFlags flags = FOLLOW_CHAINS;
7178 Handle<Object> holder =
7179 context->Lookup(name, flags, &index, &attributes);
7180
7181 if (index >= 0) {
7182 if (holder->IsContext()) {
7183 // Ignore if read_only variable.
7184 if ((attributes & READ_ONLY) == 0) {
7185 Handle<Context>::cast(holder)->set(index, *value);
7186 }
7187 } else {
7188 ASSERT((attributes & READ_ONLY) == 0);
John Reck59135872010-11-02 12:39:01 -07007189 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7190 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00007191 }
7192 return *value;
7193 }
7194
7195 // Slow case: The property is not in a FixedArray context.
7196 // It is either in an JSObject extension context or it was not found.
7197 Handle<JSObject> context_ext;
7198
7199 if (!holder.is_null()) {
7200 // The property exists in the extension context.
7201 context_ext = Handle<JSObject>::cast(holder);
7202 } else {
7203 // The property was not found. It needs to be stored in the global context.
7204 ASSERT(attributes == ABSENT);
7205 attributes = NONE;
7206 context_ext = Handle<JSObject>(Top::context()->global());
7207 }
7208
7209 // Set the property, but ignore if read_only variable on the context
7210 // extension object itself.
7211 if ((attributes & READ_ONLY) == 0 ||
7212 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
Ben Murdochdb5a90a2011-01-06 18:27:03 +00007213 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00007214 if (set.is_null()) {
7215 // Failure::Exception is converted to a null handle in the
7216 // handle-based methods such as SetProperty. We therefore need
7217 // to convert null handles back to exceptions.
7218 ASSERT(Top::has_pending_exception());
7219 return Failure::Exception();
7220 }
7221 }
7222 return *value;
7223}
7224
7225
John Reck59135872010-11-02 12:39:01 -07007226static MaybeObject* Runtime_Throw(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007227 HandleScope scope;
7228 ASSERT(args.length() == 1);
7229
7230 return Top::Throw(args[0]);
7231}
7232
7233
John Reck59135872010-11-02 12:39:01 -07007234static MaybeObject* Runtime_ReThrow(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007235 HandleScope scope;
7236 ASSERT(args.length() == 1);
7237
7238 return Top::ReThrow(args[0]);
7239}
7240
7241
John Reck59135872010-11-02 12:39:01 -07007242static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +00007243 ASSERT_EQ(0, args.length());
7244 return Top::PromoteScheduledException();
7245}
7246
7247
John Reck59135872010-11-02 12:39:01 -07007248static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007249 HandleScope scope;
7250 ASSERT(args.length() == 1);
7251
7252 Handle<Object> name(args[0]);
7253 Handle<Object> reference_error =
7254 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7255 return Top::Throw(*reference_error);
7256}
7257
7258
John Reck59135872010-11-02 12:39:01 -07007259static MaybeObject* Runtime_StackOverflow(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007260 NoHandleAllocation na;
7261 return Top::StackOverflow();
7262}
7263
7264
John Reck59135872010-11-02 12:39:01 -07007265static MaybeObject* Runtime_StackGuard(Arguments args) {
Ben Murdochf87a2032010-10-22 12:50:53 +01007266 ASSERT(args.length() == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00007267
7268 // First check if this is a real stack overflow.
7269 if (StackGuard::IsStackOverflow()) {
7270 return Runtime_StackOverflow(args);
7271 }
7272
7273 return Execution::HandleStackGuardInterrupt();
7274}
7275
7276
7277// NOTE: These PrintXXX functions are defined for all builds (not just
7278// DEBUG builds) because we may want to be able to trace function
7279// calls in all modes.
7280static void PrintString(String* str) {
7281 // not uncommon to have empty strings
7282 if (str->length() > 0) {
7283 SmartPointer<char> s =
7284 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7285 PrintF("%s", *s);
7286 }
7287}
7288
7289
7290static void PrintObject(Object* obj) {
7291 if (obj->IsSmi()) {
7292 PrintF("%d", Smi::cast(obj)->value());
7293 } else if (obj->IsString() || obj->IsSymbol()) {
7294 PrintString(String::cast(obj));
7295 } else if (obj->IsNumber()) {
7296 PrintF("%g", obj->Number());
7297 } else if (obj->IsFailure()) {
7298 PrintF("<failure>");
7299 } else if (obj->IsUndefined()) {
7300 PrintF("<undefined>");
7301 } else if (obj->IsNull()) {
7302 PrintF("<null>");
7303 } else if (obj->IsTrue()) {
7304 PrintF("<true>");
7305 } else if (obj->IsFalse()) {
7306 PrintF("<false>");
7307 } else {
Ben Murdochf87a2032010-10-22 12:50:53 +01007308 PrintF("%p", reinterpret_cast<void*>(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00007309 }
7310}
7311
7312
7313static int StackSize() {
7314 int n = 0;
7315 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7316 return n;
7317}
7318
7319
7320static void PrintTransition(Object* result) {
7321 // indentation
7322 { const int nmax = 80;
7323 int n = StackSize();
7324 if (n <= nmax)
7325 PrintF("%4d:%*s", n, n, "");
7326 else
7327 PrintF("%4d:%*s", n, nmax, "...");
7328 }
7329
7330 if (result == NULL) {
7331 // constructor calls
7332 JavaScriptFrameIterator it;
7333 JavaScriptFrame* frame = it.frame();
7334 if (frame->IsConstructor()) PrintF("new ");
7335 // function name
7336 Object* fun = frame->function();
7337 if (fun->IsJSFunction()) {
7338 PrintObject(JSFunction::cast(fun)->shared()->name());
7339 } else {
7340 PrintObject(fun);
7341 }
7342 // function arguments
7343 // (we are intentionally only printing the actually
7344 // supplied parameters, not all parameters required)
7345 PrintF("(this=");
7346 PrintObject(frame->receiver());
7347 const int length = frame->GetProvidedParametersCount();
7348 for (int i = 0; i < length; i++) {
7349 PrintF(", ");
7350 PrintObject(frame->GetParameter(i));
7351 }
7352 PrintF(") {\n");
7353
7354 } else {
7355 // function result
7356 PrintF("} -> ");
7357 PrintObject(result);
7358 PrintF("\n");
7359 }
7360}
7361
7362
John Reck59135872010-11-02 12:39:01 -07007363static MaybeObject* Runtime_TraceEnter(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007364 ASSERT(args.length() == 0);
7365 NoHandleAllocation ha;
7366 PrintTransition(NULL);
7367 return Heap::undefined_value();
7368}
7369
7370
John Reck59135872010-11-02 12:39:01 -07007371static MaybeObject* Runtime_TraceExit(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007372 NoHandleAllocation ha;
7373 PrintTransition(args[0]);
7374 return args[0]; // return TOS
7375}
7376
7377
John Reck59135872010-11-02 12:39:01 -07007378static MaybeObject* Runtime_DebugPrint(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
7381
7382#ifdef DEBUG
7383 if (args[0]->IsString()) {
7384 // If we have a string, assume it's a code "marker"
7385 // and print some interesting cpu debugging info.
7386 JavaScriptFrameIterator it;
7387 JavaScriptFrame* frame = it.frame();
7388 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7389 frame->fp(), frame->sp(), frame->caller_sp());
7390 } else {
7391 PrintF("DebugPrint: ");
7392 }
7393 args[0]->Print();
Steve Blockd0582a62009-12-15 09:54:21 +00007394 if (args[0]->IsHeapObject()) {
Steve Block6ded16b2010-05-10 14:33:55 +01007395 PrintF("\n");
Steve Blockd0582a62009-12-15 09:54:21 +00007396 HeapObject::cast(args[0])->map()->Print();
7397 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007398#else
7399 // ShortPrint is available in release mode. Print is not.
7400 args[0]->ShortPrint();
7401#endif
7402 PrintF("\n");
7403 Flush();
7404
7405 return args[0]; // return TOS
7406}
7407
7408
John Reck59135872010-11-02 12:39:01 -07007409static MaybeObject* Runtime_DebugTrace(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007410 ASSERT(args.length() == 0);
7411 NoHandleAllocation ha;
7412 Top::PrintStack();
7413 return Heap::undefined_value();
7414}
7415
7416
John Reck59135872010-11-02 12:39:01 -07007417static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007418 NoHandleAllocation ha;
7419 ASSERT(args.length() == 0);
7420
7421 // According to ECMA-262, section 15.9.1, page 117, the precision of
7422 // the number in a Date object representing a particular instant in
7423 // time is milliseconds. Therefore, we floor the result of getting
7424 // the OS time.
7425 double millis = floor(OS::TimeCurrentMillis());
7426 return Heap::NumberFromDouble(millis);
7427}
7428
7429
John Reck59135872010-11-02 12:39:01 -07007430static MaybeObject* Runtime_DateParseString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007431 HandleScope scope;
7432 ASSERT(args.length() == 2);
7433
7434 CONVERT_ARG_CHECKED(String, str, 0);
7435 FlattenString(str);
7436
7437 CONVERT_ARG_CHECKED(JSArray, output, 1);
7438 RUNTIME_ASSERT(output->HasFastElements());
7439
7440 AssertNoAllocation no_allocation;
7441
7442 FixedArray* output_array = FixedArray::cast(output->elements());
7443 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7444 bool result;
7445 if (str->IsAsciiRepresentation()) {
7446 result = DateParser::Parse(str->ToAsciiVector(), output_array);
7447 } else {
7448 ASSERT(str->IsTwoByteRepresentation());
7449 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7450 }
7451
7452 if (result) {
7453 return *output;
7454 } else {
7455 return Heap::null_value();
7456 }
7457}
7458
7459
John Reck59135872010-11-02 12:39:01 -07007460static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007461 NoHandleAllocation ha;
7462 ASSERT(args.length() == 1);
7463
7464 CONVERT_DOUBLE_CHECKED(x, args[0]);
7465 const char* zone = OS::LocalTimezone(x);
7466 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7467}
7468
7469
John Reck59135872010-11-02 12:39:01 -07007470static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007471 NoHandleAllocation ha;
7472 ASSERT(args.length() == 0);
7473
7474 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7475}
7476
7477
John Reck59135872010-11-02 12:39:01 -07007478static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007479 NoHandleAllocation ha;
7480 ASSERT(args.length() == 1);
7481
7482 CONVERT_DOUBLE_CHECKED(x, args[0]);
7483 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7484}
7485
7486
John Reck59135872010-11-02 12:39:01 -07007487static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007488 ASSERT(args.length() == 1);
7489 Object* global = args[0];
7490 if (!global->IsJSGlobalObject()) return Heap::null_value();
7491 return JSGlobalObject::cast(global)->global_receiver();
7492}
7493
7494
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007495static MaybeObject* Runtime_ParseJson(Arguments args) {
7496 HandleScope scope;
7497 ASSERT_EQ(1, args.length());
7498 CONVERT_ARG_CHECKED(String, source, 0);
7499
7500 Handle<Object> result = JsonParser::Parse(source);
7501 if (result.is_null()) {
7502 // Syntax error or stack overflow in scanner.
7503 ASSERT(Top::has_pending_exception());
7504 return Failure::Exception();
7505 }
7506 return *result;
7507}
7508
7509
John Reck59135872010-11-02 12:39:01 -07007510static MaybeObject* Runtime_CompileString(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007511 HandleScope scope;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007512 ASSERT_EQ(1, args.length());
Steve Blocka7e24c12009-10-30 11:49:00 +00007513 CONVERT_ARG_CHECKED(String, source, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00007514
7515 // Compile source string in the global context.
7516 Handle<Context> context(Top::context()->global_context());
Steve Block6ded16b2010-05-10 14:33:55 +01007517 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7518 context,
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007519 true);
Steve Block6ded16b2010-05-10 14:33:55 +01007520 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00007521 Handle<JSFunction> fun =
Steve Block6ded16b2010-05-10 14:33:55 +01007522 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
Steve Blocka7e24c12009-10-30 11:49:00 +00007523 return *fun;
7524}
7525
7526
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007527static ObjectPair CompileGlobalEval(Handle<String> source,
7528 Handle<Object> receiver) {
7529 // Deal with a normal eval call with a string argument. Compile it
7530 // and return the compiled function bound in the local context.
7531 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7532 source,
7533 Handle<Context>(Top::context()),
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007534 Top::context()->IsGlobalContext());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007535 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7536 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7537 shared,
7538 Handle<Context>(Top::context()),
7539 NOT_TENURED);
7540 return MakePair(*compiled, *receiver);
7541}
7542
7543
Leon Clarkee46be812010-01-19 14:06:41 +00007544static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7545 ASSERT(args.length() == 3);
7546 if (!args[0]->IsJSFunction()) {
7547 return MakePair(Top::ThrowIllegalOperation(), NULL);
7548 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007549
Steve Blocka7e24c12009-10-30 11:49:00 +00007550 HandleScope scope;
Leon Clarkee46be812010-01-19 14:06:41 +00007551 Handle<JSFunction> callee = args.at<JSFunction>(0);
7552 Handle<Object> receiver; // Will be overwritten.
7553
7554 // Compute the calling context.
7555 Handle<Context> context = Handle<Context>(Top::context());
7556#ifdef DEBUG
7557 // Make sure Top::context() agrees with the old code that traversed
7558 // the stack frames to compute the context.
Steve Blocka7e24c12009-10-30 11:49:00 +00007559 StackFrameLocator locator;
7560 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
Leon Clarkee46be812010-01-19 14:06:41 +00007561 ASSERT(Context::cast(frame->context()) == *context);
7562#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00007563
7564 // Find where the 'eval' symbol is bound. It is unaliased only if
7565 // it is bound in the global context.
Leon Clarkee46be812010-01-19 14:06:41 +00007566 int index = -1;
7567 PropertyAttributes attributes = ABSENT;
7568 while (true) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007569 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7570 &index, &attributes);
7571 // Stop search when eval is found or when the global context is
7572 // reached.
7573 if (attributes != ABSENT || context->IsGlobalContext()) break;
7574 if (context->is_function_context()) {
7575 context = Handle<Context>(Context::cast(context->closure()->context()));
7576 } else {
7577 context = Handle<Context>(context->previous());
7578 }
7579 }
7580
7581 // If eval could not be resolved, it has been deleted and we need to
7582 // throw a reference error.
7583 if (attributes == ABSENT) {
7584 Handle<Object> name = Factory::eval_symbol();
7585 Handle<Object> reference_error =
7586 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
Leon Clarkee46be812010-01-19 14:06:41 +00007587 return MakePair(Top::Throw(*reference_error), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007588 }
7589
Leon Clarkee46be812010-01-19 14:06:41 +00007590 if (!context->IsGlobalContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007591 // 'eval' is not bound in the global context. Just call the function
7592 // with the given arguments. This is not necessarily the global eval.
7593 if (receiver->IsContext()) {
7594 context = Handle<Context>::cast(receiver);
7595 receiver = Handle<Object>(context->get(index));
Leon Clarkee46be812010-01-19 14:06:41 +00007596 } else if (receiver->IsJSContextExtensionObject()) {
7597 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00007598 }
Leon Clarkee46be812010-01-19 14:06:41 +00007599 return MakePair(*callee, *receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007600 }
7601
Leon Clarkee46be812010-01-19 14:06:41 +00007602 // 'eval' is bound in the global context, but it may have been overwritten.
7603 // Compare it to the builtin 'GlobalEval' function to make sure.
7604 if (*callee != Top::global_context()->global_eval_fun() ||
7605 !args[1]->IsString()) {
7606 return MakePair(*callee, Top::context()->global()->global_receiver());
7607 }
7608
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007609 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7610}
7611
7612
7613static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7614 ASSERT(args.length() == 3);
7615 if (!args[0]->IsJSFunction()) {
7616 return MakePair(Top::ThrowIllegalOperation(), NULL);
7617 }
7618
7619 HandleScope scope;
7620 Handle<JSFunction> callee = args.at<JSFunction>(0);
7621
7622 // 'eval' is bound in the global context, but it may have been overwritten.
7623 // Compare it to the builtin 'GlobalEval' function to make sure.
7624 if (*callee != Top::global_context()->global_eval_fun() ||
7625 !args[1]->IsString()) {
7626 return MakePair(*callee, Top::context()->global()->global_receiver());
7627 }
7628
7629 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
Steve Blocka7e24c12009-10-30 11:49:00 +00007630}
7631
7632
John Reck59135872010-11-02 12:39:01 -07007633static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007634 // This utility adjusts the property attributes for newly created Function
7635 // object ("new Function(...)") by changing the map.
7636 // All it does is changing the prototype property to enumerable
7637 // as specified in ECMA262, 15.3.5.2.
7638 HandleScope scope;
7639 ASSERT(args.length() == 1);
7640 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7641 ASSERT(func->map()->instance_type() ==
7642 Top::function_instance_map()->instance_type());
7643 ASSERT(func->map()->instance_size() ==
7644 Top::function_instance_map()->instance_size());
7645 func->set_map(*Top::function_instance_map());
7646 return *func;
7647}
7648
7649
John Reck59135872010-11-02 12:39:01 -07007650static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
Ben Murdochbb769b22010-08-11 14:56:33 +01007651 // Allocate a block of memory in NewSpace (filled with a filler).
7652 // Use as fallback for allocation in generated code when NewSpace
7653 // is full.
7654 ASSERT(args.length() == 1);
7655 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7656 int size = size_smi->value();
7657 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7658 RUNTIME_ASSERT(size > 0);
7659 static const int kMinFreeNewSpaceAfterGC =
7660 Heap::InitialSemiSpaceSize() * 3/4;
7661 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
John Reck59135872010-11-02 12:39:01 -07007662 Object* allocation;
7663 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7664 if (maybe_allocation->ToObject(&allocation)) {
7665 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7666 }
7667 return maybe_allocation;
Ben Murdochbb769b22010-08-11 14:56:33 +01007668 }
Ben Murdochbb769b22010-08-11 14:56:33 +01007669}
7670
7671
Ben Murdochb0fe1622011-05-05 13:52:32 +01007672// Push an object unto an array of objects if it is not already in the
Steve Blocka7e24c12009-10-30 11:49:00 +00007673// array. Returns true if the element was pushed on the stack and
7674// false otherwise.
John Reck59135872010-11-02 12:39:01 -07007675static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007676 ASSERT(args.length() == 2);
7677 CONVERT_CHECKED(JSArray, array, args[0]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007678 CONVERT_CHECKED(JSObject, element, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00007679 RUNTIME_ASSERT(array->HasFastElements());
7680 int length = Smi::cast(array->length())->value();
7681 FixedArray* elements = FixedArray::cast(array->elements());
7682 for (int i = 0; i < length; i++) {
7683 if (elements->get(i) == element) return Heap::false_value();
7684 }
John Reck59135872010-11-02 12:39:01 -07007685 Object* obj;
7686 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7687 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7688 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007689 return Heap::true_value();
7690}
7691
7692
7693/**
7694 * A simple visitor visits every element of Array's.
7695 * The backend storage can be a fixed array for fast elements case,
7696 * or a dictionary for sparse array. Since Dictionary is a subtype
7697 * of FixedArray, the class can be used by both fast and slow cases.
7698 * The second parameter of the constructor, fast_elements, specifies
7699 * whether the storage is a FixedArray or Dictionary.
7700 *
7701 * An index limit is used to deal with the situation that a result array
7702 * length overflows 32-bit non-negative integer.
7703 */
7704class ArrayConcatVisitor {
7705 public:
7706 ArrayConcatVisitor(Handle<FixedArray> storage,
7707 uint32_t index_limit,
7708 bool fast_elements) :
7709 storage_(storage), index_limit_(index_limit),
Leon Clarkee46be812010-01-19 14:06:41 +00007710 index_offset_(0), fast_elements_(fast_elements) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00007711
7712 void visit(uint32_t i, Handle<Object> elm) {
Leon Clarkee46be812010-01-19 14:06:41 +00007713 if (i >= index_limit_ - index_offset_) return;
7714 uint32_t index = index_offset_ + i;
Steve Blocka7e24c12009-10-30 11:49:00 +00007715
7716 if (fast_elements_) {
7717 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7718 storage_->set(index, *elm);
7719
7720 } else {
7721 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7722 Handle<NumberDictionary> result =
7723 Factory::DictionaryAtNumberPut(dict, index, elm);
7724 if (!result.is_identical_to(dict))
7725 storage_ = result;
7726 }
7727 }
7728
7729 void increase_index_offset(uint32_t delta) {
Leon Clarkee46be812010-01-19 14:06:41 +00007730 if (index_limit_ - index_offset_ < delta) {
7731 index_offset_ = index_limit_;
7732 } else {
7733 index_offset_ += delta;
7734 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007735 }
7736
Leon Clarkee46be812010-01-19 14:06:41 +00007737 Handle<FixedArray> storage() { return storage_; }
7738
Steve Blocka7e24c12009-10-30 11:49:00 +00007739 private:
7740 Handle<FixedArray> storage_;
Leon Clarkee46be812010-01-19 14:06:41 +00007741 // Limit on the accepted indices. Elements with indices larger than the
7742 // limit are ignored by the visitor.
Steve Blocka7e24c12009-10-30 11:49:00 +00007743 uint32_t index_limit_;
Leon Clarkee46be812010-01-19 14:06:41 +00007744 // Index after last seen index. Always less than or equal to index_limit_.
Steve Blocka7e24c12009-10-30 11:49:00 +00007745 uint32_t index_offset_;
Steve Block8defd9f2010-07-08 12:39:36 +01007746 const bool fast_elements_;
Steve Blocka7e24c12009-10-30 11:49:00 +00007747};
7748
7749
Steve Block3ce2e202009-11-05 08:53:23 +00007750template<class ExternalArrayClass, class ElementType>
7751static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7752 bool elements_are_ints,
7753 bool elements_are_guaranteed_smis,
7754 uint32_t range,
7755 ArrayConcatVisitor* visitor) {
7756 Handle<ExternalArrayClass> array(
7757 ExternalArrayClass::cast(receiver->elements()));
7758 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7759
7760 if (visitor != NULL) {
7761 if (elements_are_ints) {
7762 if (elements_are_guaranteed_smis) {
7763 for (uint32_t j = 0; j < len; j++) {
7764 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7765 visitor->visit(j, e);
7766 }
7767 } else {
7768 for (uint32_t j = 0; j < len; j++) {
7769 int64_t val = static_cast<int64_t>(array->get(j));
7770 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7771 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7772 visitor->visit(j, e);
7773 } else {
Ben Murdochf87a2032010-10-22 12:50:53 +01007774 Handle<Object> e =
7775 Factory::NewNumber(static_cast<ElementType>(val));
Steve Block3ce2e202009-11-05 08:53:23 +00007776 visitor->visit(j, e);
7777 }
7778 }
7779 }
7780 } else {
7781 for (uint32_t j = 0; j < len; j++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01007782 Handle<Object> e = Factory::NewNumber(array->get(j));
Steve Block3ce2e202009-11-05 08:53:23 +00007783 visitor->visit(j, e);
7784 }
7785 }
7786 }
7787
7788 return len;
7789}
7790
Steve Blocka7e24c12009-10-30 11:49:00 +00007791/**
7792 * A helper function that visits elements of a JSObject. Only elements
7793 * whose index between 0 and range (exclusive) are visited.
7794 *
7795 * If the third parameter, visitor, is not NULL, the visitor is called
7796 * with parameters, 'visitor_index_offset + element index' and the element.
7797 *
7798 * It returns the number of visisted elements.
7799 */
7800static uint32_t IterateElements(Handle<JSObject> receiver,
7801 uint32_t range,
7802 ArrayConcatVisitor* visitor) {
7803 uint32_t num_of_elements = 0;
7804
7805 switch (receiver->GetElementsKind()) {
7806 case JSObject::FAST_ELEMENTS: {
7807 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7808 uint32_t len = elements->length();
7809 if (range < len) {
7810 len = range;
7811 }
7812
7813 for (uint32_t j = 0; j < len; j++) {
7814 Handle<Object> e(elements->get(j));
7815 if (!e->IsTheHole()) {
7816 num_of_elements++;
7817 if (visitor) {
7818 visitor->visit(j, e);
7819 }
7820 }
7821 }
7822 break;
7823 }
7824 case JSObject::PIXEL_ELEMENTS: {
7825 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7826 uint32_t len = pixels->length();
7827 if (range < len) {
7828 len = range;
7829 }
7830
7831 for (uint32_t j = 0; j < len; j++) {
7832 num_of_elements++;
7833 if (visitor != NULL) {
7834 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7835 visitor->visit(j, e);
7836 }
7837 }
7838 break;
7839 }
Steve Block3ce2e202009-11-05 08:53:23 +00007840 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7841 num_of_elements =
7842 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7843 receiver, true, true, range, visitor);
7844 break;
7845 }
7846 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7847 num_of_elements =
7848 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7849 receiver, true, true, range, visitor);
7850 break;
7851 }
7852 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7853 num_of_elements =
7854 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7855 receiver, true, true, range, visitor);
7856 break;
7857 }
7858 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7859 num_of_elements =
7860 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7861 receiver, true, true, range, visitor);
7862 break;
7863 }
7864 case JSObject::EXTERNAL_INT_ELEMENTS: {
7865 num_of_elements =
7866 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7867 receiver, true, false, range, visitor);
7868 break;
7869 }
7870 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7871 num_of_elements =
7872 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7873 receiver, true, false, range, visitor);
7874 break;
7875 }
7876 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7877 num_of_elements =
7878 IterateExternalArrayElements<ExternalFloatArray, float>(
7879 receiver, false, false, range, visitor);
7880 break;
7881 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007882 case JSObject::DICTIONARY_ELEMENTS: {
7883 Handle<NumberDictionary> dict(receiver->element_dictionary());
7884 uint32_t capacity = dict->Capacity();
7885 for (uint32_t j = 0; j < capacity; j++) {
7886 Handle<Object> k(dict->KeyAt(j));
7887 if (dict->IsKey(*k)) {
7888 ASSERT(k->IsNumber());
7889 uint32_t index = static_cast<uint32_t>(k->Number());
7890 if (index < range) {
7891 num_of_elements++;
7892 if (visitor) {
7893 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7894 }
7895 }
7896 }
7897 }
7898 break;
7899 }
7900 default:
7901 UNREACHABLE();
7902 break;
7903 }
7904
7905 return num_of_elements;
7906}
7907
7908
7909/**
7910 * A helper function that visits elements of an Array object, and elements
7911 * on its prototypes.
7912 *
7913 * Elements on prototypes are visited first, and only elements whose indices
7914 * less than Array length are visited.
7915 *
7916 * If a ArrayConcatVisitor object is given, the visitor is called with
7917 * parameters, element's index + visitor_index_offset and the element.
Leon Clarkee46be812010-01-19 14:06:41 +00007918 *
7919 * The returned number of elements is an upper bound on the actual number
7920 * of elements added. If the same element occurs in more than one object
7921 * in the array's prototype chain, it will be counted more than once, but
7922 * will only occur once in the result.
Steve Blocka7e24c12009-10-30 11:49:00 +00007923 */
7924static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7925 ArrayConcatVisitor* visitor) {
7926 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7927 Handle<Object> obj = array;
7928
7929 static const int kEstimatedPrototypes = 3;
7930 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7931
7932 // Visit prototype first. If an element on the prototype is shadowed by
7933 // the inheritor using the same index, the ArrayConcatVisitor visits
7934 // the prototype element before the shadowing element.
7935 // The visitor can simply overwrite the old value by new value using
7936 // the same index. This follows Array::concat semantics.
7937 while (!obj->IsNull()) {
7938 objects.Add(Handle<JSObject>::cast(obj));
7939 obj = Handle<Object>(obj->GetPrototype());
7940 }
7941
7942 uint32_t nof_elements = 0;
7943 for (int i = objects.length() - 1; i >= 0; i--) {
7944 Handle<JSObject> obj = objects[i];
Leon Clarkee46be812010-01-19 14:06:41 +00007945 uint32_t encountered_elements =
Steve Blocka7e24c12009-10-30 11:49:00 +00007946 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
Leon Clarkee46be812010-01-19 14:06:41 +00007947
7948 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7949 nof_elements = JSObject::kMaxElementCount;
7950 } else {
7951 nof_elements += encountered_elements;
7952 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007953 }
7954
7955 return nof_elements;
7956}
7957
7958
7959/**
7960 * A helper function of Runtime_ArrayConcat.
7961 *
7962 * The first argument is an Array of arrays and objects. It is the
7963 * same as the arguments array of Array::concat JS function.
7964 *
7965 * If an argument is an Array object, the function visits array
7966 * elements. If an argument is not an Array object, the function
7967 * visits the object as if it is an one-element array.
7968 *
Leon Clarkee46be812010-01-19 14:06:41 +00007969 * If the result array index overflows 32-bit unsigned integer, the rounded
Steve Blocka7e24c12009-10-30 11:49:00 +00007970 * non-negative number is used as new length. For example, if one
7971 * array length is 2^32 - 1, second array length is 1, the
7972 * concatenated array length is 0.
Leon Clarkee46be812010-01-19 14:06:41 +00007973 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7974 * is one more than the last array index to get a value assigned).
Steve Blocka7e24c12009-10-30 11:49:00 +00007975 */
7976static uint32_t IterateArguments(Handle<JSArray> arguments,
7977 ArrayConcatVisitor* visitor) {
7978 uint32_t visited_elements = 0;
7979 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7980
7981 for (uint32_t i = 0; i < num_of_args; i++) {
John Reck59135872010-11-02 12:39:01 -07007982 Object *element;
7983 MaybeObject* maybe_element = arguments->GetElement(i);
7984 // This if() is not expected to fail, but we have the check in the
7985 // interest of hardening the runtime calls.
7986 if (maybe_element->ToObject(&element)) {
7987 Handle<Object> obj(element);
7988 if (obj->IsJSArray()) {
7989 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7990 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7991 uint32_t nof_elements =
7992 IterateArrayAndPrototypeElements(array, visitor);
7993 // Total elements of array and its prototype chain can be more than
7994 // the array length, but ArrayConcat can only concatenate at most
7995 // the array length number of elements. We use the length as an estimate
7996 // for the actual number of elements added.
7997 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7998 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7999 visited_elements = JSArray::kMaxElementCount;
8000 } else {
8001 visited_elements += added_elements;
8002 }
8003 if (visitor) visitor->increase_index_offset(len);
Leon Clarkee46be812010-01-19 14:06:41 +00008004 } else {
John Reck59135872010-11-02 12:39:01 -07008005 if (visitor) {
8006 visitor->visit(0, obj);
8007 visitor->increase_index_offset(1);
8008 }
8009 if (visited_elements < JSArray::kMaxElementCount) {
8010 visited_elements++;
8011 }
Leon Clarkee46be812010-01-19 14:06:41 +00008012 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008013 }
8014 }
8015 return visited_elements;
8016}
8017
8018
8019/**
8020 * Array::concat implementation.
8021 * See ECMAScript 262, 15.4.4.4.
Leon Clarkee46be812010-01-19 14:06:41 +00008022 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8023 * following the ECMAScript 5 specification.
Steve Blocka7e24c12009-10-30 11:49:00 +00008024 */
John Reck59135872010-11-02 12:39:01 -07008025static MaybeObject* Runtime_ArrayConcat(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008026 ASSERT(args.length() == 1);
8027 HandleScope handle_scope;
8028
8029 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8030 Handle<JSArray> arguments(arg_arrays);
8031
8032 // Pass 1: estimate the number of elements of the result
8033 // (it could be more than real numbers if prototype has elements).
8034 uint32_t result_length = 0;
8035 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8036
8037 { AssertNoAllocation nogc;
8038 for (uint32_t i = 0; i < num_of_args; i++) {
John Reck59135872010-11-02 12:39:01 -07008039 Object* obj;
8040 MaybeObject* maybe_object = arguments->GetElement(i);
8041 // This if() is not expected to fail, but we have the check in the
8042 // interest of hardening the runtime calls.
8043 if (maybe_object->ToObject(&obj)) {
8044 uint32_t length_estimate;
8045 if (obj->IsJSArray()) {
8046 length_estimate =
8047 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8048 } else {
8049 length_estimate = 1;
8050 }
8051 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8052 result_length = JSObject::kMaxElementCount;
8053 break;
8054 }
8055 result_length += length_estimate;
Steve Blocka7e24c12009-10-30 11:49:00 +00008056 }
8057 }
8058 }
8059
8060 // Allocate an empty array, will set length and content later.
8061 Handle<JSArray> result = Factory::NewJSArray(0);
8062
8063 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8064 // If estimated number of elements is more than half of length, a
8065 // fixed array (fast case) is more time and space-efficient than a
8066 // dictionary.
8067 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8068
8069 Handle<FixedArray> storage;
8070 if (fast_case) {
8071 // The backing storage array must have non-existing elements to
8072 // preserve holes across concat operations.
8073 storage = Factory::NewFixedArrayWithHoles(result_length);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008074 Handle<Map> fast_map =
8075 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8076 result->set_map(*fast_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00008077 } else {
8078 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8079 uint32_t at_least_space_for = estimate_nof_elements +
8080 (estimate_nof_elements >> 2);
8081 storage = Handle<FixedArray>::cast(
8082 Factory::NewNumberDictionary(at_least_space_for));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008083 Handle<Map> slow_map =
8084 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8085 result->set_map(*slow_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00008086 }
8087
8088 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8089
8090 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8091
8092 IterateArguments(arguments, &visitor);
8093
8094 result->set_length(*len);
Leon Clarkee46be812010-01-19 14:06:41 +00008095 // Please note the storage might have changed in the visitor.
8096 result->set_elements(*visitor.storage());
Steve Blocka7e24c12009-10-30 11:49:00 +00008097
8098 return *result;
8099}
8100
8101
8102// This will not allocate (flatten the string), but it may run
8103// very slowly for very deeply nested ConsStrings. For debugging use only.
John Reck59135872010-11-02 12:39:01 -07008104static MaybeObject* Runtime_GlobalPrint(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008105 NoHandleAllocation ha;
8106 ASSERT(args.length() == 1);
8107
8108 CONVERT_CHECKED(String, string, args[0]);
8109 StringInputBuffer buffer(string);
8110 while (buffer.has_more()) {
8111 uint16_t character = buffer.GetNext();
8112 PrintF("%c", character);
8113 }
8114 return string;
8115}
8116
8117// Moves all own elements of an object, that are below a limit, to positions
8118// starting at zero. All undefined values are placed after non-undefined values,
8119// and are followed by non-existing element. Does not change the length
8120// property.
8121// Returns the number of non-undefined elements collected.
John Reck59135872010-11-02 12:39:01 -07008122static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008123 ASSERT(args.length() == 2);
8124 CONVERT_CHECKED(JSObject, object, args[0]);
8125 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8126 return object->PrepareElementsForSort(limit);
8127}
8128
8129
8130// Move contents of argument 0 (an array) to argument 1 (an array)
John Reck59135872010-11-02 12:39:01 -07008131static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008132 ASSERT(args.length() == 2);
8133 CONVERT_CHECKED(JSArray, from, args[0]);
8134 CONVERT_CHECKED(JSArray, to, args[1]);
Steve Block8defd9f2010-07-08 12:39:36 +01008135 HeapObject* new_elements = from->elements();
John Reck59135872010-11-02 12:39:01 -07008136 MaybeObject* maybe_new_map;
Iain Merrick75681382010-08-19 15:07:18 +01008137 if (new_elements->map() == Heap::fixed_array_map() ||
8138 new_elements->map() == Heap::fixed_cow_array_map()) {
John Reck59135872010-11-02 12:39:01 -07008139 maybe_new_map = to->map()->GetFastElementsMap();
Steve Block8defd9f2010-07-08 12:39:36 +01008140 } else {
John Reck59135872010-11-02 12:39:01 -07008141 maybe_new_map = to->map()->GetSlowElementsMap();
Steve Block8defd9f2010-07-08 12:39:36 +01008142 }
John Reck59135872010-11-02 12:39:01 -07008143 Object* new_map;
8144 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
Steve Block8defd9f2010-07-08 12:39:36 +01008145 to->set_map(Map::cast(new_map));
8146 to->set_elements(new_elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00008147 to->set_length(from->length());
John Reck59135872010-11-02 12:39:01 -07008148 Object* obj;
8149 { MaybeObject* maybe_obj = from->ResetElements();
8150 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8151 }
Leon Clarke4515c472010-02-03 11:58:03 +00008152 from->set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00008153 return to;
8154}
8155
8156
Steve Block59151502010-09-22 15:07:15 +01008157// How many elements does this object/array have?
John Reck59135872010-11-02 12:39:01 -07008158static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008159 ASSERT(args.length() == 1);
Steve Block59151502010-09-22 15:07:15 +01008160 CONVERT_CHECKED(JSObject, object, args[0]);
8161 HeapObject* elements = object->elements();
Steve Blocka7e24c12009-10-30 11:49:00 +00008162 if (elements->IsDictionary()) {
8163 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
Steve Block59151502010-09-22 15:07:15 +01008164 } else if (object->IsJSArray()) {
8165 return JSArray::cast(object)->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008166 } else {
Steve Block59151502010-09-22 15:07:15 +01008167 return Smi::FromInt(FixedArray::cast(elements)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008168 }
8169}
8170
8171
John Reck59135872010-11-02 12:39:01 -07008172static MaybeObject* Runtime_SwapElements(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +01008173 HandleScope handle_scope;
8174
8175 ASSERT_EQ(3, args.length());
8176
8177 CONVERT_ARG_CHECKED(JSObject, object, 0);
8178 Handle<Object> key1 = args.at<Object>(1);
8179 Handle<Object> key2 = args.at<Object>(2);
8180
8181 uint32_t index1, index2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008182 if (!key1->ToArrayIndex(&index1)
8183 || !key2->ToArrayIndex(&index2)) {
Steve Block6ded16b2010-05-10 14:33:55 +01008184 return Top::ThrowIllegalOperation();
8185 }
8186
8187 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8188 Handle<Object> tmp1 = GetElement(jsobject, index1);
8189 Handle<Object> tmp2 = GetElement(jsobject, index2);
8190
8191 SetElement(jsobject, index1, tmp2);
8192 SetElement(jsobject, index2, tmp1);
8193
8194 return Heap::undefined_value();
8195}
8196
8197
Steve Blocka7e24c12009-10-30 11:49:00 +00008198// Returns an array that tells you where in the [0, length) interval an array
Steve Block59151502010-09-22 15:07:15 +01008199// might have elements. Can either return keys (positive integers) or
8200// intervals (pair of a negative integer (-start-1) followed by a
8201// positive (length)) or undefined values.
8202// Intervals can span over some keys that are not in the object.
John Reck59135872010-11-02 12:39:01 -07008203static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008204 ASSERT(args.length() == 2);
8205 HandleScope scope;
8206 CONVERT_ARG_CHECKED(JSObject, array, 0);
8207 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
8208 if (array->elements()->IsDictionary()) {
8209 // Create an array and get all the keys into it, then remove all the
8210 // keys that are not integers in the range 0 to length-1.
8211 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
8212 int keys_length = keys->length();
8213 for (int i = 0; i < keys_length; i++) {
8214 Object* key = keys->get(i);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008215 uint32_t index = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008216 if (!key->ToArrayIndex(&index) || index >= length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008217 // Zap invalid keys.
8218 keys->set_undefined(i);
8219 }
8220 }
8221 return *Factory::NewJSArrayWithElements(keys);
8222 } else {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008223 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008224 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8225 // -1 means start of array.
Leon Clarke4515c472010-02-03 11:58:03 +00008226 single_interval->set(0, Smi::FromInt(-1));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008227 uint32_t actual_length =
8228 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008229 uint32_t min_length = actual_length < length ? actual_length : length;
8230 Handle<Object> length_object =
8231 Factory::NewNumber(static_cast<double>(min_length));
8232 single_interval->set(1, *length_object);
8233 return *Factory::NewJSArrayWithElements(single_interval);
8234 }
8235}
8236
8237
8238// DefineAccessor takes an optional final argument which is the
8239// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8240// to the way accessors are implemented, it is set for both the getter
8241// and setter on the first call to DefineAccessor and ignored on
8242// subsequent calls.
John Reck59135872010-11-02 12:39:01 -07008243static MaybeObject* Runtime_DefineAccessor(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008244 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8245 // Compute attributes.
8246 PropertyAttributes attributes = NONE;
8247 if (args.length() == 5) {
8248 CONVERT_CHECKED(Smi, attrs, args[4]);
8249 int value = attrs->value();
8250 // Only attribute bits should be set.
8251 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8252 attributes = static_cast<PropertyAttributes>(value);
8253 }
8254
8255 CONVERT_CHECKED(JSObject, obj, args[0]);
8256 CONVERT_CHECKED(String, name, args[1]);
8257 CONVERT_CHECKED(Smi, flag, args[2]);
8258 CONVERT_CHECKED(JSFunction, fun, args[3]);
8259 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8260}
8261
8262
John Reck59135872010-11-02 12:39:01 -07008263static MaybeObject* Runtime_LookupAccessor(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008264 ASSERT(args.length() == 3);
8265 CONVERT_CHECKED(JSObject, obj, args[0]);
8266 CONVERT_CHECKED(String, name, args[1]);
8267 CONVERT_CHECKED(Smi, flag, args[2]);
8268 return obj->LookupAccessor(name, flag->value() == 0);
8269}
8270
8271
8272#ifdef ENABLE_DEBUGGER_SUPPORT
John Reck59135872010-11-02 12:39:01 -07008273static MaybeObject* Runtime_DebugBreak(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008274 ASSERT(args.length() == 0);
8275 return Execution::DebugBreakHelper();
8276}
8277
8278
8279// Helper functions for wrapping and unwrapping stack frame ids.
8280static Smi* WrapFrameId(StackFrame::Id id) {
8281 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
8282 return Smi::FromInt(id >> 2);
8283}
8284
8285
8286static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8287 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8288}
8289
8290
8291// Adds a JavaScript function as a debug event listener.
8292// args[0]: debug event listener function to set or null or undefined for
8293// clearing the event listener function
8294// args[1]: object supplied during callback
John Reck59135872010-11-02 12:39:01 -07008295static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008296 ASSERT(args.length() == 2);
8297 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8298 args[0]->IsUndefined() ||
8299 args[0]->IsNull());
8300 Handle<Object> callback = args.at<Object>(0);
8301 Handle<Object> data = args.at<Object>(1);
8302 Debugger::SetEventListener(callback, data);
8303
8304 return Heap::undefined_value();
8305}
8306
8307
John Reck59135872010-11-02 12:39:01 -07008308static MaybeObject* Runtime_Break(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008309 ASSERT(args.length() == 0);
8310 StackGuard::DebugBreak();
8311 return Heap::undefined_value();
8312}
8313
8314
John Reck59135872010-11-02 12:39:01 -07008315static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8316 LookupResult* result,
8317 bool* caught_exception) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008318 Object* value;
8319 switch (result->type()) {
8320 case NORMAL:
8321 value = result->holder()->GetNormalizedProperty(result);
8322 if (value->IsTheHole()) {
8323 return Heap::undefined_value();
8324 }
8325 return value;
8326 case FIELD:
8327 value =
8328 JSObject::cast(
8329 result->holder())->FastPropertyAt(result->GetFieldIndex());
8330 if (value->IsTheHole()) {
8331 return Heap::undefined_value();
8332 }
8333 return value;
8334 case CONSTANT_FUNCTION:
8335 return result->GetConstantFunction();
8336 case CALLBACKS: {
8337 Object* structure = result->GetCallbackObject();
8338 if (structure->IsProxy() || structure->IsAccessorInfo()) {
John Reck59135872010-11-02 12:39:01 -07008339 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
Steve Blocka7e24c12009-10-30 11:49:00 +00008340 receiver, structure, name, result->holder());
John Reck59135872010-11-02 12:39:01 -07008341 if (!maybe_value->ToObject(&value)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008342 if (maybe_value->IsRetryAfterGC()) return maybe_value;
John Reck59135872010-11-02 12:39:01 -07008343 ASSERT(maybe_value->IsException());
8344 maybe_value = Top::pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00008345 Top::clear_pending_exception();
8346 if (caught_exception != NULL) {
8347 *caught_exception = true;
8348 }
John Reck59135872010-11-02 12:39:01 -07008349 return maybe_value;
Steve Blocka7e24c12009-10-30 11:49:00 +00008350 }
8351 return value;
8352 } else {
8353 return Heap::undefined_value();
8354 }
8355 }
8356 case INTERCEPTOR:
8357 case MAP_TRANSITION:
8358 case CONSTANT_TRANSITION:
8359 case NULL_DESCRIPTOR:
8360 return Heap::undefined_value();
8361 default:
8362 UNREACHABLE();
8363 }
8364 UNREACHABLE();
8365 return Heap::undefined_value();
8366}
8367
8368
8369// Get debugger related details for an object property.
8370// args[0]: object holding property
8371// args[1]: name of the property
8372//
8373// The array returned contains the following information:
8374// 0: Property value
8375// 1: Property details
8376// 2: Property value is exception
8377// 3: Getter function if defined
8378// 4: Setter function if defined
8379// Items 2-4 are only filled if the property has either a getter or a setter
8380// defined through __defineGetter__ and/or __defineSetter__.
John Reck59135872010-11-02 12:39:01 -07008381static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008382 HandleScope scope;
8383
8384 ASSERT(args.length() == 2);
8385
8386 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8387 CONVERT_ARG_CHECKED(String, name, 1);
8388
8389 // Make sure to set the current context to the context before the debugger was
8390 // entered (if the debugger is entered). The reason for switching context here
8391 // is that for some property lookups (accessors and interceptors) callbacks
8392 // into the embedding application can occour, and the embedding application
8393 // could have the assumption that its own global context is the current
8394 // context and not some internal debugger context.
8395 SaveContext save;
8396 if (Debug::InDebugger()) {
8397 Top::set_context(*Debug::debugger_entry()->GetContext());
8398 }
8399
8400 // Skip the global proxy as it has no properties and always delegates to the
8401 // real global object.
8402 if (obj->IsJSGlobalProxy()) {
8403 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8404 }
8405
8406
8407 // Check if the name is trivially convertible to an index and get the element
8408 // if so.
8409 uint32_t index;
8410 if (name->AsArrayIndex(&index)) {
8411 Handle<FixedArray> details = Factory::NewFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07008412 Object* element_or_char;
8413 { MaybeObject* maybe_element_or_char =
8414 Runtime::GetElementOrCharAt(obj, index);
8415 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8416 return maybe_element_or_char;
8417 }
8418 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008419 details->set(0, element_or_char);
Steve Blocka7e24c12009-10-30 11:49:00 +00008420 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8421 return *Factory::NewJSArrayWithElements(details);
8422 }
8423
8424 // Find the number of objects making up this.
8425 int length = LocalPrototypeChainLength(*obj);
8426
8427 // Try local lookup on each of the objects.
8428 Handle<JSObject> jsproto = obj;
8429 for (int i = 0; i < length; i++) {
8430 LookupResult result;
8431 jsproto->LocalLookup(*name, &result);
8432 if (result.IsProperty()) {
8433 // LookupResult is not GC safe as it holds raw object pointers.
8434 // GC can happen later in this code so put the required fields into
8435 // local variables using handles when required for later use.
8436 PropertyType result_type = result.type();
8437 Handle<Object> result_callback_obj;
8438 if (result_type == CALLBACKS) {
8439 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8440 }
8441 Smi* property_details = result.GetPropertyDetails().AsSmi();
8442 // DebugLookupResultValue can cause GC so details from LookupResult needs
8443 // to be copied to handles before this.
8444 bool caught_exception = false;
John Reck59135872010-11-02 12:39:01 -07008445 Object* raw_value;
8446 { MaybeObject* maybe_raw_value =
8447 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8448 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8449 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008450 Handle<Object> value(raw_value);
8451
8452 // If the callback object is a fixed array then it contains JavaScript
8453 // getter and/or setter.
8454 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8455 result_callback_obj->IsFixedArray();
8456 Handle<FixedArray> details =
8457 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8458 details->set(0, *value);
8459 details->set(1, property_details);
8460 if (hasJavaScriptAccessors) {
8461 details->set(2,
8462 caught_exception ? Heap::true_value()
8463 : Heap::false_value());
8464 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8465 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8466 }
8467
8468 return *Factory::NewJSArrayWithElements(details);
8469 }
8470 if (i < length - 1) {
8471 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8472 }
8473 }
8474
8475 return Heap::undefined_value();
8476}
8477
8478
John Reck59135872010-11-02 12:39:01 -07008479static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008480 HandleScope scope;
8481
8482 ASSERT(args.length() == 2);
8483
8484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8485 CONVERT_ARG_CHECKED(String, name, 1);
8486
8487 LookupResult result;
8488 obj->Lookup(*name, &result);
8489 if (result.IsProperty()) {
8490 return DebugLookupResultValue(*obj, *name, &result, NULL);
8491 }
8492 return Heap::undefined_value();
8493}
8494
8495
Steve Blocka7e24c12009-10-30 11:49:00 +00008496// Return the property type calculated from the property details.
8497// args[0]: smi with property details.
John Reck59135872010-11-02 12:39:01 -07008498static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008499 ASSERT(args.length() == 1);
8500 CONVERT_CHECKED(Smi, details, args[0]);
8501 PropertyType type = PropertyDetails(details).type();
8502 return Smi::FromInt(static_cast<int>(type));
8503}
8504
8505
8506// Return the property attribute calculated from the property details.
8507// args[0]: smi with property details.
John Reck59135872010-11-02 12:39:01 -07008508static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008509 ASSERT(args.length() == 1);
8510 CONVERT_CHECKED(Smi, details, args[0]);
8511 PropertyAttributes attributes = PropertyDetails(details).attributes();
8512 return Smi::FromInt(static_cast<int>(attributes));
8513}
8514
8515
8516// Return the property insertion index calculated from the property details.
8517// args[0]: smi with property details.
John Reck59135872010-11-02 12:39:01 -07008518static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008519 ASSERT(args.length() == 1);
8520 CONVERT_CHECKED(Smi, details, args[0]);
8521 int index = PropertyDetails(details).index();
8522 return Smi::FromInt(index);
8523}
8524
8525
Steve Blocka7e24c12009-10-30 11:49:00 +00008526// Return property value from named interceptor.
8527// args[0]: object
8528// args[1]: property name
John Reck59135872010-11-02 12:39:01 -07008529static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008530 HandleScope scope;
8531 ASSERT(args.length() == 2);
8532 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8533 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8534 CONVERT_ARG_CHECKED(String, name, 1);
8535
8536 PropertyAttributes attributes;
8537 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
8538}
8539
8540
8541// Return element value from indexed interceptor.
8542// args[0]: object
8543// args[1]: index
John Reck59135872010-11-02 12:39:01 -07008544static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8545 Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008546 HandleScope scope;
8547 ASSERT(args.length() == 2);
8548 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8549 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8550 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8551
8552 return obj->GetElementWithInterceptor(*obj, index);
8553}
8554
8555
John Reck59135872010-11-02 12:39:01 -07008556static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008557 ASSERT(args.length() >= 1);
8558 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
8559 // Check that the break id is valid.
8560 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
8561 return Top::Throw(Heap::illegal_execution_state_symbol());
8562 }
8563
8564 return Heap::true_value();
8565}
8566
8567
John Reck59135872010-11-02 12:39:01 -07008568static MaybeObject* Runtime_GetFrameCount(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008569 HandleScope scope;
8570 ASSERT(args.length() == 1);
8571
8572 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07008573 Object* result;
8574 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8575 if (!maybe_result->ToObject(&result)) return maybe_result;
8576 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008577
8578 // Count all frames which are relevant to debugging stack trace.
8579 int n = 0;
8580 StackFrame::Id id = Debug::break_frame_id();
8581 if (id == StackFrame::NO_ID) {
8582 // If there is no JavaScript stack frame count is 0.
8583 return Smi::FromInt(0);
8584 }
8585 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8586 return Smi::FromInt(n);
8587}
8588
8589
8590static const int kFrameDetailsFrameIdIndex = 0;
8591static const int kFrameDetailsReceiverIndex = 1;
8592static const int kFrameDetailsFunctionIndex = 2;
8593static const int kFrameDetailsArgumentCountIndex = 3;
8594static const int kFrameDetailsLocalCountIndex = 4;
8595static const int kFrameDetailsSourcePositionIndex = 5;
8596static const int kFrameDetailsConstructCallIndex = 6;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008597static const int kFrameDetailsAtReturnIndex = 7;
8598static const int kFrameDetailsDebuggerFrameIndex = 8;
8599static const int kFrameDetailsFirstDynamicIndex = 9;
Steve Blocka7e24c12009-10-30 11:49:00 +00008600
8601// Return an array with frame details
8602// args[0]: number: break id
8603// args[1]: number: frame index
8604//
8605// The array returned contains the following information:
8606// 0: Frame id
8607// 1: Receiver
8608// 2: Function
8609// 3: Argument count
8610// 4: Local count
8611// 5: Source position
8612// 6: Constructor call
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008613// 7: Is at return
8614// 8: Debugger frame
Steve Blocka7e24c12009-10-30 11:49:00 +00008615// Arguments name, value
8616// Locals name, value
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008617// Return value if any
John Reck59135872010-11-02 12:39:01 -07008618static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008619 HandleScope scope;
8620 ASSERT(args.length() == 2);
8621
8622 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07008623 Object* check;
8624 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8625 if (!maybe_check->ToObject(&check)) return maybe_check;
8626 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008627 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8628
8629 // Find the relevant frame with the requested index.
8630 StackFrame::Id id = Debug::break_frame_id();
8631 if (id == StackFrame::NO_ID) {
8632 // If there are no JavaScript stack frames return undefined.
8633 return Heap::undefined_value();
8634 }
8635 int count = 0;
8636 JavaScriptFrameIterator it(id);
8637 for (; !it.done(); it.Advance()) {
8638 if (count == index) break;
8639 count++;
8640 }
8641 if (it.done()) return Heap::undefined_value();
8642
Ben Murdochb0fe1622011-05-05 13:52:32 +01008643 bool is_optimized_frame =
8644 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8645
Steve Blocka7e24c12009-10-30 11:49:00 +00008646 // Traverse the saved contexts chain to find the active context for the
8647 // selected frame.
8648 SaveContext* save = Top::save_context();
8649 while (save != NULL && !save->below(it.frame())) {
8650 save = save->prev();
8651 }
8652 ASSERT(save != NULL);
8653
8654 // Get the frame id.
8655 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8656
8657 // Find source position.
8658 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
8659
8660 // Check for constructor frame.
8661 bool constructor = it.frame()->IsConstructor();
8662
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008663 // Get scope info and read from it for local variable information.
8664 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
8665 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
8666 ScopeInfo<> info(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00008667
8668 // Get the context.
8669 Handle<Context> context(Context::cast(it.frame()->context()));
8670
8671 // Get the locals names and values into a temporary array.
8672 //
8673 // TODO(1240907): Hide compiler-introduced stack variables
8674 // (e.g. .result)? For users of the debugger, they will probably be
8675 // confusing.
8676 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
Steve Blocka7e24c12009-10-30 11:49:00 +00008677
Ben Murdochb0fe1622011-05-05 13:52:32 +01008678 // Fill in the names of the locals.
8679 for (int i = 0; i < info.NumberOfLocals(); i++) {
8680 locals->set(i * 2, *info.LocalName(i));
8681 }
8682
8683 // Fill in the values of the locals.
8684 for (int i = 0; i < info.NumberOfLocals(); i++) {
8685 if (is_optimized_frame) {
8686 // If we are inspecting an optimized frame use undefined as the
8687 // value for all locals.
8688 //
8689 // TODO(3141533): We should be able to get the correct values
8690 // for locals in optimized frames.
8691 locals->set(i * 2 + 1, Heap::undefined_value());
8692 } else if (i < info.number_of_stack_slots()) {
8693 // Get the value from the stack.
Steve Blocka7e24c12009-10-30 11:49:00 +00008694 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8695 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00008696 // Traverse the context chain to the function context as all local
8697 // variables stored in the context will be on the function context.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008698 Handle<String> name = info.LocalName(i);
Steve Blocka7e24c12009-10-30 11:49:00 +00008699 while (!context->is_function_context()) {
8700 context = Handle<Context>(context->previous());
8701 }
8702 ASSERT(context->is_function_context());
8703 locals->set(i * 2 + 1,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008704 context->get(scope_info->ContextSlotIndex(*name, NULL)));
Steve Blocka7e24c12009-10-30 11:49:00 +00008705 }
8706 }
8707
Ben Murdochb0fe1622011-05-05 13:52:32 +01008708 // Check whether this frame is positioned at return. If not top
8709 // frame or if the frame is optimized it cannot be at a return.
8710 bool at_return = false;
8711 if (!is_optimized_frame && index == 0) {
8712 at_return = Debug::IsBreakAtReturn(it.frame());
8713 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008714
8715 // If positioned just before return find the value to be returned and add it
8716 // to the frame information.
8717 Handle<Object> return_value = Factory::undefined_value();
8718 if (at_return) {
8719 StackFrameIterator it2;
8720 Address internal_frame_sp = NULL;
8721 while (!it2.done()) {
8722 if (it2.frame()->is_internal()) {
8723 internal_frame_sp = it2.frame()->sp();
8724 } else {
8725 if (it2.frame()->is_java_script()) {
8726 if (it2.frame()->id() == it.frame()->id()) {
8727 // The internal frame just before the JavaScript frame contains the
8728 // value to return on top. A debug break at return will create an
8729 // internal frame to store the return value (eax/rax/r0) before
8730 // entering the debug break exit frame.
8731 if (internal_frame_sp != NULL) {
8732 return_value =
8733 Handle<Object>(Memory::Object_at(internal_frame_sp));
8734 break;
8735 }
8736 }
8737 }
8738
8739 // Indicate that the previous frame was not an internal frame.
8740 internal_frame_sp = NULL;
8741 }
8742 it2.Advance();
8743 }
8744 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008745
8746 // Now advance to the arguments adapter frame (if any). It contains all
8747 // the provided parameters whereas the function frame always have the number
8748 // of arguments matching the functions parameters. The rest of the
8749 // information (except for what is collected above) is the same.
8750 it.AdvanceToArgumentsFrame();
8751
8752 // Find the number of arguments to fill. At least fill the number of
8753 // parameters for the function and fill more if more parameters are provided.
8754 int argument_count = info.number_of_parameters();
8755 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8756 argument_count = it.frame()->GetProvidedParametersCount();
8757 }
8758
8759 // Calculate the size of the result.
8760 int details_size = kFrameDetailsFirstDynamicIndex +
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008761 2 * (argument_count + info.NumberOfLocals()) +
8762 (at_return ? 1 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008763 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8764
8765 // Add the frame id.
8766 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8767
8768 // Add the function (same as in function frame).
8769 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8770
8771 // Add the arguments count.
8772 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8773
8774 // Add the locals count
8775 details->set(kFrameDetailsLocalCountIndex,
8776 Smi::FromInt(info.NumberOfLocals()));
8777
8778 // Add the source position.
8779 if (position != RelocInfo::kNoPosition) {
8780 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8781 } else {
8782 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8783 }
8784
8785 // Add the constructor information.
8786 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8787
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008788 // Add the at return information.
8789 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8790
Steve Blocka7e24c12009-10-30 11:49:00 +00008791 // Add information on whether this frame is invoked in the debugger context.
8792 details->set(kFrameDetailsDebuggerFrameIndex,
8793 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8794
8795 // Fill the dynamic part.
8796 int details_index = kFrameDetailsFirstDynamicIndex;
8797
8798 // Add arguments name and value.
8799 for (int i = 0; i < argument_count; i++) {
8800 // Name of the argument.
8801 if (i < info.number_of_parameters()) {
8802 details->set(details_index++, *info.parameter_name(i));
8803 } else {
8804 details->set(details_index++, Heap::undefined_value());
8805 }
8806
Ben Murdochb0fe1622011-05-05 13:52:32 +01008807 // Parameter value. If we are inspecting an optimized frame, use
8808 // undefined as the value.
8809 //
8810 // TODO(3141533): We should be able to get the actual parameter
8811 // value for optimized frames.
8812 if (!is_optimized_frame &&
8813 (i < it.frame()->GetProvidedParametersCount())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008814 details->set(details_index++, it.frame()->GetParameter(i));
8815 } else {
8816 details->set(details_index++, Heap::undefined_value());
8817 }
8818 }
8819
8820 // Add locals name and value from the temporary copy from the function frame.
8821 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8822 details->set(details_index++, locals->get(i));
8823 }
8824
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008825 // Add the value being returned.
8826 if (at_return) {
8827 details->set(details_index++, *return_value);
8828 }
8829
Steve Blocka7e24c12009-10-30 11:49:00 +00008830 // Add the receiver (same as in function frame).
8831 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8832 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8833 Handle<Object> receiver(it.frame()->receiver());
8834 if (!receiver->IsJSObject()) {
8835 // If the receiver is NOT a JSObject we have hit an optimization
8836 // where a value object is not converted into a wrapped JS objects.
8837 // To hide this optimization from the debugger, we wrap the receiver
8838 // by creating correct wrapper object based on the calling frame's
8839 // global context.
8840 it.Advance();
8841 Handle<Context> calling_frames_global_context(
8842 Context::cast(Context::cast(it.frame()->context())->global_context()));
8843 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8844 }
8845 details->set(kFrameDetailsReceiverIndex, *receiver);
8846
8847 ASSERT_EQ(details_size, details_index);
8848 return *Factory::NewJSArrayWithElements(details);
8849}
8850
8851
8852// Copy all the context locals into an object used to materialize a scope.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008853static void CopyContextLocalsToScopeObject(
8854 Handle<SerializedScopeInfo> serialized_scope_info,
8855 ScopeInfo<>& scope_info,
8856 Handle<Context> context,
8857 Handle<JSObject> scope_object) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008858 // Fill all context locals to the context extension.
8859 for (int i = Context::MIN_CONTEXT_SLOTS;
8860 i < scope_info.number_of_context_slots();
8861 i++) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008862 int context_index = serialized_scope_info->ContextSlotIndex(
8863 *scope_info.context_slot_name(i), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008864
8865 // Don't include the arguments shadow (.arguments) context variable.
8866 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8867 SetProperty(scope_object,
8868 scope_info.context_slot_name(i),
8869 Handle<Object>(context->get(context_index)), NONE);
8870 }
8871 }
8872}
8873
8874
8875// Create a plain JSObject which materializes the local scope for the specified
8876// frame.
8877static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8878 Handle<JSFunction> function(JSFunction::cast(frame->function()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008879 Handle<SharedFunctionInfo> shared(function->shared());
8880 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8881 ScopeInfo<> scope_info(*serialized_scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00008882
8883 // Allocate and initialize a JSObject with all the arguments, stack locals
8884 // heap locals and extension properties of the debugged function.
8885 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8886
8887 // First fill all parameters.
8888 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8889 SetProperty(local_scope,
8890 scope_info.parameter_name(i),
8891 Handle<Object>(frame->GetParameter(i)), NONE);
8892 }
8893
8894 // Second fill all stack locals.
8895 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8896 SetProperty(local_scope,
8897 scope_info.stack_slot_name(i),
8898 Handle<Object>(frame->GetExpression(i)), NONE);
8899 }
8900
8901 // Third fill all context locals.
8902 Handle<Context> frame_context(Context::cast(frame->context()));
8903 Handle<Context> function_context(frame_context->fcontext());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008904 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
Steve Blocka7e24c12009-10-30 11:49:00 +00008905 function_context, local_scope);
8906
8907 // Finally copy any properties from the function context extension. This will
8908 // be variables introduced by eval.
8909 if (function_context->closure() == *function) {
8910 if (function_context->has_extension() &&
8911 !function_context->IsGlobalContext()) {
8912 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
8913 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
8914 for (int i = 0; i < keys->length(); i++) {
8915 // Names of variables introduced by eval are strings.
8916 ASSERT(keys->get(i)->IsString());
8917 Handle<String> key(String::cast(keys->get(i)));
8918 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8919 }
8920 }
8921 }
8922 return local_scope;
8923}
8924
8925
8926// Create a plain JSObject which materializes the closure content for the
8927// context.
8928static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8929 ASSERT(context->is_function_context());
8930
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008931 Handle<SharedFunctionInfo> shared(context->closure()->shared());
8932 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8933 ScopeInfo<> scope_info(*serialized_scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00008934
8935 // Allocate and initialize a JSObject with all the content of theis function
8936 // closure.
8937 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8938
8939 // Check whether the arguments shadow object exists.
8940 int arguments_shadow_index =
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008941 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8942 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008943 if (arguments_shadow_index >= 0) {
8944 // In this case all the arguments are available in the arguments shadow
8945 // object.
8946 Handle<JSObject> arguments_shadow(
8947 JSObject::cast(context->get(arguments_shadow_index)));
8948 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
John Reck59135872010-11-02 12:39:01 -07008949 // We don't expect exception-throwing getters on the arguments shadow.
8950 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008951 SetProperty(closure_scope,
8952 scope_info.parameter_name(i),
John Reck59135872010-11-02 12:39:01 -07008953 Handle<Object>(element),
8954 NONE);
Steve Blocka7e24c12009-10-30 11:49:00 +00008955 }
8956 }
8957
8958 // Fill all context locals to the context extension.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008959 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8960 context, closure_scope);
Steve Blocka7e24c12009-10-30 11:49:00 +00008961
8962 // Finally copy any properties from the function context extension. This will
8963 // be variables introduced by eval.
8964 if (context->has_extension()) {
8965 Handle<JSObject> ext(JSObject::cast(context->extension()));
8966 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
8967 for (int i = 0; i < keys->length(); i++) {
8968 // Names of variables introduced by eval are strings.
8969 ASSERT(keys->get(i)->IsString());
8970 Handle<String> key(String::cast(keys->get(i)));
8971 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8972 }
8973 }
8974
8975 return closure_scope;
8976}
8977
8978
8979// Iterate over the actual scopes visible from a stack frame. All scopes are
8980// backed by an actual context except the local scope, which is inserted
8981// "artifically" in the context chain.
8982class ScopeIterator {
8983 public:
8984 enum ScopeType {
8985 ScopeTypeGlobal = 0,
8986 ScopeTypeLocal,
8987 ScopeTypeWith,
8988 ScopeTypeClosure,
8989 // Every catch block contains an implicit with block (its parameter is
8990 // a JSContextExtensionObject) that extends current scope with a variable
8991 // holding exception object. Such with blocks are treated as scopes of their
8992 // own type.
8993 ScopeTypeCatch
8994 };
8995
8996 explicit ScopeIterator(JavaScriptFrame* frame)
8997 : frame_(frame),
8998 function_(JSFunction::cast(frame->function())),
8999 context_(Context::cast(frame->context())),
9000 local_done_(false),
9001 at_local_(false) {
9002
9003 // Check whether the first scope is actually a local scope.
9004 if (context_->IsGlobalContext()) {
9005 // If there is a stack slot for .result then this local scope has been
9006 // created for evaluating top level code and it is not a real local scope.
9007 // Checking for the existence of .result seems fragile, but the scope info
9008 // saved with the code object does not otherwise have that information.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009009 int index = function_->shared()->scope_info()->
9010 StackSlotIndex(Heap::result_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00009011 at_local_ = index < 0;
9012 } else if (context_->is_function_context()) {
9013 at_local_ = true;
9014 }
9015 }
9016
9017 // More scopes?
9018 bool Done() { return context_.is_null(); }
9019
9020 // Move to the next scope.
9021 void Next() {
9022 // If at a local scope mark the local scope as passed.
9023 if (at_local_) {
9024 at_local_ = false;
9025 local_done_ = true;
9026
9027 // If the current context is not associated with the local scope the
9028 // current context is the next real scope, so don't move to the next
9029 // context in this case.
9030 if (context_->closure() != *function_) {
9031 return;
9032 }
9033 }
9034
9035 // The global scope is always the last in the chain.
9036 if (context_->IsGlobalContext()) {
9037 context_ = Handle<Context>();
9038 return;
9039 }
9040
9041 // Move to the next context.
9042 if (context_->is_function_context()) {
9043 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9044 } else {
9045 context_ = Handle<Context>(context_->previous());
9046 }
9047
9048 // If passing the local scope indicate that the current scope is now the
9049 // local scope.
9050 if (!local_done_ &&
9051 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9052 at_local_ = true;
9053 }
9054 }
9055
9056 // Return the type of the current scope.
9057 int Type() {
9058 if (at_local_) {
9059 return ScopeTypeLocal;
9060 }
9061 if (context_->IsGlobalContext()) {
9062 ASSERT(context_->global()->IsGlobalObject());
9063 return ScopeTypeGlobal;
9064 }
9065 if (context_->is_function_context()) {
9066 return ScopeTypeClosure;
9067 }
9068 ASSERT(context_->has_extension());
9069 // Current scope is either an explicit with statement or a with statement
9070 // implicitely generated for a catch block.
9071 // If the extension object here is a JSContextExtensionObject then
9072 // current with statement is one frome a catch block otherwise it's a
9073 // regular with statement.
9074 if (context_->extension()->IsJSContextExtensionObject()) {
9075 return ScopeTypeCatch;
9076 }
9077 return ScopeTypeWith;
9078 }
9079
9080 // Return the JavaScript object with the content of the current scope.
9081 Handle<JSObject> ScopeObject() {
9082 switch (Type()) {
9083 case ScopeIterator::ScopeTypeGlobal:
9084 return Handle<JSObject>(CurrentContext()->global());
9085 break;
9086 case ScopeIterator::ScopeTypeLocal:
9087 // Materialize the content of the local scope into a JSObject.
9088 return MaterializeLocalScope(frame_);
9089 break;
9090 case ScopeIterator::ScopeTypeWith:
9091 case ScopeIterator::ScopeTypeCatch:
9092 // Return the with object.
9093 return Handle<JSObject>(CurrentContext()->extension());
9094 break;
9095 case ScopeIterator::ScopeTypeClosure:
9096 // Materialize the content of the closure scope into a JSObject.
9097 return MaterializeClosure(CurrentContext());
9098 break;
9099 }
9100 UNREACHABLE();
9101 return Handle<JSObject>();
9102 }
9103
9104 // Return the context for this scope. For the local context there might not
9105 // be an actual context.
9106 Handle<Context> CurrentContext() {
9107 if (at_local_ && context_->closure() != *function_) {
9108 return Handle<Context>();
9109 }
9110 return context_;
9111 }
9112
9113#ifdef DEBUG
9114 // Debug print of the content of the current scope.
9115 void DebugPrint() {
9116 switch (Type()) {
9117 case ScopeIterator::ScopeTypeGlobal:
9118 PrintF("Global:\n");
9119 CurrentContext()->Print();
9120 break;
9121
9122 case ScopeIterator::ScopeTypeLocal: {
9123 PrintF("Local:\n");
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009124 ScopeInfo<> scope_info(function_->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +00009125 scope_info.Print();
9126 if (!CurrentContext().is_null()) {
9127 CurrentContext()->Print();
9128 if (CurrentContext()->has_extension()) {
9129 Handle<JSObject> extension =
9130 Handle<JSObject>(CurrentContext()->extension());
9131 if (extension->IsJSContextExtensionObject()) {
9132 extension->Print();
9133 }
9134 }
9135 }
9136 break;
9137 }
9138
9139 case ScopeIterator::ScopeTypeWith: {
9140 PrintF("With:\n");
9141 Handle<JSObject> extension =
9142 Handle<JSObject>(CurrentContext()->extension());
9143 extension->Print();
9144 break;
9145 }
9146
9147 case ScopeIterator::ScopeTypeCatch: {
9148 PrintF("Catch:\n");
9149 Handle<JSObject> extension =
9150 Handle<JSObject>(CurrentContext()->extension());
9151 extension->Print();
9152 break;
9153 }
9154
9155 case ScopeIterator::ScopeTypeClosure: {
9156 PrintF("Closure:\n");
9157 CurrentContext()->Print();
9158 if (CurrentContext()->has_extension()) {
9159 Handle<JSObject> extension =
9160 Handle<JSObject>(CurrentContext()->extension());
9161 if (extension->IsJSContextExtensionObject()) {
9162 extension->Print();
9163 }
9164 }
9165 break;
9166 }
9167
9168 default:
9169 UNREACHABLE();
9170 }
9171 PrintF("\n");
9172 }
9173#endif
9174
9175 private:
9176 JavaScriptFrame* frame_;
9177 Handle<JSFunction> function_;
9178 Handle<Context> context_;
9179 bool local_done_;
9180 bool at_local_;
9181
9182 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9183};
9184
9185
John Reck59135872010-11-02 12:39:01 -07009186static MaybeObject* Runtime_GetScopeCount(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009187 HandleScope scope;
9188 ASSERT(args.length() == 2);
9189
9190 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009191 Object* check;
9192 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9193 if (!maybe_check->ToObject(&check)) return maybe_check;
9194 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009195 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9196
9197 // Get the frame where the debugging is performed.
9198 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9199 JavaScriptFrameIterator it(id);
9200 JavaScriptFrame* frame = it.frame();
9201
9202 // Count the visible scopes.
9203 int n = 0;
9204 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9205 n++;
9206 }
9207
9208 return Smi::FromInt(n);
9209}
9210
9211
9212static const int kScopeDetailsTypeIndex = 0;
9213static const int kScopeDetailsObjectIndex = 1;
9214static const int kScopeDetailsSize = 2;
9215
9216// Return an array with scope details
9217// args[0]: number: break id
9218// args[1]: number: frame index
9219// args[2]: number: scope index
9220//
9221// The array returned contains the following information:
9222// 0: Scope type
9223// 1: Scope object
John Reck59135872010-11-02 12:39:01 -07009224static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009225 HandleScope scope;
9226 ASSERT(args.length() == 3);
9227
9228 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009229 Object* check;
9230 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9231 if (!maybe_check->ToObject(&check)) return maybe_check;
9232 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009233 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9234 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9235
9236 // Get the frame where the debugging is performed.
9237 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9238 JavaScriptFrameIterator frame_it(id);
9239 JavaScriptFrame* frame = frame_it.frame();
9240
9241 // Find the requested scope.
9242 int n = 0;
9243 ScopeIterator it(frame);
9244 for (; !it.Done() && n < index; it.Next()) {
9245 n++;
9246 }
9247 if (it.Done()) {
9248 return Heap::undefined_value();
9249 }
9250
9251 // Calculate the size of the result.
9252 int details_size = kScopeDetailsSize;
9253 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9254
9255 // Fill in scope details.
9256 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009257 Handle<JSObject> scope_object = it.ScopeObject();
9258 details->set(kScopeDetailsObjectIndex, *scope_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00009259
9260 return *Factory::NewJSArrayWithElements(details);
9261}
9262
9263
John Reck59135872010-11-02 12:39:01 -07009264static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009265 HandleScope scope;
9266 ASSERT(args.length() == 0);
9267
9268#ifdef DEBUG
9269 // Print the scopes for the top frame.
9270 StackFrameLocator locator;
9271 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9272 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9273 it.DebugPrint();
9274 }
9275#endif
9276 return Heap::undefined_value();
9277}
9278
9279
John Reck59135872010-11-02 12:39:01 -07009280static MaybeObject* Runtime_GetThreadCount(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009281 HandleScope scope;
9282 ASSERT(args.length() == 1);
9283
9284 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009285 Object* result;
9286 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9287 if (!maybe_result->ToObject(&result)) return maybe_result;
9288 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009289
9290 // Count all archived V8 threads.
9291 int n = 0;
9292 for (ThreadState* thread = ThreadState::FirstInUse();
9293 thread != NULL;
9294 thread = thread->Next()) {
9295 n++;
9296 }
9297
9298 // Total number of threads is current thread and archived threads.
9299 return Smi::FromInt(n + 1);
9300}
9301
9302
9303static const int kThreadDetailsCurrentThreadIndex = 0;
9304static const int kThreadDetailsThreadIdIndex = 1;
9305static const int kThreadDetailsSize = 2;
9306
9307// Return an array with thread details
9308// args[0]: number: break id
9309// args[1]: number: thread index
9310//
9311// The array returned contains the following information:
9312// 0: Is current thread?
9313// 1: Thread id
John Reck59135872010-11-02 12:39:01 -07009314static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009315 HandleScope scope;
9316 ASSERT(args.length() == 2);
9317
9318 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009319 Object* check;
9320 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9321 if (!maybe_check->ToObject(&check)) return maybe_check;
9322 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009323 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9324
9325 // Allocate array for result.
9326 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9327
9328 // Thread index 0 is current thread.
9329 if (index == 0) {
9330 // Fill the details.
9331 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9332 details->set(kThreadDetailsThreadIdIndex,
9333 Smi::FromInt(ThreadManager::CurrentId()));
9334 } else {
9335 // Find the thread with the requested index.
9336 int n = 1;
9337 ThreadState* thread = ThreadState::FirstInUse();
9338 while (index != n && thread != NULL) {
9339 thread = thread->Next();
9340 n++;
9341 }
9342 if (thread == NULL) {
9343 return Heap::undefined_value();
9344 }
9345
9346 // Fill the details.
9347 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9348 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9349 }
9350
9351 // Convert to JS array and return.
9352 return *Factory::NewJSArrayWithElements(details);
9353}
9354
9355
Ben Murdochbb769b22010-08-11 14:56:33 +01009356// Sets the disable break state
9357// args[0]: disable break state
John Reck59135872010-11-02 12:39:01 -07009358static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
Ben Murdochbb769b22010-08-11 14:56:33 +01009359 HandleScope scope;
9360 ASSERT(args.length() == 1);
9361 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9362 Debug::set_disable_break(disable_break);
9363 return Heap::undefined_value();
9364}
9365
9366
John Reck59135872010-11-02 12:39:01 -07009367static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009368 HandleScope scope;
9369 ASSERT(args.length() == 1);
9370
9371 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9372 Handle<SharedFunctionInfo> shared(fun->shared());
9373 // Find the number of break points
9374 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9375 if (break_locations->IsUndefined()) return Heap::undefined_value();
9376 // Return array as JS array
9377 return *Factory::NewJSArrayWithElements(
9378 Handle<FixedArray>::cast(break_locations));
9379}
9380
9381
9382// Set a break point in a function
9383// args[0]: function
9384// args[1]: number: break source position (within the function source)
9385// args[2]: number: break point object
John Reck59135872010-11-02 12:39:01 -07009386static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009387 HandleScope scope;
9388 ASSERT(args.length() == 3);
9389 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9390 Handle<SharedFunctionInfo> shared(fun->shared());
9391 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9392 RUNTIME_ASSERT(source_position >= 0);
9393 Handle<Object> break_point_object_arg = args.at<Object>(2);
9394
9395 // Set break point.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009396 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +00009397
Steve Block8defd9f2010-07-08 12:39:36 +01009398 return Smi::FromInt(source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +00009399}
9400
9401
9402Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9403 int position) {
9404 // Iterate the heap looking for SharedFunctionInfo generated from the
9405 // script. The inner most SharedFunctionInfo containing the source position
9406 // for the requested break point is found.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009407 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
Steve Blocka7e24c12009-10-30 11:49:00 +00009408 // which is found is not compiled it is compiled and the heap is iterated
9409 // again as the compilation might create inner functions from the newly
9410 // compiled function and the actual requested break point might be in one of
9411 // these functions.
9412 bool done = false;
9413 // The current candidate for the source position:
9414 int target_start_position = RelocInfo::kNoPosition;
9415 Handle<SharedFunctionInfo> target;
Steve Blocka7e24c12009-10-30 11:49:00 +00009416 while (!done) {
9417 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00009418 for (HeapObject* obj = iterator.next();
9419 obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009420 if (obj->IsSharedFunctionInfo()) {
9421 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9422 if (shared->script() == *script) {
9423 // If the SharedFunctionInfo found has the requested script data and
9424 // contains the source position it is a candidate.
9425 int start_position = shared->function_token_position();
9426 if (start_position == RelocInfo::kNoPosition) {
9427 start_position = shared->start_position();
9428 }
9429 if (start_position <= position &&
9430 position <= shared->end_position()) {
9431 // If there is no candidate or this function is within the current
9432 // candidate this is the new candidate.
9433 if (target.is_null()) {
9434 target_start_position = start_position;
9435 target = shared;
9436 } else {
9437 if (target_start_position == start_position &&
9438 shared->end_position() == target->end_position()) {
9439 // If a top-level function contain only one function
9440 // declartion the source for the top-level and the function is
9441 // the same. In that case prefer the non top-level function.
9442 if (!shared->is_toplevel()) {
9443 target_start_position = start_position;
9444 target = shared;
9445 }
9446 } else if (target_start_position <= start_position &&
9447 shared->end_position() <= target->end_position()) {
9448 // This containment check includes equality as a function inside
9449 // a top-level function can share either start or end position
9450 // with the top-level function.
9451 target_start_position = start_position;
9452 target = shared;
9453 }
9454 }
9455 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009456 }
9457 }
9458 }
9459
Steve Blocka7e24c12009-10-30 11:49:00 +00009460 if (target.is_null()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009461 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009462 }
9463
9464 // If the candidate found is compiled we are done. NOTE: when lazy
9465 // compilation of inner functions is introduced some additional checking
9466 // needs to be done here to compile inner functions.
9467 done = target->is_compiled();
9468 if (!done) {
9469 // If the candidate is not compiled compile it to reveal any inner
9470 // functions which might contain the requested source position.
Leon Clarke4515c472010-02-03 11:58:03 +00009471 CompileLazyShared(target, KEEP_EXCEPTION);
Steve Blocka7e24c12009-10-30 11:49:00 +00009472 }
9473 }
9474
9475 return *target;
9476}
9477
9478
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009479// Changes the state of a break point in a script and returns source position
9480// where break point was set. NOTE: Regarding performance see the NOTE for
9481// GetScriptFromScriptData.
Steve Blocka7e24c12009-10-30 11:49:00 +00009482// args[0]: script to set break point in
9483// args[1]: number: break source position (within the script source)
9484// args[2]: number: break point object
John Reck59135872010-11-02 12:39:01 -07009485static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009486 HandleScope scope;
9487 ASSERT(args.length() == 3);
9488 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9489 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9490 RUNTIME_ASSERT(source_position >= 0);
9491 Handle<Object> break_point_object_arg = args.at<Object>(2);
9492
9493 // Get the script from the script wrapper.
9494 RUNTIME_ASSERT(wrapper->value()->IsScript());
9495 Handle<Script> script(Script::cast(wrapper->value()));
9496
9497 Object* result = Runtime::FindSharedFunctionInfoInScript(
9498 script, source_position);
9499 if (!result->IsUndefined()) {
9500 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9501 // Find position within function. The script position might be before the
9502 // source position of the first function.
9503 int position;
9504 if (shared->start_position() > source_position) {
9505 position = 0;
9506 } else {
9507 position = source_position - shared->start_position();
9508 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009509 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9510 position += shared->start_position();
9511 return Smi::FromInt(position);
Steve Blocka7e24c12009-10-30 11:49:00 +00009512 }
9513 return Heap::undefined_value();
9514}
9515
9516
9517// Clear a break point
9518// args[0]: number: break point object
John Reck59135872010-11-02 12:39:01 -07009519static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009520 HandleScope scope;
9521 ASSERT(args.length() == 1);
9522 Handle<Object> break_point_object_arg = args.at<Object>(0);
9523
9524 // Clear break point.
9525 Debug::ClearBreakPoint(break_point_object_arg);
9526
9527 return Heap::undefined_value();
9528}
9529
9530
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009531// Change the state of break on exceptions.
9532// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9533// args[1]: Boolean indicating on/off.
John Reck59135872010-11-02 12:39:01 -07009534static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009535 HandleScope scope;
9536 ASSERT(args.length() == 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009537 RUNTIME_ASSERT(args[0]->IsNumber());
9538 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +00009539
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009540 // If the number doesn't match an enum value, the ChangeBreakOnException
9541 // function will default to affecting caught exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +00009542 ExceptionBreakType type =
9543 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009544 // Update break point state.
Steve Blocka7e24c12009-10-30 11:49:00 +00009545 Debug::ChangeBreakOnException(type, enable);
9546 return Heap::undefined_value();
9547}
9548
9549
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009550// Returns the state of break on exceptions
9551// args[0]: boolean indicating uncaught exceptions
John Reck59135872010-11-02 12:39:01 -07009552static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009553 HandleScope scope;
9554 ASSERT(args.length() == 1);
9555 RUNTIME_ASSERT(args[0]->IsNumber());
9556
9557 ExceptionBreakType type =
9558 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9559 bool result = Debug::IsBreakOnException(type);
9560 return Smi::FromInt(result);
9561}
9562
9563
Steve Blocka7e24c12009-10-30 11:49:00 +00009564// Prepare for stepping
9565// args[0]: break id for checking execution state
9566// args[1]: step action from the enumeration StepAction
9567// args[2]: number of times to perform the step, for step out it is the number
9568// of frames to step down.
John Reck59135872010-11-02 12:39:01 -07009569static MaybeObject* Runtime_PrepareStep(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009570 HandleScope scope;
9571 ASSERT(args.length() == 3);
9572 // Check arguments.
John Reck59135872010-11-02 12:39:01 -07009573 Object* check;
9574 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9575 if (!maybe_check->ToObject(&check)) return maybe_check;
9576 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009577 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9578 return Top::Throw(Heap::illegal_argument_symbol());
9579 }
9580
9581 // Get the step action and check validity.
9582 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9583 if (step_action != StepIn &&
9584 step_action != StepNext &&
9585 step_action != StepOut &&
9586 step_action != StepInMin &&
9587 step_action != StepMin) {
9588 return Top::Throw(Heap::illegal_argument_symbol());
9589 }
9590
9591 // Get the number of steps.
9592 int step_count = NumberToInt32(args[2]);
9593 if (step_count < 1) {
9594 return Top::Throw(Heap::illegal_argument_symbol());
9595 }
9596
9597 // Clear all current stepping setup.
9598 Debug::ClearStepping();
9599
9600 // Prepare step.
9601 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9602 return Heap::undefined_value();
9603}
9604
9605
9606// Clear all stepping set by PrepareStep.
John Reck59135872010-11-02 12:39:01 -07009607static MaybeObject* Runtime_ClearStepping(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009608 HandleScope scope;
9609 ASSERT(args.length() == 0);
9610 Debug::ClearStepping();
9611 return Heap::undefined_value();
9612}
9613
9614
9615// Creates a copy of the with context chain. The copy of the context chain is
9616// is linked to the function context supplied.
9617static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9618 Handle<Context> function_context) {
9619 // At the bottom of the chain. Return the function context to link to.
9620 if (context_chain->is_function_context()) {
9621 return function_context;
9622 }
9623
9624 // Recursively copy the with contexts.
9625 Handle<Context> previous(context_chain->previous());
9626 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009627 Handle<Context> context = CopyWithContextChain(function_context, previous);
9628 return Factory::NewWithContext(context,
9629 extension,
9630 context_chain->IsCatchContext());
Steve Blocka7e24c12009-10-30 11:49:00 +00009631}
9632
9633
9634// Helper function to find or create the arguments object for
9635// Runtime_DebugEvaluate.
9636static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9637 Handle<JSFunction> function,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009638 Handle<SerializedScopeInfo> scope_info,
Steve Blocka7e24c12009-10-30 11:49:00 +00009639 const ScopeInfo<>* sinfo,
9640 Handle<Context> function_context) {
9641 // Try to find the value of 'arguments' to pass as parameter. If it is not
9642 // found (that is the debugged function does not reference 'arguments' and
9643 // does not support eval) then create an 'arguments' object.
9644 int index;
9645 if (sinfo->number_of_stack_slots() > 0) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009646 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00009647 if (index != -1) {
9648 return Handle<Object>(frame->GetExpression(index));
9649 }
9650 }
9651
9652 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009653 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009654 if (index != -1) {
9655 return Handle<Object>(function_context->get(index));
9656 }
9657 }
9658
9659 const int length = frame->GetProvidedParametersCount();
9660 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9661 Handle<FixedArray> array = Factory::NewFixedArray(length);
Leon Clarke4515c472010-02-03 11:58:03 +00009662
9663 AssertNoAllocation no_gc;
9664 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009665 for (int i = 0; i < length; i++) {
9666 array->set(i, frame->GetParameter(i), mode);
9667 }
9668 arguments->set_elements(*array);
9669 return arguments;
9670}
9671
9672
9673// Evaluate a piece of JavaScript in the context of a stack frame for
9674// debugging. This is accomplished by creating a new context which in its
9675// extension part has all the parameters and locals of the function on the
9676// stack frame. A function which calls eval with the code to evaluate is then
9677// compiled in this context and called in this context. As this context
9678// replaces the context of the function on the stack frame a new (empty)
9679// function is created as well to be used as the closure for the context.
9680// This function and the context acts as replacements for the function on the
9681// stack frame presenting the same view of the values of parameters and
9682// local variables as if the piece of JavaScript was evaluated at the point
9683// where the function on the stack frame is currently stopped.
John Reck59135872010-11-02 12:39:01 -07009684static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009685 HandleScope scope;
9686
9687 // Check the execution state and decode arguments frame and source to be
9688 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009689 ASSERT(args.length() == 5);
John Reck59135872010-11-02 12:39:01 -07009690 Object* check_result;
9691 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9692 if (!maybe_check_result->ToObject(&check_result)) {
9693 return maybe_check_result;
9694 }
9695 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009696 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9697 CONVERT_ARG_CHECKED(String, source, 2);
9698 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009699 Handle<Object> additional_context(args[4]);
Steve Blocka7e24c12009-10-30 11:49:00 +00009700
9701 // Handle the processing of break.
9702 DisableBreak disable_break_save(disable_break);
9703
9704 // Get the frame where the debugging is performed.
9705 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9706 JavaScriptFrameIterator it(id);
9707 JavaScriptFrame* frame = it.frame();
9708 Handle<JSFunction> function(JSFunction::cast(frame->function()));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009709 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
9710 ScopeInfo<> sinfo(*scope_info);
Steve Blocka7e24c12009-10-30 11:49:00 +00009711
9712 // Traverse the saved contexts chain to find the active context for the
9713 // selected frame.
9714 SaveContext* save = Top::save_context();
9715 while (save != NULL && !save->below(frame)) {
9716 save = save->prev();
9717 }
9718 ASSERT(save != NULL);
9719 SaveContext savex;
9720 Top::set_context(*(save->context()));
9721
9722 // Create the (empty) function replacing the function on the stack frame for
9723 // the purpose of evaluating in the context created below. It is important
9724 // that this function does not describe any parameters and local variables
9725 // in the context. If it does then this will cause problems with the lookup
9726 // in Context::Lookup, where context slots for parameters and local variables
9727 // are looked at before the extension object.
9728 Handle<JSFunction> go_between =
9729 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9730 go_between->set_context(function->context());
9731#ifdef DEBUG
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009732 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +00009733 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9734 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9735#endif
9736
9737 // Materialize the content of the local scope into a JSObject.
9738 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
9739
9740 // Allocate a new context for the debug evaluation and set the extension
9741 // object build.
9742 Handle<Context> context =
9743 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9744 context->set_extension(*local_scope);
9745 // Copy any with contexts present and chain them in front of this context.
9746 Handle<Context> frame_context(Context::cast(frame->context()));
9747 Handle<Context> function_context(frame_context->fcontext());
9748 context = CopyWithContextChain(frame_context, context);
9749
Ben Murdochb0fe1622011-05-05 13:52:32 +01009750 if (additional_context->IsJSObject()) {
9751 context = Factory::NewWithContext(context,
9752 Handle<JSObject>::cast(additional_context), false);
9753 }
9754
Steve Blocka7e24c12009-10-30 11:49:00 +00009755 // Wrap the evaluation statement in a new function compiled in the newly
9756 // created context. The function has one parameter which has to be called
9757 // 'arguments'. This it to have access to what would have been 'arguments' in
9758 // the function being debugged.
9759 // function(arguments,__source__) {return eval(__source__);}
9760 static const char* source_str =
9761 "(function(arguments,__source__){return eval(__source__);})";
Steve Blockd0582a62009-12-15 09:54:21 +00009762 static const int source_str_length = StrLength(source_str);
Steve Blocka7e24c12009-10-30 11:49:00 +00009763 Handle<String> function_source =
9764 Factory::NewStringFromAscii(Vector<const char>(source_str,
9765 source_str_length));
Steve Block6ded16b2010-05-10 14:33:55 +01009766 Handle<SharedFunctionInfo> shared =
Steve Blocka7e24c12009-10-30 11:49:00 +00009767 Compiler::CompileEval(function_source,
9768 context,
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08009769 context->IsGlobalContext());
Steve Block6ded16b2010-05-10 14:33:55 +01009770 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00009771 Handle<JSFunction> compiled_function =
Steve Block6ded16b2010-05-10 14:33:55 +01009772 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
Steve Blocka7e24c12009-10-30 11:49:00 +00009773
9774 // Invoke the result of the compilation to get the evaluation function.
9775 bool has_pending_exception;
9776 Handle<Object> receiver(frame->receiver());
9777 Handle<Object> evaluation_function =
9778 Execution::Call(compiled_function, receiver, 0, NULL,
9779 &has_pending_exception);
9780 if (has_pending_exception) return Failure::Exception();
9781
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009782 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9783 &sinfo, function_context);
Steve Blocka7e24c12009-10-30 11:49:00 +00009784
9785 // Invoke the evaluation function and return the result.
9786 const int argc = 2;
9787 Object** argv[argc] = { arguments.location(),
9788 Handle<Object>::cast(source).location() };
9789 Handle<Object> result =
9790 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9791 argc, argv, &has_pending_exception);
9792 if (has_pending_exception) return Failure::Exception();
9793
9794 // Skip the global proxy as it has no properties and always delegates to the
9795 // real global object.
9796 if (result->IsJSGlobalProxy()) {
9797 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9798 }
9799
9800 return *result;
9801}
9802
9803
John Reck59135872010-11-02 12:39:01 -07009804static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009805 HandleScope scope;
9806
9807 // Check the execution state and decode arguments frame and source to be
9808 // evaluated.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009809 ASSERT(args.length() == 4);
John Reck59135872010-11-02 12:39:01 -07009810 Object* check_result;
9811 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9812 if (!maybe_check_result->ToObject(&check_result)) {
9813 return maybe_check_result;
9814 }
9815 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009816 CONVERT_ARG_CHECKED(String, source, 1);
9817 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009818 Handle<Object> additional_context(args[3]);
Steve Blocka7e24c12009-10-30 11:49:00 +00009819
9820 // Handle the processing of break.
9821 DisableBreak disable_break_save(disable_break);
9822
9823 // Enter the top context from before the debugger was invoked.
9824 SaveContext save;
9825 SaveContext* top = &save;
9826 while (top != NULL && *top->context() == *Debug::debug_context()) {
9827 top = top->prev();
9828 }
9829 if (top != NULL) {
9830 Top::set_context(*top->context());
9831 }
9832
9833 // Get the global context now set to the top context from before the
9834 // debugger was invoked.
9835 Handle<Context> context = Top::global_context();
9836
Ben Murdochb0fe1622011-05-05 13:52:32 +01009837 bool is_global = true;
9838
9839 if (additional_context->IsJSObject()) {
9840 // Create a function context first, than put 'with' context on top of it.
9841 Handle<JSFunction> go_between = Factory::NewFunction(
9842 Factory::empty_string(), Factory::undefined_value());
9843 go_between->set_context(*context);
9844 context =
9845 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9846 context->set_extension(JSObject::cast(*additional_context));
9847 is_global = false;
9848 }
9849
Steve Blocka7e24c12009-10-30 11:49:00 +00009850 // Compile the source to be evaluated.
Steve Block6ded16b2010-05-10 14:33:55 +01009851 Handle<SharedFunctionInfo> shared =
9852 Compiler::CompileEval(source,
9853 context,
Ben Murdochb0fe1622011-05-05 13:52:32 +01009854 is_global);
Steve Block6ded16b2010-05-10 14:33:55 +01009855 if (shared.is_null()) return Failure::Exception();
Steve Blocka7e24c12009-10-30 11:49:00 +00009856 Handle<JSFunction> compiled_function =
Steve Block6ded16b2010-05-10 14:33:55 +01009857 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9858 context));
Steve Blocka7e24c12009-10-30 11:49:00 +00009859
9860 // Invoke the result of the compilation to get the evaluation function.
9861 bool has_pending_exception;
9862 Handle<Object> receiver = Top::global();
9863 Handle<Object> result =
9864 Execution::Call(compiled_function, receiver, 0, NULL,
9865 &has_pending_exception);
9866 if (has_pending_exception) return Failure::Exception();
9867 return *result;
9868}
9869
9870
John Reck59135872010-11-02 12:39:01 -07009871static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009872 HandleScope scope;
9873 ASSERT(args.length() == 0);
9874
9875 // Fill the script objects.
9876 Handle<FixedArray> instances = Debug::GetLoadedScripts();
9877
9878 // Convert the script objects to proper JS objects.
9879 for (int i = 0; i < instances->length(); i++) {
9880 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9881 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9882 // because using
9883 // instances->set(i, *GetScriptWrapper(script))
9884 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9885 // already have deferenced the instances handle.
9886 Handle<JSValue> wrapper = GetScriptWrapper(script);
9887 instances->set(i, *wrapper);
9888 }
9889
9890 // Return result as a JS array.
9891 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9892 Handle<JSArray>::cast(result)->SetContent(*instances);
9893 return *result;
9894}
9895
9896
9897// Helper function used by Runtime_DebugReferencedBy below.
9898static int DebugReferencedBy(JSObject* target,
9899 Object* instance_filter, int max_references,
9900 FixedArray* instances, int instances_size,
9901 JSFunction* arguments_function) {
9902 NoHandleAllocation ha;
9903 AssertNoAllocation no_alloc;
9904
9905 // Iterate the heap.
9906 int count = 0;
9907 JSObject* last = NULL;
9908 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00009909 HeapObject* heap_obj = NULL;
9910 while (((heap_obj = iterator.next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +00009911 (max_references == 0 || count < max_references)) {
9912 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +00009913 if (heap_obj->IsJSObject()) {
9914 // Skip context extension objects and argument arrays as these are
9915 // checked in the context of functions using them.
9916 JSObject* obj = JSObject::cast(heap_obj);
9917 if (obj->IsJSContextExtensionObject() ||
9918 obj->map()->constructor() == arguments_function) {
9919 continue;
9920 }
9921
9922 // Check if the JS object has a reference to the object looked for.
9923 if (obj->ReferencesObject(target)) {
9924 // Check instance filter if supplied. This is normally used to avoid
9925 // references from mirror objects (see Runtime_IsInPrototypeChain).
9926 if (!instance_filter->IsUndefined()) {
9927 Object* V = obj;
9928 while (true) {
9929 Object* prototype = V->GetPrototype();
9930 if (prototype->IsNull()) {
9931 break;
9932 }
9933 if (instance_filter == prototype) {
9934 obj = NULL; // Don't add this object.
9935 break;
9936 }
9937 V = prototype;
9938 }
9939 }
9940
9941 if (obj != NULL) {
9942 // Valid reference found add to instance array if supplied an update
9943 // count.
9944 if (instances != NULL && count < instances_size) {
9945 instances->set(count, obj);
9946 }
9947 last = obj;
9948 count++;
9949 }
9950 }
9951 }
9952 }
9953
9954 // Check for circular reference only. This can happen when the object is only
9955 // referenced from mirrors and has a circular reference in which case the
9956 // object is not really alive and would have been garbage collected if not
9957 // referenced from the mirror.
9958 if (count == 1 && last == target) {
9959 count = 0;
9960 }
9961
9962 // Return the number of referencing objects found.
9963 return count;
9964}
9965
9966
9967// Scan the heap for objects with direct references to an object
9968// args[0]: the object to find references to
9969// args[1]: constructor function for instances to exclude (Mirror)
9970// args[2]: the the maximum number of objects to return
John Reck59135872010-11-02 12:39:01 -07009971static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009972 ASSERT(args.length() == 3);
9973
9974 // First perform a full GC in order to avoid references from dead objects.
9975 Heap::CollectAllGarbage(false);
9976
9977 // Check parameters.
9978 CONVERT_CHECKED(JSObject, target, args[0]);
9979 Object* instance_filter = args[1];
9980 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9981 instance_filter->IsJSObject());
9982 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9983 RUNTIME_ASSERT(max_references >= 0);
9984
9985 // Get the constructor function for context extension and arguments array.
9986 JSObject* arguments_boilerplate =
9987 Top::context()->global_context()->arguments_boilerplate();
9988 JSFunction* arguments_function =
9989 JSFunction::cast(arguments_boilerplate->map()->constructor());
9990
9991 // Get the number of referencing objects.
9992 int count;
9993 count = DebugReferencedBy(target, instance_filter, max_references,
9994 NULL, 0, arguments_function);
9995
9996 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -07009997 Object* object;
9998 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9999 if (!maybe_object->ToObject(&object)) return maybe_object;
10000 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010001 FixedArray* instances = FixedArray::cast(object);
10002
10003 // Fill the referencing objects.
10004 count = DebugReferencedBy(target, instance_filter, max_references,
10005 instances, count, arguments_function);
10006
10007 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070010008 Object* result;
10009 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10010 Top::context()->global_context()->array_function());
10011 if (!maybe_result->ToObject(&result)) return maybe_result;
10012 }
10013 JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000010014 return result;
10015}
10016
10017
10018// Helper function used by Runtime_DebugConstructedBy below.
10019static int DebugConstructedBy(JSFunction* constructor, int max_references,
10020 FixedArray* instances, int instances_size) {
10021 AssertNoAllocation no_alloc;
10022
10023 // Iterate the heap.
10024 int count = 0;
10025 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000010026 HeapObject* heap_obj = NULL;
10027 while (((heap_obj = iterator.next()) != NULL) &&
Steve Blocka7e24c12009-10-30 11:49:00 +000010028 (max_references == 0 || count < max_references)) {
10029 // Only look at all JSObjects.
Steve Blocka7e24c12009-10-30 11:49:00 +000010030 if (heap_obj->IsJSObject()) {
10031 JSObject* obj = JSObject::cast(heap_obj);
10032 if (obj->map()->constructor() == constructor) {
10033 // Valid reference found add to instance array if supplied an update
10034 // count.
10035 if (instances != NULL && count < instances_size) {
10036 instances->set(count, obj);
10037 }
10038 count++;
10039 }
10040 }
10041 }
10042
10043 // Return the number of referencing objects found.
10044 return count;
10045}
10046
10047
10048// Scan the heap for objects constructed by a specific function.
10049// args[0]: the constructor to find instances of
10050// args[1]: the the maximum number of objects to return
John Reck59135872010-11-02 12:39:01 -070010051static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010052 ASSERT(args.length() == 2);
10053
10054 // First perform a full GC in order to avoid dead objects.
10055 Heap::CollectAllGarbage(false);
10056
10057 // Check parameters.
10058 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10059 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10060 RUNTIME_ASSERT(max_references >= 0);
10061
10062 // Get the number of referencing objects.
10063 int count;
10064 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10065
10066 // Allocate an array to hold the result.
John Reck59135872010-11-02 12:39:01 -070010067 Object* object;
10068 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10069 if (!maybe_object->ToObject(&object)) return maybe_object;
10070 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010071 FixedArray* instances = FixedArray::cast(object);
10072
10073 // Fill the referencing objects.
10074 count = DebugConstructedBy(constructor, max_references, instances, count);
10075
10076 // Return result as JS array.
John Reck59135872010-11-02 12:39:01 -070010077 Object* result;
10078 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10079 Top::context()->global_context()->array_function());
10080 if (!maybe_result->ToObject(&result)) return maybe_result;
10081 }
10082 JSArray::cast(result)->SetContent(instances);
Steve Blocka7e24c12009-10-30 11:49:00 +000010083 return result;
10084}
10085
10086
10087// Find the effective prototype object as returned by __proto__.
10088// args[0]: the object to find the prototype for.
John Reck59135872010-11-02 12:39:01 -070010089static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010090 ASSERT(args.length() == 1);
10091
10092 CONVERT_CHECKED(JSObject, obj, args[0]);
10093
10094 // Use the __proto__ accessor.
10095 return Accessors::ObjectPrototype.getter(obj, NULL);
10096}
10097
10098
John Reck59135872010-11-02 12:39:01 -070010099static MaybeObject* Runtime_SystemBreak(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010100 ASSERT(args.length() == 0);
10101 CPU::DebugBreak();
10102 return Heap::undefined_value();
10103}
10104
10105
John Reck59135872010-11-02 12:39:01 -070010106static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010107#ifdef DEBUG
10108 HandleScope scope;
10109 ASSERT(args.length() == 1);
10110 // Get the function and make sure it is compiled.
10111 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000010112 Handle<SharedFunctionInfo> shared(func->shared());
10113 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010114 return Failure::Exception();
10115 }
10116 func->code()->PrintLn();
10117#endif // DEBUG
10118 return Heap::undefined_value();
10119}
10120
10121
John Reck59135872010-11-02 12:39:01 -070010122static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010123#ifdef DEBUG
10124 HandleScope scope;
10125 ASSERT(args.length() == 1);
10126 // Get the function and make sure it is compiled.
10127 CONVERT_ARG_CHECKED(JSFunction, func, 0);
Leon Clarke4515c472010-02-03 11:58:03 +000010128 Handle<SharedFunctionInfo> shared(func->shared());
10129 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010130 return Failure::Exception();
10131 }
Leon Clarke4515c472010-02-03 11:58:03 +000010132 shared->construct_stub()->PrintLn();
Steve Blocka7e24c12009-10-30 11:49:00 +000010133#endif // DEBUG
10134 return Heap::undefined_value();
10135}
10136
10137
John Reck59135872010-11-02 12:39:01 -070010138static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010139 NoHandleAllocation ha;
10140 ASSERT(args.length() == 1);
10141
10142 CONVERT_CHECKED(JSFunction, f, args[0]);
10143 return f->shared()->inferred_name();
10144}
Steve Blockd0582a62009-12-15 09:54:21 +000010145
Steve Block6ded16b2010-05-10 14:33:55 +010010146
10147static int FindSharedFunctionInfosForScript(Script* script,
10148 FixedArray* buffer) {
10149 AssertNoAllocation no_allocations;
10150
10151 int counter = 0;
10152 int buffer_size = buffer->length();
10153 HeapIterator iterator;
10154 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10155 ASSERT(obj != NULL);
10156 if (!obj->IsSharedFunctionInfo()) {
10157 continue;
10158 }
10159 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10160 if (shared->script() != script) {
10161 continue;
10162 }
10163 if (counter < buffer_size) {
10164 buffer->set(counter, shared);
10165 }
10166 counter++;
10167 }
10168 return counter;
10169}
10170
10171// For a script finds all SharedFunctionInfo's in the heap that points
10172// to this script. Returns JSArray of SharedFunctionInfo wrapped
10173// in OpaqueReferences.
John Reck59135872010-11-02 12:39:01 -070010174static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
Steve Block6ded16b2010-05-10 14:33:55 +010010175 Arguments args) {
10176 ASSERT(args.length() == 1);
10177 HandleScope scope;
10178 CONVERT_CHECKED(JSValue, script_value, args[0]);
10179
10180 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10181
10182 const int kBufferSize = 32;
10183
10184 Handle<FixedArray> array;
10185 array = Factory::NewFixedArray(kBufferSize);
10186 int number = FindSharedFunctionInfosForScript(*script, *array);
10187 if (number > kBufferSize) {
10188 array = Factory::NewFixedArray(number);
10189 FindSharedFunctionInfosForScript(*script, *array);
10190 }
10191
10192 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10193 result->set_length(Smi::FromInt(number));
10194
10195 LiveEdit::WrapSharedFunctionInfos(result);
10196
10197 return *result;
10198}
10199
10200// For a script calculates compilation information about all its functions.
10201// The script source is explicitly specified by the second argument.
10202// The source of the actual script is not used, however it is important that
10203// all generated code keeps references to this particular instance of script.
10204// Returns a JSArray of compilation infos. The array is ordered so that
10205// each function with all its descendant is always stored in a continues range
10206// with the function itself going first. The root function is a script function.
John Reck59135872010-11-02 12:39:01 -070010207static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010208 ASSERT(args.length() == 2);
10209 HandleScope scope;
10210 CONVERT_CHECKED(JSValue, script, args[0]);
10211 CONVERT_ARG_CHECKED(String, source, 1);
10212 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10213
10214 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10215
10216 if (Top::has_pending_exception()) {
10217 return Failure::Exception();
10218 }
10219
10220 return result;
10221}
10222
10223// Changes the source of the script to a new_source.
10224// If old_script_name is provided (i.e. is a String), also creates a copy of
10225// the script with its original source and sends notification to debugger.
John Reck59135872010-11-02 12:39:01 -070010226static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010227 ASSERT(args.length() == 3);
10228 HandleScope scope;
10229 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10230 CONVERT_ARG_CHECKED(String, new_source, 1);
10231 Handle<Object> old_script_name(args[2]);
10232
10233 CONVERT_CHECKED(Script, original_script_pointer,
10234 original_script_value->value());
10235 Handle<Script> original_script(original_script_pointer);
10236
10237 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10238 new_source,
10239 old_script_name);
10240
10241 if (old_script->IsScript()) {
10242 Handle<Script> script_handle(Script::cast(old_script));
10243 return *(GetScriptWrapper(script_handle));
10244 } else {
10245 return Heap::null_value();
10246 }
10247}
10248
Ben Murdochb0fe1622011-05-05 13:52:32 +010010249
10250static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10251 ASSERT(args.length() == 1);
10252 HandleScope scope;
10253 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10254 return LiveEdit::FunctionSourceUpdated(shared_info);
10255}
10256
10257
Steve Block6ded16b2010-05-10 14:33:55 +010010258// Replaces code of SharedFunctionInfo with a new one.
John Reck59135872010-11-02 12:39:01 -070010259static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010260 ASSERT(args.length() == 2);
10261 HandleScope scope;
10262 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10263 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10264
10265 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
10266}
10267
10268// Connects SharedFunctionInfo to another script.
John Reck59135872010-11-02 12:39:01 -070010269static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010270 ASSERT(args.length() == 2);
10271 HandleScope scope;
10272 Handle<Object> function_object(args[0]);
10273 Handle<Object> script_object(args[1]);
10274
10275 if (function_object->IsJSValue()) {
10276 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10277 if (script_object->IsJSValue()) {
10278 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10279 script_object = Handle<Object>(script);
10280 }
10281
10282 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10283 } else {
10284 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10285 // and we check it in this function.
10286 }
10287
10288 return Heap::undefined_value();
10289}
10290
10291
10292// In a code of a parent function replaces original function as embedded object
10293// with a substitution one.
John Reck59135872010-11-02 12:39:01 -070010294static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010295 ASSERT(args.length() == 3);
10296 HandleScope scope;
10297
10298 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10299 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10300 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10301
10302 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10303 subst_wrapper);
10304
10305 return Heap::undefined_value();
10306}
10307
10308
10309// Updates positions of a shared function info (first parameter) according
10310// to script source change. Text change is described in second parameter as
10311// array of groups of 3 numbers:
10312// (change_begin, change_end, change_end_new_position).
10313// Each group describes a change in text; groups are sorted by change_begin.
John Reck59135872010-11-02 12:39:01 -070010314static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010315 ASSERT(args.length() == 2);
10316 HandleScope scope;
10317 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10318 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10319
10320 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
10321}
10322
10323
10324// For array of SharedFunctionInfo's (each wrapped in JSValue)
10325// checks that none of them have activations on stacks (of any thread).
10326// Returns array of the same length with corresponding results of
10327// LiveEdit::FunctionPatchabilityStatus type.
John Reck59135872010-11-02 12:39:01 -070010328static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010329 ASSERT(args.length() == 2);
10330 HandleScope scope;
10331 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10332 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
10333
10334 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
10335}
10336
10337// Compares 2 strings line-by-line and returns diff in form of JSArray of
10338// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
John Reck59135872010-11-02 12:39:01 -070010339static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010340 ASSERT(args.length() == 2);
10341 HandleScope scope;
10342 CONVERT_ARG_CHECKED(String, s1, 0);
10343 CONVERT_ARG_CHECKED(String, s2, 1);
10344
10345 return *LiveEdit::CompareStringsLinewise(s1, s2);
10346}
10347
10348
10349
10350// A testing entry. Returns statement position which is the closest to
10351// source_position.
John Reck59135872010-11-02 12:39:01 -070010352static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010353 ASSERT(args.length() == 2);
10354 HandleScope scope;
10355 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10356 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10357
10358 Handle<Code> code(function->code());
10359
Ben Murdochb0fe1622011-05-05 13:52:32 +010010360 if (code->kind() != Code::FUNCTION &&
10361 code->kind() != Code::OPTIMIZED_FUNCTION) {
10362 return Heap::undefined_value();
10363 }
10364
10365 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
Steve Block6ded16b2010-05-10 14:33:55 +010010366 int closest_pc = 0;
10367 int distance = kMaxInt;
10368 while (!it.done()) {
10369 int statement_position = static_cast<int>(it.rinfo()->data());
10370 // Check if this break point is closer that what was previously found.
10371 if (source_position <= statement_position &&
10372 statement_position - source_position < distance) {
10373 closest_pc =
10374 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
10375 distance = statement_position - source_position;
10376 // Check whether we can't get any closer.
10377 if (distance == 0) break;
10378 }
10379 it.next();
10380 }
10381
10382 return Smi::FromInt(closest_pc);
10383}
10384
10385
10386// Calls specified function with or without entering the debugger.
10387// This is used in unit tests to run code as if debugger is entered or simply
10388// to have a stack with C++ frame in the middle.
John Reck59135872010-11-02 12:39:01 -070010389static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010390 ASSERT(args.length() == 2);
10391 HandleScope scope;
10392 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10393 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10394
10395 Handle<Object> result;
10396 bool pending_exception;
10397 {
10398 if (without_debugger) {
10399 result = Execution::Call(function, Top::global(), 0, NULL,
10400 &pending_exception);
10401 } else {
10402 EnterDebugger enter_debugger;
10403 result = Execution::Call(function, Top::global(), 0, NULL,
10404 &pending_exception);
10405 }
10406 }
10407 if (!pending_exception) {
10408 return *result;
10409 } else {
10410 return Failure::Exception();
10411 }
10412}
10413
10414
Ben Murdoch086aeea2011-05-13 15:57:08 +010010415// Sets a v8 flag.
10416static MaybeObject* Runtime_SetFlags(Arguments args) {
10417 CONVERT_CHECKED(String, arg, args[0]);
10418 SmartPointer<char> flags =
10419 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10420 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10421 return Heap::undefined_value();
10422}
10423
10424
10425// Performs a GC.
10426// Presently, it only does a full GC.
10427static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10428 Heap::CollectAllGarbage(true);
10429 return Heap::undefined_value();
10430}
10431
10432
10433// Gets the current heap usage.
10434static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10435 int usage = static_cast<int>(Heap::SizeOfObjects());
10436 if (!Smi::IsValid(usage)) {
10437 return *Factory::NewNumberFromInt(usage);
10438 }
10439 return Smi::FromInt(usage);
10440}
Steve Blocka7e24c12009-10-30 11:49:00 +000010441#endif // ENABLE_DEBUGGER_SUPPORT
10442
Steve Blockd0582a62009-12-15 09:54:21 +000010443
Ben Murdoch086aeea2011-05-13 15:57:08 +010010444#ifdef ENABLE_LOGGING_AND_PROFILING
John Reck59135872010-11-02 12:39:01 -070010445static MaybeObject* Runtime_ProfilerResume(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +000010446 NoHandleAllocation ha;
Andrei Popescu402d9372010-02-26 13:31:12 +000010447 ASSERT(args.length() == 2);
Steve Blockd0582a62009-12-15 09:54:21 +000010448
10449 CONVERT_CHECKED(Smi, smi_modules, args[0]);
Andrei Popescu402d9372010-02-26 13:31:12 +000010450 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10451 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
Steve Blockd0582a62009-12-15 09:54:21 +000010452 return Heap::undefined_value();
10453}
10454
10455
John Reck59135872010-11-02 12:39:01 -070010456static MaybeObject* Runtime_ProfilerPause(Arguments args) {
Steve Blockd0582a62009-12-15 09:54:21 +000010457 NoHandleAllocation ha;
Andrei Popescu402d9372010-02-26 13:31:12 +000010458 ASSERT(args.length() == 2);
Steve Blockd0582a62009-12-15 09:54:21 +000010459
10460 CONVERT_CHECKED(Smi, smi_modules, args[0]);
Andrei Popescu402d9372010-02-26 13:31:12 +000010461 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10462 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
Steve Blockd0582a62009-12-15 09:54:21 +000010463 return Heap::undefined_value();
10464}
10465
10466#endif // ENABLE_LOGGING_AND_PROFILING
Steve Blocka7e24c12009-10-30 11:49:00 +000010467
10468// Finds the script object from the script data. NOTE: This operation uses
10469// heap traversal to find the function generated for the source position
10470// for the requested break point. For lazily compiled functions several heap
10471// traversals might be required rendering this operation as a rather slow
10472// operation. However for setting break points which is normally done through
10473// some kind of user interaction the performance is not crucial.
10474static Handle<Object> Runtime_GetScriptFromScriptName(
10475 Handle<String> script_name) {
10476 // Scan the heap for Script objects to find the script with the requested
10477 // script data.
10478 Handle<Script> script;
10479 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000010480 HeapObject* obj = NULL;
10481 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010482 // If a script is found check if it has the script data requested.
10483 if (obj->IsScript()) {
10484 if (Script::cast(obj)->name()->IsString()) {
10485 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10486 script = Handle<Script>(Script::cast(obj));
10487 }
10488 }
10489 }
10490 }
10491
10492 // If no script with the requested script data is found return undefined.
10493 if (script.is_null()) return Factory::undefined_value();
10494
10495 // Return the script found.
10496 return GetScriptWrapper(script);
10497}
10498
10499
10500// Get the script object from script data. NOTE: Regarding performance
10501// see the NOTE for GetScriptFromScriptData.
10502// args[0]: script data for the script to find the source for
John Reck59135872010-11-02 12:39:01 -070010503static MaybeObject* Runtime_GetScript(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010504 HandleScope scope;
10505
10506 ASSERT(args.length() == 1);
10507
10508 CONVERT_CHECKED(String, script_name, args[0]);
10509
10510 // Find the requested script.
10511 Handle<Object> result =
10512 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10513 return *result;
10514}
10515
10516
10517// Determines whether the given stack frame should be displayed in
10518// a stack trace. The caller is the error constructor that asked
10519// for the stack trace to be collected. The first time a construct
10520// call to this function is encountered it is skipped. The seen_caller
10521// in/out parameter is used to remember if the caller has been seen
10522// yet.
10523static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10524 bool* seen_caller) {
10525 // Only display JS frames.
10526 if (!raw_frame->is_java_script())
10527 return false;
10528 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10529 Object* raw_fun = frame->function();
10530 // Not sure when this can happen but skip it just in case.
10531 if (!raw_fun->IsJSFunction())
10532 return false;
10533 if ((raw_fun == caller) && !(*seen_caller)) {
10534 *seen_caller = true;
10535 return false;
10536 }
10537 // Skip all frames until we've seen the caller. Also, skip the most
10538 // obvious builtin calls. Some builtin calls (such as Number.ADD
10539 // which is invoked using 'call') are very difficult to recognize
10540 // so we're leaving them in for now.
10541 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
10542}
10543
10544
Ben Murdochb0fe1622011-05-05 13:52:32 +010010545// Collect the raw data for a stack trace. Returns an array of 4
10546// element segments each containing a receiver, function, code and
10547// native code offset.
John Reck59135872010-11-02 12:39:01 -070010548static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010549 ASSERT_EQ(args.length(), 2);
10550 Handle<Object> caller = args.at<Object>(0);
10551 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10552
10553 HandleScope scope;
10554
Leon Clarkee46be812010-01-19 14:06:41 +000010555 limit = Max(limit, 0); // Ensure that limit is not negative.
10556 int initial_size = Min(limit, 10);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010557 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
Steve Blocka7e24c12009-10-30 11:49:00 +000010558
10559 StackFrameIterator iter;
10560 // If the caller parameter is a function we skip frames until we're
10561 // under it before starting to collect.
10562 bool seen_caller = !caller->IsJSFunction();
10563 int cursor = 0;
10564 int frames_seen = 0;
10565 while (!iter.done() && frames_seen < limit) {
10566 StackFrame* raw_frame = iter.frame();
10567 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
10568 frames_seen++;
10569 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010570 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10571 frame->Summarize(&frames);
10572 for (int i = frames.length() - 1; i >= 0; i--) {
10573 Handle<Object> recv = frames[i].receiver();
10574 Handle<JSFunction> fun = frames[i].function();
10575 Handle<Code> code = frames[i].code();
10576 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10577 FixedArray* elements = FixedArray::cast(result->elements());
10578 if (cursor + 3 < elements->length()) {
10579 elements->set(cursor++, *recv);
10580 elements->set(cursor++, *fun);
10581 elements->set(cursor++, *code);
10582 elements->set(cursor++, *offset);
10583 } else {
10584 SetElement(result, cursor++, recv);
10585 SetElement(result, cursor++, fun);
10586 SetElement(result, cursor++, code);
10587 SetElement(result, cursor++, offset);
10588 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010589 }
10590 }
10591 iter.Advance();
10592 }
10593
Leon Clarke4515c472010-02-03 11:58:03 +000010594 result->set_length(Smi::FromInt(cursor));
Steve Blocka7e24c12009-10-30 11:49:00 +000010595 return *result;
10596}
10597
10598
Steve Block3ce2e202009-11-05 08:53:23 +000010599// Returns V8 version as a string.
John Reck59135872010-11-02 12:39:01 -070010600static MaybeObject* Runtime_GetV8Version(Arguments args) {
Steve Block3ce2e202009-11-05 08:53:23 +000010601 ASSERT_EQ(args.length(), 0);
10602
10603 NoHandleAllocation ha;
10604
10605 const char* version_string = v8::V8::GetVersion();
10606
10607 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10608}
10609
10610
John Reck59135872010-11-02 12:39:01 -070010611static MaybeObject* Runtime_Abort(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010612 ASSERT(args.length() == 2);
10613 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10614 Smi::cast(args[1])->value());
10615 Top::PrintStack();
10616 OS::Abort();
10617 UNREACHABLE();
10618 return NULL;
10619}
10620
10621
John Reck59135872010-11-02 12:39:01 -070010622MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10623 int index,
10624 Object* key_obj) {
Steve Block6ded16b2010-05-10 14:33:55 +010010625 ASSERT(index % 2 == 0); // index of the key
10626 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10627 ASSERT(index < cache_obj->length());
10628
10629 HandleScope scope;
10630
10631 Handle<FixedArray> cache(cache_obj);
10632 Handle<Object> key(key_obj);
10633 Handle<JSFunction> factory(JSFunction::cast(
10634 cache->get(JSFunctionResultCache::kFactoryIndex)));
10635 // TODO(antonm): consider passing a receiver when constructing a cache.
10636 Handle<Object> receiver(Top::global_context()->global());
10637
10638 Handle<Object> value;
10639 {
10640 // This handle is nor shared, nor used later, so it's safe.
10641 Object** argv[] = { key.location() };
10642 bool pending_exception = false;
10643 value = Execution::Call(factory,
10644 receiver,
10645 1,
10646 argv,
10647 &pending_exception);
10648 if (pending_exception) return Failure::Exception();
10649 }
10650
10651 cache->set(index, *key);
10652 cache->set(index + 1, *value);
10653 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10654
10655 return *value;
10656}
10657
10658
John Reck59135872010-11-02 12:39:01 -070010659static MaybeObject* Runtime_GetFromCache(Arguments args) {
Steve Block6ded16b2010-05-10 14:33:55 +010010660 // This is only called from codegen, so checks might be more lax.
10661 CONVERT_CHECKED(FixedArray, cache, args[0]);
10662 Object* key = args[1];
10663
10664 const int finger_index =
10665 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10666
10667 Object* o = cache->get(finger_index);
10668 if (o == key) {
10669 // The fastest case: hit the same place again.
10670 return cache->get(finger_index + 1);
10671 }
10672
10673 for (int i = finger_index - 2;
10674 i >= JSFunctionResultCache::kEntriesIndex;
10675 i -= 2) {
10676 o = cache->get(i);
10677 if (o == key) {
10678 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10679 return cache->get(i + 1);
10680 }
10681 }
10682
10683 const int size =
10684 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10685 ASSERT(size <= cache->length());
10686
10687 for (int i = size - 2; i > finger_index; i -= 2) {
10688 o = cache->get(i);
10689 if (o == key) {
10690 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10691 return cache->get(i + 1);
10692 }
10693 }
10694
10695 // Cache miss. If we have spare room, put new data into it, otherwise
10696 // evict post finger entry which must be least recently used.
10697 if (size < cache->length()) {
10698 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10699 return CacheMiss(cache, size, key);
10700 } else {
10701 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10702 if (target_index == cache->length()) {
10703 target_index = JSFunctionResultCache::kEntriesIndex;
10704 }
10705 return CacheMiss(cache, target_index, key);
10706 }
10707}
10708
Steve Blocka7e24c12009-10-30 11:49:00 +000010709#ifdef DEBUG
10710// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10711// Exclude the code in release mode.
John Reck59135872010-11-02 12:39:01 -070010712static MaybeObject* Runtime_ListNatives(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010713 ASSERT(args.length() == 0);
10714 HandleScope scope;
10715 Handle<JSArray> result = Factory::NewJSArray(0);
10716 int index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010717 bool inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010718#define ADD_ENTRY(Name, argc, ressize) \
10719 { \
10720 HandleScope inner; \
Steve Block6ded16b2010-05-10 14:33:55 +010010721 Handle<String> name; \
10722 /* Inline runtime functions have an underscore in front of the name. */ \
10723 if (inline_runtime_functions) { \
10724 name = Factory::NewStringFromAscii( \
10725 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10726 } else { \
10727 name = Factory::NewStringFromAscii( \
10728 Vector<const char>(#Name, StrLength(#Name))); \
10729 } \
Steve Blocka7e24c12009-10-30 11:49:00 +000010730 Handle<JSArray> pair = Factory::NewJSArray(0); \
10731 SetElement(pair, 0, name); \
10732 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10733 SetElement(result, index++, pair); \
10734 }
Steve Block6ded16b2010-05-10 14:33:55 +010010735 inline_runtime_functions = false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010736 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010010737 inline_runtime_functions = true;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010738 INLINE_FUNCTION_LIST(ADD_ENTRY)
Steve Block6ded16b2010-05-10 14:33:55 +010010739 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
Steve Blocka7e24c12009-10-30 11:49:00 +000010740#undef ADD_ENTRY
10741 return *result;
10742}
10743#endif
10744
10745
John Reck59135872010-11-02 12:39:01 -070010746static MaybeObject* Runtime_Log(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010747 ASSERT(args.length() == 2);
10748 CONVERT_CHECKED(String, format, args[0]);
10749 CONVERT_CHECKED(JSArray, elms, args[1]);
10750 Vector<const char> chars = format->ToAsciiVector();
10751 Logger::LogRuntime(chars, elms);
10752 return Heap::undefined_value();
10753}
10754
10755
John Reck59135872010-11-02 12:39:01 -070010756static MaybeObject* Runtime_IS_VAR(Arguments args) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010757 UNREACHABLE(); // implemented as macro in the parser
10758 return NULL;
10759}
10760
10761
10762// ----------------------------------------------------------------------------
10763// Implementation of Runtime
10764
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010765#define F(name, number_of_args, result_size) \
10766 { Runtime::k##name, Runtime::RUNTIME, #name, \
10767 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
Steve Blocka7e24c12009-10-30 11:49:00 +000010768
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010769
10770#define I(name, number_of_args, result_size) \
10771 { Runtime::kInline##name, Runtime::INLINE, \
10772 "_" #name, NULL, number_of_args, result_size },
10773
10774Runtime::Function kIntrinsicFunctions[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000010775 RUNTIME_FUNCTION_LIST(F)
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010776 INLINE_FUNCTION_LIST(I)
10777 INLINE_RUNTIME_FUNCTION_LIST(I)
Steve Blocka7e24c12009-10-30 11:49:00 +000010778};
10779
Steve Blocka7e24c12009-10-30 11:49:00 +000010780
John Reck59135872010-11-02 12:39:01 -070010781MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010782 ASSERT(dictionary != NULL);
10783 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10784 for (int i = 0; i < kNumFunctions; ++i) {
John Reck59135872010-11-02 12:39:01 -070010785 Object* name_symbol;
10786 { MaybeObject* maybe_name_symbol =
10787 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10788 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10789 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010790 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
John Reck59135872010-11-02 12:39:01 -070010791 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10792 String::cast(name_symbol),
10793 Smi::FromInt(i),
10794 PropertyDetails(NONE, NORMAL));
10795 if (!maybe_dictionary->ToObject(&dictionary)) {
10796 // Non-recoverable failure. Calling code must restart heap
10797 // initialization.
10798 return maybe_dictionary;
10799 }
10800 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010801 }
10802 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000010803}
10804
10805
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010806Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10807 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10808 if (entry != kNotFound) {
10809 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10810 int function_index = Smi::cast(smi_index)->value();
10811 return &(kIntrinsicFunctions[function_index]);
Steve Blocka7e24c12009-10-30 11:49:00 +000010812 }
10813 return NULL;
10814}
10815
10816
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010817Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10818 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10819}
10820
10821
Steve Blocka7e24c12009-10-30 11:49:00 +000010822void Runtime::PerformGC(Object* result) {
10823 Failure* failure = Failure::cast(result);
10824 if (failure->IsRetryAfterGC()) {
10825 // Try to do a garbage collection; ignore it if it fails. The C
10826 // entry stub will throw an out-of-memory exception in that case.
Ben Murdochf87a2032010-10-22 12:50:53 +010010827 Heap::CollectGarbage(failure->allocation_space());
Steve Blocka7e24c12009-10-30 11:49:00 +000010828 } else {
10829 // Handle last resort GC and make sure to allow future allocations
10830 // to grow the heap without causing GCs (if possible).
10831 Counters::gc_last_resort_from_js.Increment();
10832 Heap::CollectAllGarbage(false);
10833 }
10834}
10835
10836
10837} } // namespace v8::internal