1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
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.
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.
32 #include "accessors.h"
34 #include "arguments.h"
35 #include "bootstrapper.h"
37 #include "compilation-cache.h"
40 #include "dateparser-inl.h"
42 #include "deoptimizer.h"
44 #include "execution.h"
45 #include "global-handles.h"
46 #include "isolate-inl.h"
48 #include "json-parser.h"
50 #include "liveobjectlist-inl.h"
51 #include "misc-intrinsics.h"
54 #include "runtime-profiler.h"
56 #include "scopeinfo.h"
57 #include "smart-array-pointer.h"
58 #include "string-search.h"
59 #include "stub-cache.h"
60 #include "v8threads.h"
61 #include "vm-state-inl.h"
67 #define RUNTIME_ASSERT(value) \
68 if (!(value)) return isolate->ThrowIllegalOperation();
70 // Cast the given object to a value of the specified type and store
71 // it in a variable with the given name. If the object is not of the
72 // expected type call IllegalOperation and return.
73 #define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Type* name = Type::cast(args[index]);
77 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
79 Handle<Type> name = args.at<Type>(index);
81 // Cast the given object to a boolean and store it in a variable with
82 // the given name. If the object is not a boolean call IllegalOperation
84 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
88 // Cast the given argument to a Smi and store its value in an int variable
89 // with the given name. If the argument is not a Smi call IllegalOperation
91 #define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
95 // Cast the given argument to a double and store it in a variable with
96 // the given name. If the argument is not a number (as opposed to
97 // the number not-a-number) call IllegalOperation and return.
98 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
102 // Call the specified converter on the object *comand store the result in
103 // a variable of the specified type with the given name. If the
104 // object is not a Number call IllegalOperation and return.
105 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
110 // Cast the given argument to PropertyDetails and store its value in a
111 // variable with the given name. If the argument is not a Smi call
112 // IllegalOperation and return.
113 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
118 // Assert that the given argument has a valid value for a StrictModeFlag
119 // and store it in a StrictModeFlag variable with the given name.
120 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
128 // Assert that the given argument has a valid value for a LanguageMode
129 // and store it in a LanguageMode variable with the given name.
130 #define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
139 MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
144 Heap* heap = isolate->heap();
146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
147 if (!maybe_result->ToObject(&result)) return maybe_result;
149 JSObject* copy = JSObject::cast(result);
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
157 JSObject* js_object = JSObject::cast(value);
158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
159 if (!maybe_result->ToObject(&result)) return maybe_result;
161 properties->set(i, result);
164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
168 JSObject* js_object = JSObject::cast(value);
169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
170 if (!maybe_result->ToObject(&result)) return maybe_result;
172 copy->InObjectPropertyAtPut(i, result);
176 { MaybeObject* maybe_result =
177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
178 if (!maybe_result->ToObject(&result)) return maybe_result;
180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
184 String* key_string = String::cast(names->get(i));
185 PropertyAttributes attributes =
186 copy->GetLocalPropertyAttribute(key_string);
187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
190 if (attributes != NONE) continue;
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
193 if (value->IsJSObject()) {
194 JSObject* js_object = JSObject::cast(value);
195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
196 if (!maybe_result->ToObject(&result)) return maybe_result;
198 { MaybeObject* maybe_result =
199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
201 if (!maybe_result->ToObject(&result)) return maybe_result;
207 // Deep copy local elements.
208 // Pixel elements cannot be created using an object literal.
209 ASSERT(!copy->HasExternalArrayElements());
210 switch (copy->GetElementsKind()) {
211 case FAST_SMI_ONLY_ELEMENTS:
212 case FAST_ELEMENTS: {
213 FixedArray* elements = FixedArray::cast(copy->elements());
214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
231 if (!maybe_result->ToObject(&result)) return maybe_result;
233 elements->set(i, result);
239 case DICTIONARY_ELEMENTS: {
240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
247 JSObject* js_object = JSObject::cast(value);
248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
250 if (!maybe_result->ToObject(&result)) return maybe_result;
252 element_dictionary->ValueAtPut(i, result);
258 case NON_STRICT_ARGUMENTS_ELEMENTS:
261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
271 // No contained objects, nothing to do.
278 static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
281 bool* is_result_from_cache) {
282 Isolate* isolate = context->GetIsolate();
283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
318 ASSERT(index == number_of_symbol_keys);
320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
323 *is_result_from_cache = false;
324 return isolate->factory()->CopyMap(
325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
330 static Handle<Object> CreateLiteralBoilerplate(
332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
336 static Handle<Object> CreateObjectLiteralBoilerplate(
338 Handle<FixedArray> literals,
339 Handle<FixedArray> constant_properties,
340 bool should_have_fast_elements,
341 bool has_function_literal) {
342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
360 &is_result_from_cache);
362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
364 // Normalize the elements of the boilerplate to save space if needed.
365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
438 MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
451 return isolate->ThrowIllegalOperation();
455 static const int kSmiOnlyLiteralMinimumLength = 1024;
458 Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
479 object->set_map(Map::cast(global_context->object_js_array_map()));
482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
494 copied_elements_values = constant_elements_values;
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
538 static Handle<Object> CreateLiteralBoilerplate(
540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
543 const bool kHasNoFunctionLiteral = false;
544 switch (CompileTimeValue::GetType(array)) {
545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
546 return CreateObjectLiteralBoilerplate(isolate,
550 kHasNoFunctionLiteral);
551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
552 return CreateObjectLiteralBoilerplate(isolate,
556 kHasNoFunctionLiteral);
557 case CompileTimeValue::ARRAY_LITERAL:
558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
562 return Handle<Object>::null();
567 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
568 HandleScope scope(isolate);
569 ASSERT(args.length() == 4);
570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
573 CONVERT_SMI_ARG_CHECKED(flags, 3);
574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
577 // Check if boilerplate exists. If not, create it first.
578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
583 should_have_fast_elements,
584 has_function_literal);
585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
593 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
594 HandleScope scope(isolate);
595 ASSERT(args.length() == 4);
596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
599 CONVERT_SMI_ARG_CHECKED(flags, 3);
600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
603 // Check if boilerplate exists. If not, create it first.
604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
609 should_have_fast_elements,
610 has_function_literal);
611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
619 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
620 HandleScope scope(isolate);
621 ASSERT(args.length() == 3);
622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
626 // Check if boilerplate exists. If not, create it first.
627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
639 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
640 HandleScope scope(isolate);
641 ASSERT(args.length() == 3);
642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
646 // Check if boilerplate exists. If not, create it first.
647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
656 if (JSObject::cast(*boilerplate)->elements()->map() ==
657 isolate->heap()->fixed_cow_array_map()) {
658 isolate->counters()->cow_arrays_created_runtime()->Increment();
660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
664 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
674 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
687 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
694 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
701 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
704 return proxy->handler();
708 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
711 return proxy->call_trap();
715 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
718 return proxy->construct_trap();
722 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
726 return isolate->heap()->undefined_value();
730 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
740 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
752 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
762 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
774 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
784 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
793 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
806 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
818 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
827 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
832 Handle<Object> value(args[2]);
833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
840 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
845 return JSObject::cast(obj)->class_name();
849 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
864 obj = obj->GetPrototype();
865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
871 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
878 Object* prototype = V->GetPrototype();
879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
886 // Recursively traverses hidden prototypes if property is not found
887 static void GetOwnPropertyImplementation(JSObject* obj,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
902 static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
921 static bool CheckAccess(JSObject* obj,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
929 Isolate* isolate = obj->GetIsolate();
931 if (current->IsAccessCheckNeeded() &&
932 !isolate->MayNamedAccess(current, name, access_type)) {
933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
939 if (current == holder) {
943 current = JSObject::cast(current->GetPrototype());
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
949 if (CheckAccessException(result, access_type)) {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
969 isolate->ReportFailedAccessCheck(current, access_type);
974 // TODO(1095): we should traverse hidden prototype hierachy as well.
975 static bool CheckElementAccess(JSObject* obj,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
987 // Enumerator used as indices into the array returned from GetOwnProperty
988 enum PropertyDescriptorIndices {
1000 static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
1003 Heap* heap = isolate->heap();
1004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
1006 LookupResult result(isolate);
1007 // This could be an element.
1009 if (name->AsArrayIndex(&index)) {
1010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
1012 return heap->undefined_value();
1014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
1021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
1023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1024 elms->set(VALUE_INDEX, *substr);
1025 elms->set(WRITABLE_INDEX, heap->false_value());
1026 elms->set(ENUMERABLE_INDEX, heap->true_value());
1027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
1033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1034 Handle<Object> value = Object::GetElement(obj, index);
1035 RETURN_IF_EMPTY_HANDLE(isolate, value);
1036 elms->set(VALUE_INDEX, *value);
1037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
1043 case JSObject::DICTIONARY_ELEMENT: {
1044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
1047 if (proto->IsNull()) return heap->undefined_value();
1048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1051 FixedArray* elements = FixedArray::cast(holder->elements());
1052 SeededNumberDictionary* dictionary = NULL;
1053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1054 dictionary = SeededNumberDictionary::cast(elements->get(1));
1056 dictionary = SeededNumberDictionary::cast(elements);
1058 int entry = dictionary->FindEntry(index);
1059 ASSERT(entry != SeededNumberDictionary::kNotFound);
1060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1063 // This is an accessor property with getter and/or setter.
1064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
1066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
1067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
1076 // This is a data property.
1077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1078 Handle<Object> value = Object::GetElement(obj, index);
1079 ASSERT(!value.is_null());
1080 elms->set(VALUE_INDEX, *value);
1081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
1088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
1095 // Use recursive implementation to also traverse hidden prototypes
1096 GetOwnPropertyImplementation(*obj, *name, &result);
1098 if (!result.IsProperty()) {
1099 return heap->undefined_value();
1102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
1103 return heap->false_value();
1106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
1110 (result.GetCallbackObject()->IsAccessorPair());
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
1114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
1116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
1117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
1124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
1127 PropertyAttributes attrs;
1129 // GetProperty will check access and report any violations.
1130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1133 elms->set(VALUE_INDEX, value);
1140 // Returns an array with the property description:
1141 // if args[1] is not a property on args[0]
1142 // returns undefined
1143 // if args[1] is a data property on args[0]
1144 // [false, value, Writeable, Enumerable, Configurable]
1145 // if args[1] is an accessor on args[0]
1146 // [true, GetFunction, SetFunction, Enumerable, Configurable]
1147 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1156 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
1157 ASSERT(args.length() == 1);
1158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1159 return obj->PreventExtensions();
1163 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
1164 ASSERT(args.length() == 1);
1165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
1168 if (proto->IsNull()) return isolate->heap()->false_value();
1169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
1176 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
1177 HandleScope scope(isolate);
1178 ASSERT(args.length() == 3);
1179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
1182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1188 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
1189 HandleScope scope(isolate);
1190 ASSERT(args.length() == 1);
1191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
1192 return *isolate->factory()->CreateApiFunction(data);
1196 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
1197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
1199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
1200 return isolate->heap()->ToBoolean(result);
1204 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
1205 ASSERT(args.length() == 2);
1206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
1208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
1213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
1214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1218 return *HeapObject::RawField(templ, offset);
1222 RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
1223 ASSERT(args.length() == 1);
1224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
1225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1237 return isolate->heap()->ToBoolean(needs_access_checks);
1241 RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
1242 ASSERT(args.length() == 1);
1243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
1244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1255 return isolate->heap()->undefined_value();
1259 static Failure* ThrowRedeclarationError(Isolate* isolate,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
1265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
1267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
1272 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
1273 ASSERT(args.length() == 3);
1274 HandleScope scope(isolate);
1276 Handle<Context> context = args.at<Context>(0);
1277 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
1278 CONVERT_SMI_ARG_CHECKED(flags, 2);
1280 Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global());
1281 Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global());
1283 // Traverse the name/value pairs and set the properties.
1284 int length = pairs->length();
1285 for (int i = 0; i < length; i += 3) {
1286 HandleScope scope(isolate);
1287 Handle<String> name(String::cast(pairs->get(i)));
1288 Handle<Object> value(pairs->get(i + 1), isolate);
1289 Handle<Object> is_qml_global(pairs->get(i + 2));
1290 ASSERT(is_qml_global->IsBoolean());
1292 Handle<JSObject> global = is_qml_global->IsTrue() ? qml_global : js_global;
1294 // We have to declare a global const property. To capture we only
1295 // assign to it when evaluating the assignment for "const x =
1296 // <expr>" the initial value is the hole.
1297 bool is_var = value->IsUndefined();
1298 bool is_const = value->IsTheHole();
1299 bool is_function = value->IsSharedFunctionInfo();
1300 bool is_module = value->IsJSModule();
1301 ASSERT(is_var + is_const + is_function + is_module == 1);
1303 if (is_var || is_const) {
1304 // Lookup the property in the global object, and don't set the
1305 // value of the variable if the property is already there.
1306 // Do the lookup locally only, see ES5 errata.
1307 LookupResult lookup(isolate);
1308 if (FLAG_es52_globals)
1309 global->LocalLookup(*name, &lookup, true);
1311 global->Lookup(*name, &lookup, true);
1312 if (lookup.IsProperty()) {
1313 // We found an existing property. Unless it was an interceptor
1314 // that claims the property is absent, skip this declaration.
1315 if (lookup.type() != INTERCEPTOR) continue;
1316 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1317 if (attributes != ABSENT) continue;
1318 // Fall-through and introduce the absent property by using
1321 } else if (is_function) {
1322 // Copy the function and update its context. Use it as value.
1323 Handle<SharedFunctionInfo> shared =
1324 Handle<SharedFunctionInfo>::cast(value);
1325 Handle<JSFunction> function =
1326 isolate->factory()->NewFunctionFromSharedFunctionInfo(
1327 shared, context, TENURED);
1331 LookupResult lookup(isolate);
1332 global->LocalLookup(*name, &lookup, true);
1334 // Compute the property attributes. According to ECMA-262,
1335 // the property must be non-configurable except in eval.
1337 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
1338 if (!is_eval || is_module) {
1339 attr |= DONT_DELETE;
1341 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
1342 if (is_const || is_module || (is_native && is_function)) {
1346 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1348 if (!lookup.IsProperty() || is_function || is_module) {
1349 // If the local property exists, check that we can reconfigure it
1350 // as required for function declarations.
1351 if (lookup.IsProperty() && lookup.IsDontDelete()) {
1352 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
1353 lookup.type() == CALLBACKS) {
1354 return ThrowRedeclarationError(
1355 isolate, is_function ? "function" : "module", name);
1357 // If the existing property is not configurable, keep its attributes.
1358 attr = lookup.GetAttributes();
1360 // Define or redefine own property.
1361 RETURN_IF_EMPTY_HANDLE(isolate,
1362 JSObject::SetLocalPropertyIgnoreAttributes(
1363 global, name, value, static_cast<PropertyAttributes>(attr)));
1365 // Do a [[Put]] on the existing (own) property.
1366 RETURN_IF_EMPTY_HANDLE(isolate,
1367 JSObject::SetProperty(
1368 global, name, value, static_cast<PropertyAttributes>(attr),
1369 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode,
1374 ASSERT(!isolate->has_pending_exception());
1375 return isolate->heap()->undefined_value();
1379 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
1380 HandleScope scope(isolate);
1381 ASSERT(args.length() == 4);
1383 // Declarations are always made in a function or global context. In the
1384 // case of eval code, the context passed is the context of the caller,
1385 // which may be some nested context and not the declaration context.
1386 RUNTIME_ASSERT(args[0]->IsContext());
1387 Handle<Context> context(Context::cast(args[0])->declaration_context());
1389 Handle<String> name(String::cast(args[1]));
1390 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
1391 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
1392 Handle<Object> initial_value(args[3], isolate);
1395 PropertyAttributes attributes;
1396 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
1397 BindingFlags binding_flags;
1398 Handle<Object> holder =
1399 context->Lookup(name, flags, &index, &attributes, &binding_flags);
1401 if (attributes != ABSENT) {
1402 // The name was declared before; check for conflicting re-declarations.
1403 // Note: this is actually inconsistent with what happens for globals (where
1404 // we silently ignore such declarations).
1405 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1406 // Functions are not read-only.
1407 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1408 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1409 return ThrowRedeclarationError(isolate, type, name);
1412 // Initialize it if necessary.
1413 if (*initial_value != NULL) {
1415 ASSERT(holder.is_identical_to(context));
1416 if (((attributes & READ_ONLY) == 0) ||
1417 context->get(index)->IsTheHole()) {
1418 context->set(index, *initial_value);
1421 // Slow case: The property is in the context extension object of a
1422 // function context or the global object of a global context.
1423 Handle<JSObject> object = Handle<JSObject>::cast(holder);
1424 RETURN_IF_EMPTY_HANDLE(
1426 JSReceiver::SetProperty(object, name, initial_value, mode,
1432 // The property is not in the function context. It needs to be
1433 // "declared" in the function context's extension context or as a
1434 // property of the the global object.
1435 Handle<JSObject> object;
1436 if (context->has_extension()) {
1437 object = Handle<JSObject>(JSObject::cast(context->extension()));
1439 // Context extension objects are allocated lazily.
1440 ASSERT(context->IsFunctionContext());
1441 object = isolate->factory()->NewJSObject(
1442 isolate->context_extension_function());
1443 context->set_extension(*object);
1445 ASSERT(*object != NULL);
1447 // Declare the property by setting it to the initial value if provided,
1448 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1449 // constant declarations).
1450 ASSERT(!object->HasLocalProperty(*name));
1451 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
1452 if (*initial_value != NULL) value = initial_value;
1453 // Declaring a const context slot is a conflicting declaration if
1454 // there is a callback with that name in a prototype. It is
1455 // allowed to introduce const variables in
1456 // JSContextExtensionObjects. They are treated specially in
1457 // SetProperty and no setters are invoked for those since they are
1458 // not real JSObjects.
1459 if (initial_value->IsTheHole() &&
1460 !object->IsJSContextExtensionObject()) {
1461 LookupResult lookup(isolate);
1462 object->Lookup(*name, &lookup);
1463 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
1464 return ThrowRedeclarationError(isolate, "const", name);
1467 if (object->IsJSGlobalObject()) {
1468 // Define own property on the global object.
1469 RETURN_IF_EMPTY_HANDLE(isolate,
1470 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
1472 RETURN_IF_EMPTY_HANDLE(isolate,
1473 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
1477 return isolate->heap()->undefined_value();
1481 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
1482 NoHandleAllocation nha;
1484 // args[1] == language_mode
1485 // args[2] == qml_mode
1486 // args[3] == value (optional)
1488 // Determine if we need to assign to the variable if it already
1489 // exists (based on the number of arguments).
1490 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1491 bool assign = args.length() == 4;
1493 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1494 RUNTIME_ASSERT(args[1]->IsSmi());
1495 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1496 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1497 ? kNonStrictMode : kStrictMode;
1499 RUNTIME_ASSERT(args[2]->IsSmi());
1500 int qml_mode = Smi::cast(args[2])->value();
1502 JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
1504 // According to ECMA-262, section 12.2, page 62, the property must
1505 // not be deletable.
1506 PropertyAttributes attributes = DONT_DELETE;
1508 // Lookup the property locally in the global object. If it isn't
1509 // there, there is a property with this name in the prototype chain.
1510 // We follow Safari and Firefox behavior and only set the property
1511 // locally if there is an explicit initialization value that we have
1512 // to assign to the property.
1513 // Note that objects can have hidden prototypes, so we need to traverse
1514 // the whole chain of hidden prototypes to do a 'local' lookup.
1515 Object* object = global;
1516 LookupResult lookup(isolate);
1517 while (object->IsJSObject() &&
1518 JSObject::cast(object)->map()->is_hidden_prototype()) {
1519 JSObject* raw_holder = JSObject::cast(object);
1520 raw_holder->LocalLookup(*name, &lookup, true);
1521 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
1522 HandleScope handle_scope(isolate);
1523 Handle<JSObject> holder(raw_holder);
1524 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1525 // Update the raw pointer in case it's changed due to GC.
1526 raw_holder = *holder;
1527 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1528 // Found an interceptor that's not read only.
1530 return raw_holder->SetProperty(
1531 &lookup, *name, args[3], attributes, strict_mode_flag);
1533 return isolate->heap()->undefined_value();
1537 object = raw_holder->GetPrototype();
1540 // Reload global in case the loop above performed a GC.
1541 global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
1543 return global->SetProperty(
1544 *name, args[3], attributes, strict_mode_flag, true);
1546 return isolate->heap()->undefined_value();
1550 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
1551 // All constants are declared with an initial value. The name
1552 // of the constant is the first argument and the initial value
1554 RUNTIME_ASSERT(args.length() == 3);
1555 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1556 Handle<Object> value = args.at<Object>(1);
1558 RUNTIME_ASSERT(args[2]->IsSmi());
1559 int qml_mode = Smi::cast(args[2])->value();
1561 // Get the current global object from top.
1562 JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global();
1564 // According to ECMA-262, section 12.2, page 62, the property must
1565 // not be deletable. Since it's a const, it must be READ_ONLY too.
1566 PropertyAttributes attributes =
1567 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1569 // Lookup the property locally in the global object. If it isn't
1570 // there, we add the property and take special precautions to always
1571 // add it as a local property even in case of callbacks in the
1572 // prototype chain (this rules out using SetProperty).
1573 // We use SetLocalPropertyIgnoreAttributes instead
1574 LookupResult lookup(isolate);
1575 global->LocalLookup(*name, &lookup);
1576 if (!lookup.IsProperty()) {
1577 return global->SetLocalPropertyIgnoreAttributes(*name,
1582 if (!lookup.IsReadOnly()) {
1583 // Restore global object from context (in case of GC) and continue
1584 // with setting the value.
1585 HandleScope handle_scope(isolate);
1586 Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global());
1588 // BUG 1213575: Handle the case where we have to set a read-only
1589 // property through an interceptor and only do it if it's
1590 // uninitialized, e.g. the hole. Nirk...
1591 // Passing non-strict mode because the property is writable.
1592 RETURN_IF_EMPTY_HANDLE(
1594 JSReceiver::SetProperty(global, name, value, attributes,
1599 // Set the value, but only if we're assigning the initial value to a
1600 // constant. For now, we determine this by checking if the
1601 // current value is the hole.
1602 // Strict mode handling not needed (const is disallowed in strict mode).
1603 PropertyType type = lookup.type();
1604 if (type == FIELD) {
1605 FixedArray* properties = global->properties();
1606 int index = lookup.GetFieldIndex();
1607 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
1608 properties->set(index, *value);
1610 } else if (type == NORMAL) {
1611 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1612 !lookup.IsReadOnly()) {
1613 global->SetNormalizedProperty(&lookup, *value);
1616 // Ignore re-initialization of constants that have already been
1617 // assigned a function value.
1618 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1621 // Use the set value as the result of the operation.
1626 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
1627 HandleScope scope(isolate);
1628 ASSERT(args.length() == 3);
1630 Handle<Object> value(args[0], isolate);
1631 ASSERT(!value->IsTheHole());
1633 // Initializations are always done in a function or global context.
1634 RUNTIME_ASSERT(args[1]->IsContext());
1635 Handle<Context> context(Context::cast(args[1])->declaration_context());
1637 Handle<String> name(String::cast(args[2]));
1640 PropertyAttributes attributes;
1641 ContextLookupFlags flags = FOLLOW_CHAINS;
1642 BindingFlags binding_flags;
1643 Handle<Object> holder =
1644 context->Lookup(name, flags, &index, &attributes, &binding_flags);
1647 ASSERT(holder->IsContext());
1648 // Property was found in a context. Perform the assignment if we
1649 // found some non-constant or an uninitialized constant.
1650 Handle<Context> context = Handle<Context>::cast(holder);
1651 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1652 context->set(index, *value);
1657 // The property could not be found, we introduce it as a property of the
1659 if (attributes == ABSENT) {
1660 Handle<JSObject> global = Handle<JSObject>(
1661 isolate->context()->global());
1662 // Strict mode not needed (const disallowed in strict mode).
1663 RETURN_IF_EMPTY_HANDLE(
1665 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
1669 // The property was present in some function's context extension object,
1670 // as a property on the subject of a with, or as a property of the global
1673 // In most situations, eval-introduced consts should still be present in
1674 // the context extension object. However, because declaration and
1675 // initialization are separate, the property might have been deleted
1676 // before we reach the initialization point.
1680 // function f() { eval("delete x; const x;"); }
1682 // In that case, the initialization behaves like a normal assignment.
1683 Handle<JSObject> object = Handle<JSObject>::cast(holder);
1685 if (*object == context->extension()) {
1686 // This is the property that was introduced by the const declaration.
1687 // Set it if it hasn't been set before. NOTE: We cannot use
1688 // GetProperty() to get the current value as it 'unholes' the value.
1689 LookupResult lookup(isolate);
1690 object->LocalLookupRealNamedProperty(*name, &lookup);
1691 ASSERT(lookup.IsFound()); // the property was declared
1692 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1694 PropertyType type = lookup.type();
1695 if (type == FIELD) {
1696 FixedArray* properties = object->properties();
1697 int index = lookup.GetFieldIndex();
1698 if (properties->get(index)->IsTheHole()) {
1699 properties->set(index, *value);
1701 } else if (type == NORMAL) {
1702 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1703 object->SetNormalizedProperty(&lookup, *value);
1706 // We should not reach here. Any real, named property should be
1707 // either a field or a dictionary slot.
1711 // The property was found on some other object. Set it if it is not a
1712 // read-only property.
1713 if ((attributes & READ_ONLY) == 0) {
1714 // Strict mode not needed (const disallowed in strict mode).
1715 RETURN_IF_EMPTY_HANDLE(
1717 JSReceiver::SetProperty(object, name, value, attributes,
1726 RUNTIME_FUNCTION(MaybeObject*,
1727 Runtime_OptimizeObjectForAddingMultipleProperties) {
1728 HandleScope scope(isolate);
1729 ASSERT(args.length() == 2);
1730 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1731 CONVERT_SMI_ARG_CHECKED(properties, 1);
1732 if (object->HasFastProperties()) {
1733 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1739 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
1740 HandleScope scope(isolate);
1741 ASSERT(args.length() == 4);
1742 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1743 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
1744 // Due to the way the JS calls are constructed this must be less than the
1745 // length of a string, i.e. it is always a Smi. We check anyway for security.
1746 CONVERT_SMI_ARG_CHECKED(index, 2);
1747 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
1748 RUNTIME_ASSERT(last_match_info->HasFastElements());
1749 RUNTIME_ASSERT(index >= 0);
1750 RUNTIME_ASSERT(index <= subject->length());
1751 isolate->counters()->regexp_entry_runtime()->Increment();
1752 Handle<Object> result = RegExpImpl::Exec(regexp,
1756 if (result.is_null()) return Failure::Exception();
1761 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
1762 ASSERT(args.length() == 3);
1763 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
1764 if (elements_count < 0 ||
1765 elements_count > FixedArray::kMaxLength ||
1766 !Smi::IsValid(elements_count)) {
1767 return isolate->ThrowIllegalOperation();
1770 { MaybeObject* maybe_new_object =
1771 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
1772 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1774 FixedArray* elements = FixedArray::cast(new_object);
1775 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1776 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
1777 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1780 AssertNoAllocation no_gc;
1781 HandleScope scope(isolate);
1782 reinterpret_cast<HeapObject*>(new_object)->
1783 set_map(isolate->global_context()->regexp_result_map());
1785 JSArray* array = JSArray::cast(new_object);
1786 array->set_properties(isolate->heap()->empty_fixed_array());
1787 array->set_elements(elements);
1788 array->set_length(Smi::FromInt(elements_count));
1789 // Write in-object properties after the length of the array.
1790 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1791 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1796 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
1797 AssertNoAllocation no_alloc;
1798 ASSERT(args.length() == 5);
1799 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1800 CONVERT_ARG_CHECKED(String, source, 1);
1801 // If source is the empty string we set it to "(?:)" instead as
1802 // suggested by ECMA-262, 5th, section 15.10.4.1.
1803 if (source->length() == 0) source = isolate->heap()->query_colon_symbol();
1805 Object* global = args[2];
1806 if (!global->IsTrue()) global = isolate->heap()->false_value();
1808 Object* ignoreCase = args[3];
1809 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
1811 Object* multiline = args[4];
1812 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
1814 Map* map = regexp->map();
1815 Object* constructor = map->constructor();
1816 if (constructor->IsJSFunction() &&
1817 JSFunction::cast(constructor)->initial_map() == map) {
1818 // If we still have the original map, set in-object properties directly.
1819 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1820 // Both true and false are immovable immortal objects so no need for write
1822 regexp->InObjectPropertyAtPut(
1823 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1824 regexp->InObjectPropertyAtPut(
1825 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1826 regexp->InObjectPropertyAtPut(
1827 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
1828 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1830 SKIP_WRITE_BARRIER); // It's a Smi.
1834 // Map has changed, so use generic, but slower, method.
1835 PropertyAttributes final =
1836 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1837 PropertyAttributes writable =
1838 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
1839 Heap* heap = isolate->heap();
1840 MaybeObject* result;
1841 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
1844 ASSERT(!result->IsFailure());
1845 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
1848 ASSERT(!result->IsFailure());
1850 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
1853 ASSERT(!result->IsFailure());
1854 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
1857 ASSERT(!result->IsFailure());
1859 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
1862 ASSERT(!result->IsFailure());
1868 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
1869 HandleScope scope(isolate);
1870 ASSERT(args.length() == 1);
1871 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
1872 // This is necessary to enable fast checks for absence of elements
1873 // on Array.prototype and below.
1874 prototype->set_elements(isolate->heap()->empty_fixed_array());
1875 return Smi::FromInt(0);
1879 static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1880 Handle<JSObject> holder,
1882 Builtins::Name builtin_name) {
1883 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1884 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1885 Handle<JSFunction> optimized =
1886 isolate->factory()->NewFunction(key,
1888 JSObject::kHeaderSize,
1891 optimized->shared()->DontAdaptArguments();
1892 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
1897 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
1898 HandleScope scope(isolate);
1899 ASSERT(args.length() == 1);
1900 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
1902 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1903 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1904 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1905 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1906 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1907 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1908 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
1914 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1915 ASSERT(args.length() == 1);
1916 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
1918 if (!callable->IsJSFunction()) {
1919 HandleScope scope(isolate);
1921 Handle<Object> delegate =
1922 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1923 if (threw) return Failure::Exception();
1924 callable = JSFunction::cast(*delegate);
1926 JSFunction* function = JSFunction::cast(callable);
1928 SharedFunctionInfo* shared = function->shared();
1929 if (shared->native() || !shared->is_classic_mode()) {
1930 return isolate->heap()->undefined_value();
1932 // Returns undefined for strict or native functions, or
1933 // the associated global receiver for "normal" functions.
1935 Context* global_context =
1936 function->context()->global()->global_context();
1937 return global_context->global()->global_receiver();
1941 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
1942 HandleScope scope(isolate);
1943 ASSERT(args.length() == 4);
1944 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
1945 int index = args.smi_at(1);
1946 Handle<String> pattern = args.at<String>(2);
1947 Handle<String> flags = args.at<String>(3);
1949 // Get the RegExp function from the context in the literals array.
1950 // This is the RegExp function from the context in which the
1951 // function was created. We do not use the RegExp function from the
1952 // current global context because this might be the RegExp function
1953 // from another context which we should not have access to.
1954 Handle<JSFunction> constructor =
1956 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
1957 // Compute the regular expression literal.
1958 bool has_pending_exception;
1959 Handle<Object> regexp =
1960 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1961 &has_pending_exception);
1962 if (has_pending_exception) {
1963 ASSERT(isolate->has_pending_exception());
1964 return Failure::Exception();
1966 literals->set(index, *regexp);
1971 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
1972 NoHandleAllocation ha;
1973 ASSERT(args.length() == 1);
1975 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1976 return f->shared()->name();
1980 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
1981 NoHandleAllocation ha;
1982 ASSERT(args.length() == 2);
1984 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1985 CONVERT_ARG_CHECKED(String, name, 1);
1986 f->shared()->set_name(name);
1987 return isolate->heap()->undefined_value();
1991 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1992 NoHandleAllocation ha;
1993 ASSERT(args.length() == 1);
1994 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1995 return isolate->heap()->ToBoolean(
1996 f->shared()->name_should_print_as_anonymous());
2000 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2001 NoHandleAllocation ha;
2002 ASSERT(args.length() == 1);
2003 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2004 f->shared()->set_name_should_print_as_anonymous(true);
2005 return isolate->heap()->undefined_value();
2009 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
2010 NoHandleAllocation ha;
2011 ASSERT(args.length() == 1);
2013 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2014 Object* obj = f->RemovePrototype();
2015 if (obj->IsFailure()) return obj;
2017 return isolate->heap()->undefined_value();
2021 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
2022 HandleScope scope(isolate);
2023 ASSERT(args.length() == 1);
2025 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2026 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2027 if (!script->IsScript()) return isolate->heap()->undefined_value();
2029 return *GetScriptWrapper(Handle<Script>::cast(script));
2033 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
2034 HandleScope scope(isolate);
2035 ASSERT(args.length() == 1);
2037 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
2038 Handle<SharedFunctionInfo> shared(f->shared());
2039 return *shared->GetSourceCode();
2043 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
2044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 1);
2047 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2048 int pos = fun->shared()->start_position();
2049 return Smi::FromInt(pos);
2053 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
2054 ASSERT(args.length() == 2);
2056 CONVERT_ARG_CHECKED(Code, code, 0);
2057 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2059 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2061 Address pc = code->address() + offset;
2062 return Smi::FromInt(code->SourcePosition(pc));
2066 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
2067 NoHandleAllocation ha;
2068 ASSERT(args.length() == 2);
2070 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2071 CONVERT_ARG_CHECKED(String, name, 1);
2072 fun->SetInstanceClassName(name);
2073 return isolate->heap()->undefined_value();
2077 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
2078 NoHandleAllocation ha;
2079 ASSERT(args.length() == 2);
2081 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2082 CONVERT_SMI_ARG_CHECKED(length, 1);
2083 fun->shared()->set_length(length);
2084 return isolate->heap()->undefined_value();
2088 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
2089 NoHandleAllocation ha;
2090 ASSERT(args.length() == 2);
2092 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2093 ASSERT(fun->should_have_prototype());
2095 { MaybeObject* maybe_obj =
2096 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2097 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2099 return args[0]; // return TOS
2103 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2104 NoHandleAllocation ha;
2105 RUNTIME_ASSERT(args.length() == 1);
2106 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2108 MaybeObject* maybe_name =
2109 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2111 if (!maybe_name->To(&name)) return maybe_name;
2113 if (function->HasFastProperties()) {
2114 // Construct a new field descriptor with updated attributes.
2115 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2116 int index = instance_desc->Search(name);
2117 ASSERT(index != DescriptorArray::kNotFound);
2118 PropertyDetails details = instance_desc->GetDetails(index);
2119 CallbacksDescriptor new_desc(name,
2120 instance_desc->GetValue(index),
2121 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2123 // Construct a new field descriptors array containing the new descriptor.
2124 Object* descriptors_unchecked;
2125 { MaybeObject* maybe_descriptors_unchecked =
2126 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2127 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2128 return maybe_descriptors_unchecked;
2131 DescriptorArray* new_descriptors =
2132 DescriptorArray::cast(descriptors_unchecked);
2133 // Create a new map featuring the new field descriptors array.
2134 Object* map_unchecked;
2135 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2136 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2137 return maybe_map_unchecked;
2140 Map* new_map = Map::cast(map_unchecked);
2141 new_map->set_instance_descriptors(new_descriptors);
2142 function->set_map(new_map);
2143 } else { // Dictionary properties.
2144 // Directly manipulate the property details.
2145 int entry = function->property_dictionary()->FindEntry(name);
2146 ASSERT(entry != StringDictionary::kNotFound);
2147 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2148 PropertyDetails new_details(
2149 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2152 function->property_dictionary()->DetailsAtPut(entry, new_details);
2158 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
2159 NoHandleAllocation ha;
2160 ASSERT(args.length() == 1);
2162 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2163 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
2167 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
2168 NoHandleAllocation ha;
2169 ASSERT(args.length() == 1);
2171 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2172 return isolate->heap()->ToBoolean(f->IsBuiltin());
2176 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
2177 HandleScope scope(isolate);
2178 ASSERT(args.length() == 2);
2180 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
2181 Handle<Object> code = args.at<Object>(1);
2183 Handle<Context> context(target->context());
2185 if (!code->IsNull()) {
2186 RUNTIME_ASSERT(code->IsJSFunction());
2187 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
2188 Handle<SharedFunctionInfo> shared(fun->shared());
2190 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
2191 return Failure::Exception();
2193 // Since we don't store the source for this we should never
2195 shared->code()->set_optimizable(false);
2196 // Set the code, scope info, formal parameter count,
2197 // and the length of the target function.
2198 target->shared()->set_code(shared->code());
2199 target->ReplaceCode(shared->code());
2200 target->shared()->set_scope_info(shared->scope_info());
2201 target->shared()->set_length(shared->length());
2202 target->shared()->set_formal_parameter_count(
2203 shared->formal_parameter_count());
2204 // Set the source code of the target function to undefined.
2205 // SetCode is only used for built-in constructors like String,
2206 // Array, and Object, and some web code
2207 // doesn't like seeing source code for constructors.
2208 target->shared()->set_script(isolate->heap()->undefined_value());
2209 target->shared()->code()->set_optimizable(false);
2210 // Clear the optimization hints related to the compiled code as these are no
2211 // longer valid when the code is overwritten.
2212 target->shared()->ClearThisPropertyAssignmentsInfo();
2213 context = Handle<Context>(fun->context());
2215 // Make sure we get a fresh copy of the literal vector to avoid
2216 // cross context contamination.
2217 int number_of_literals = fun->NumberOfLiterals();
2218 Handle<FixedArray> literals =
2219 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
2220 if (number_of_literals > 0) {
2221 // Insert the object, regexp and array functions in the literals
2222 // array prefix. These are the functions that will be used when
2223 // creating object, regexp and array literals.
2224 literals->set(JSFunction::kLiteralGlobalContextIndex,
2225 context->global_context());
2227 target->set_literals(*literals);
2228 target->set_next_function_link(isolate->heap()->undefined_value());
2230 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2231 isolate->logger()->LogExistingFunction(
2232 shared, Handle<Code>(shared->code()));
2236 target->set_context(*context);
2241 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
2242 HandleScope scope(isolate);
2243 ASSERT(args.length() == 2);
2244 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
2245 CONVERT_SMI_ARG_CHECKED(num, 1);
2246 RUNTIME_ASSERT(num >= 0);
2247 SetExpectedNofProperties(function, num);
2248 return isolate->heap()->undefined_value();
2252 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2253 Object* char_code) {
2255 if (char_code->ToArrayIndex(&code)) {
2256 if (code <= 0xffff) {
2257 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
2260 return isolate->heap()->empty_string();
2264 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
2265 NoHandleAllocation ha;
2266 ASSERT(args.length() == 2);
2268 CONVERT_ARG_CHECKED(String, subject, 0);
2269 Object* index = args[1];
2270 RUNTIME_ASSERT(index->IsNumber());
2273 if (index->IsSmi()) {
2274 int value = Smi::cast(index)->value();
2275 if (value < 0) return isolate->heap()->nan_value();
2278 ASSERT(index->IsHeapNumber());
2279 double value = HeapNumber::cast(index)->value();
2280 i = static_cast<uint32_t>(DoubleToInteger(value));
2283 // Flatten the string. If someone wants to get a char at an index
2284 // in a cons string, it is likely that more indices will be
2287 { MaybeObject* maybe_flat = subject->TryFlatten();
2288 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2290 subject = String::cast(flat);
2292 if (i >= static_cast<uint32_t>(subject->length())) {
2293 return isolate->heap()->nan_value();
2296 return Smi::FromInt(subject->Get(i));
2300 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
2301 NoHandleAllocation ha;
2302 ASSERT(args.length() == 1);
2303 return CharFromCode(isolate, args[0]);
2307 class FixedArrayBuilder {
2309 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2310 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
2312 has_non_smi_elements_(false) {
2313 // Require a non-zero initial size. Ensures that doubling the size to
2314 // extend the array will work.
2315 ASSERT(initial_capacity > 0);
2318 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2319 : array_(backing_store),
2321 has_non_smi_elements_(false) {
2322 // Require a non-zero initial size. Ensures that doubling the size to
2323 // extend the array will work.
2324 ASSERT(backing_store->length() > 0);
2327 bool HasCapacity(int elements) {
2328 int length = array_->length();
2329 int required_length = length_ + elements;
2330 return (length >= required_length);
2333 void EnsureCapacity(int elements) {
2334 int length = array_->length();
2335 int required_length = length_ + elements;
2336 if (length < required_length) {
2337 int new_length = length;
2340 } while (new_length < required_length);
2341 Handle<FixedArray> extended_array =
2342 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
2343 array_->CopyTo(0, *extended_array, 0, length_);
2344 array_ = extended_array;
2348 void Add(Object* value) {
2349 ASSERT(!value->IsSmi());
2350 ASSERT(length_ < capacity());
2351 array_->set(length_, value);
2353 has_non_smi_elements_ = true;
2356 void Add(Smi* value) {
2357 ASSERT(value->IsSmi());
2358 ASSERT(length_ < capacity());
2359 array_->set(length_, value);
2363 Handle<FixedArray> array() {
2372 return array_->length();
2375 Handle<JSArray> ToJSArray() {
2376 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
2377 result_array->set_length(Smi::FromInt(length_));
2378 return result_array;
2381 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2382 FACTORY->SetContent(target_array, array_);
2383 target_array->set_length(Smi::FromInt(length_));
2384 return target_array;
2388 Handle<FixedArray> array_;
2390 bool has_non_smi_elements_;
2394 // Forward declarations.
2395 const int kStringBuilderConcatHelperLengthBits = 11;
2396 const int kStringBuilderConcatHelperPositionBits = 19;
2398 template <typename schar>
2399 static inline void StringBuilderConcatHelper(String*,
2404 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2405 StringBuilderSubstringLength;
2406 typedef BitField<int,
2407 kStringBuilderConcatHelperLengthBits,
2408 kStringBuilderConcatHelperPositionBits>
2409 StringBuilderSubstringPosition;
2412 class ReplacementStringBuilder {
2414 ReplacementStringBuilder(Heap* heap,
2415 Handle<String> subject,
2416 int estimated_part_count)
2418 array_builder_(heap->isolate(), estimated_part_count),
2420 character_count_(0),
2421 is_ascii_(subject->IsAsciiRepresentation()) {
2422 // Require a non-zero initial size. Ensures that doubling the size to
2423 // extend the array will work.
2424 ASSERT(estimated_part_count > 0);
2427 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2431 int length = to - from;
2433 if (StringBuilderSubstringLength::is_valid(length) &&
2434 StringBuilderSubstringPosition::is_valid(from)) {
2435 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2436 StringBuilderSubstringPosition::encode(from);
2437 builder->Add(Smi::FromInt(encoded_slice));
2439 // Otherwise encode as two smis.
2440 builder->Add(Smi::FromInt(-length));
2441 builder->Add(Smi::FromInt(from));
2446 void EnsureCapacity(int elements) {
2447 array_builder_.EnsureCapacity(elements);
2451 void AddSubjectSlice(int from, int to) {
2452 AddSubjectSlice(&array_builder_, from, to);
2453 IncrementCharacterCount(to - from);
2457 void AddString(Handle<String> string) {
2458 int length = string->length();
2460 AddElement(*string);
2461 if (!string->IsAsciiRepresentation()) {
2464 IncrementCharacterCount(length);
2468 Handle<String> ToString() {
2469 if (array_builder_.length() == 0) {
2470 return heap_->isolate()->factory()->empty_string();
2473 Handle<String> joined_string;
2475 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
2476 AssertNoAllocation no_alloc;
2477 char* char_buffer = seq->GetChars();
2478 StringBuilderConcatHelper(*subject_,
2480 *array_builder_.array(),
2481 array_builder_.length());
2482 joined_string = Handle<String>::cast(seq);
2485 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
2486 AssertNoAllocation no_alloc;
2487 uc16* char_buffer = seq->GetChars();
2488 StringBuilderConcatHelper(*subject_,
2490 *array_builder_.array(),
2491 array_builder_.length());
2492 joined_string = Handle<String>::cast(seq);
2494 return joined_string;
2498 void IncrementCharacterCount(int by) {
2499 if (character_count_ > String::kMaxLength - by) {
2500 V8::FatalProcessOutOfMemory("String.replace result too large.");
2502 character_count_ += by;
2505 Handle<JSArray> GetParts() {
2506 return array_builder_.ToJSArray();
2510 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2511 return heap_->isolate()->factory()->NewRawAsciiString(length);
2515 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2516 return heap_->isolate()->factory()->NewRawTwoByteString(length);
2520 void AddElement(Object* element) {
2521 ASSERT(element->IsSmi() || element->IsString());
2522 ASSERT(array_builder_.capacity() > array_builder_.length());
2523 array_builder_.Add(element);
2527 FixedArrayBuilder array_builder_;
2528 Handle<String> subject_;
2529 int character_count_;
2534 class CompiledReplacement {
2536 CompiledReplacement()
2537 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
2539 void Compile(Handle<String> replacement,
2541 int subject_length);
2543 void Apply(ReplacementStringBuilder* builder,
2546 Handle<JSArray> last_match_info);
2548 // Number of distinct parts of the replacement pattern.
2550 return parts_.length();
2553 bool simple_hint() {
2554 return simple_hint_;
2562 REPLACEMENT_SUBSTRING,
2565 NUMBER_OF_PART_TYPES
2568 struct ReplacementPart {
2569 static inline ReplacementPart SubjectMatch() {
2570 return ReplacementPart(SUBJECT_CAPTURE, 0);
2572 static inline ReplacementPart SubjectCapture(int capture_index) {
2573 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2575 static inline ReplacementPart SubjectPrefix() {
2576 return ReplacementPart(SUBJECT_PREFIX, 0);
2578 static inline ReplacementPart SubjectSuffix(int subject_length) {
2579 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2581 static inline ReplacementPart ReplacementString() {
2582 return ReplacementPart(REPLACEMENT_STRING, 0);
2584 static inline ReplacementPart ReplacementSubString(int from, int to) {
2587 return ReplacementPart(-from, to);
2590 // If tag <= 0 then it is the negation of a start index of a substring of
2591 // the replacement pattern, otherwise it's a value from PartType.
2592 ReplacementPart(int tag, int data)
2593 : tag(tag), data(data) {
2594 // Must be non-positive or a PartType value.
2595 ASSERT(tag < NUMBER_OF_PART_TYPES);
2597 // Either a value of PartType or a non-positive number that is
2598 // the negation of an index into the replacement string.
2600 // The data value's interpretation depends on the value of tag:
2601 // tag == SUBJECT_PREFIX ||
2602 // tag == SUBJECT_SUFFIX: data is unused.
2603 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2604 // tag == REPLACEMENT_SUBSTRING ||
2605 // tag == REPLACEMENT_STRING: data is index into array of substrings
2606 // of the replacement string.
2607 // tag <= 0: Temporary representation of the substring of the replacement
2608 // string ranging over -tag .. data.
2609 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2610 // substring objects.
2614 template<typename Char>
2615 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2616 Vector<Char> characters,
2618 int subject_length) {
2619 int length = characters.length();
2621 for (int i = 0; i < length; i++) {
2622 Char c = characters[i];
2624 int next_index = i + 1;
2625 if (next_index == length) { // No next character!
2628 Char c2 = characters[next_index];
2632 // There is a substring before. Include the first "$".
2633 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2634 last = next_index + 1; // Continue after the second "$".
2636 // Let the next substring start with the second "$".
2643 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2645 parts->Add(ReplacementPart::SubjectPrefix());
2651 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2653 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2659 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2661 parts->Add(ReplacementPart::SubjectMatch());
2675 int capture_ref = c2 - '0';
2676 if (capture_ref > capture_count) {
2680 int second_digit_index = next_index + 1;
2681 if (second_digit_index < length) {
2682 // Peek ahead to see if we have two digits.
2683 Char c3 = characters[second_digit_index];
2684 if ('0' <= c3 && c3 <= '9') { // Double digits.
2685 int double_digit_ref = capture_ref * 10 + c3 - '0';
2686 if (double_digit_ref <= capture_count) {
2687 next_index = second_digit_index;
2688 capture_ref = double_digit_ref;
2692 if (capture_ref > 0) {
2694 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2696 ASSERT(capture_ref <= capture_count);
2697 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2698 last = next_index + 1;
2709 if (length > last) {
2711 parts->Add(ReplacementPart::ReplacementString());
2714 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2720 ZoneList<ReplacementPart> parts_;
2721 ZoneList<Handle<String> > replacement_substrings_;
2726 void CompiledReplacement::Compile(Handle<String> replacement,
2728 int subject_length) {
2730 AssertNoAllocation no_alloc;
2731 String::FlatContent content = replacement->GetFlatContent();
2732 ASSERT(content.IsFlat());
2733 if (content.IsAscii()) {
2734 simple_hint_ = ParseReplacementPattern(&parts_,
2735 content.ToAsciiVector(),
2739 ASSERT(content.IsTwoByte());
2740 simple_hint_ = ParseReplacementPattern(&parts_,
2741 content.ToUC16Vector(),
2746 Isolate* isolate = replacement->GetIsolate();
2747 // Find substrings of replacement string and create them as String objects.
2748 int substring_index = 0;
2749 for (int i = 0, n = parts_.length(); i < n; i++) {
2750 int tag = parts_[i].tag;
2751 if (tag <= 0) { // A replacement string slice.
2753 int to = parts_[i].data;
2754 replacement_substrings_.Add(
2755 isolate->factory()->NewSubString(replacement, from, to));
2756 parts_[i].tag = REPLACEMENT_SUBSTRING;
2757 parts_[i].data = substring_index;
2759 } else if (tag == REPLACEMENT_STRING) {
2760 replacement_substrings_.Add(replacement);
2761 parts_[i].data = substring_index;
2768 void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2771 Handle<JSArray> last_match_info) {
2772 for (int i = 0, n = parts_.length(); i < n; i++) {
2773 ReplacementPart part = parts_[i];
2775 case SUBJECT_PREFIX:
2776 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2778 case SUBJECT_SUFFIX: {
2779 int subject_length = part.data;
2780 if (match_to < subject_length) {
2781 builder->AddSubjectSlice(match_to, subject_length);
2785 case SUBJECT_CAPTURE: {
2786 int capture = part.data;
2787 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
2788 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2789 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2790 if (from >= 0 && to > from) {
2791 builder->AddSubjectSlice(from, to);
2795 case REPLACEMENT_SUBSTRING:
2796 case REPLACEMENT_STRING:
2797 builder->AddString(replacement_substrings_[part.data]);
2806 void FindAsciiStringIndices(Vector<const char> subject,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2811 // Collect indices of pattern in subject using memchr.
2812 // Stop after finding at most limit values.
2813 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2814 const char* subject_end = subject_start + subject.length();
2815 const char* pos = subject_start;
2817 pos = reinterpret_cast<const char*>(
2818 memchr(pos, pattern, subject_end - pos));
2819 if (pos == NULL) return;
2820 indices->Add(static_cast<int>(pos - subject_start));
2827 template <typename SubjectChar, typename PatternChar>
2828 void FindStringIndices(Isolate* isolate,
2829 Vector<const SubjectChar> subject,
2830 Vector<const PatternChar> pattern,
2831 ZoneList<int>* indices,
2832 unsigned int limit) {
2834 // Collect indices of pattern in subject.
2835 // Stop after finding at most limit values.
2836 int pattern_length = pattern.length();
2838 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2840 index = search.Search(subject, index);
2841 if (index < 0) return;
2842 indices->Add(index);
2843 index += pattern_length;
2849 void FindStringIndicesDispatch(Isolate* isolate,
2852 ZoneList<int>* indices,
2853 unsigned int limit) {
2855 AssertNoAllocation no_gc;
2856 String::FlatContent subject_content = subject->GetFlatContent();
2857 String::FlatContent pattern_content = pattern->GetFlatContent();
2858 ASSERT(subject_content.IsFlat());
2859 ASSERT(pattern_content.IsFlat());
2860 if (subject_content.IsAscii()) {
2861 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2862 if (pattern_content.IsAscii()) {
2863 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2864 if (pattern_vector.length() == 1) {
2865 FindAsciiStringIndices(subject_vector,
2870 FindStringIndices(isolate,
2877 FindStringIndices(isolate,
2879 pattern_content.ToUC16Vector(),
2884 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
2885 if (pattern_content.IsAscii()) {
2886 FindStringIndices(isolate,
2888 pattern_content.ToAsciiVector(),
2892 FindStringIndices(isolate,
2894 pattern_content.ToUC16Vector(),
2903 // Two smis before and after the match, for very long strings.
2904 const int kMaxBuilderEntriesPerRegExpMatch = 5;
2907 static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2908 Handle<JSArray> last_match_info,
2911 // Fill last_match_info with a single capture.
2912 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2913 AssertNoAllocation no_gc;
2914 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2915 RegExpImpl::SetLastCaptureCount(elements, 2);
2916 RegExpImpl::SetLastInput(elements, *subject);
2917 RegExpImpl::SetLastSubject(elements, *subject);
2918 RegExpImpl::SetCapture(elements, 0, match_start);
2919 RegExpImpl::SetCapture(elements, 1, match_end);
2923 template <typename SubjectChar, typename PatternChar>
2924 static bool SearchStringMultiple(Isolate* isolate,
2925 Vector<const SubjectChar> subject,
2926 Vector<const PatternChar> pattern,
2927 String* pattern_string,
2928 FixedArrayBuilder* builder,
2930 int pos = *match_pos;
2931 int subject_length = subject.length();
2932 int pattern_length = pattern.length();
2933 int max_search_start = subject_length - pattern_length;
2934 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2935 while (pos <= max_search_start) {
2936 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2940 // Position of end of previous match.
2941 int match_end = pos + pattern_length;
2942 int new_pos = search.Search(subject, match_end);
2945 if (new_pos > match_end) {
2946 ReplacementStringBuilder::AddSubjectSlice(builder,
2951 builder->Add(pattern_string);
2957 if (pos < max_search_start) {
2958 ReplacementStringBuilder::AddSubjectSlice(builder,
2959 pos + pattern_length,
2969 template<typename ResultSeqString>
2970 MUST_USE_RESULT static MaybeObject* StringReplaceAtomRegExpWithString(
2972 Handle<String> subject,
2973 Handle<JSRegExp> pattern_regexp,
2974 Handle<String> replacement,
2975 Handle<JSArray> last_match_info) {
2976 ASSERT(subject->IsFlat());
2977 ASSERT(replacement->IsFlat());
2979 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2980 ZoneList<int> indices(8);
2981 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2983 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2984 int subject_len = subject->length();
2985 int pattern_len = pattern->length();
2986 int replacement_len = replacement->length();
2988 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2990 int matches = indices.length();
2991 if (matches == 0) return *subject;
2993 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2994 int subject_pos = 0;
2997 Handle<ResultSeqString> result;
2998 if (ResultSeqString::kHasAsciiEncoding) {
2999 result = Handle<ResultSeqString>::cast(
3000 isolate->factory()->NewRawAsciiString(result_len));
3002 result = Handle<ResultSeqString>::cast(
3003 isolate->factory()->NewRawTwoByteString(result_len));
3006 for (int i = 0; i < matches; i++) {
3007 // Copy non-matched subject content.
3008 if (subject_pos < indices.at(i)) {
3009 String::WriteToFlat(*subject,
3010 result->GetChars() + result_pos,
3013 result_pos += indices.at(i) - subject_pos;
3017 if (replacement_len > 0) {
3018 String::WriteToFlat(*replacement,
3019 result->GetChars() + result_pos,
3022 result_pos += replacement_len;
3025 subject_pos = indices.at(i) + pattern_len;
3027 // Add remaining subject content at the end.
3028 if (subject_pos < subject_len) {
3029 String::WriteToFlat(*subject,
3030 result->GetChars() + result_pos,
3035 SetLastMatchInfoNoCaptures(subject,
3037 indices.at(matches - 1),
3038 indices.at(matches - 1) + pattern_len);
3044 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
3048 String* replacement,
3049 JSArray* last_match_info) {
3050 ASSERT(subject->IsFlat());
3051 ASSERT(replacement->IsFlat());
3053 HandleScope handles(isolate);
3055 int length = subject->length();
3056 Handle<String> subject_handle(subject);
3057 Handle<JSRegExp> regexp_handle(regexp);
3058 Handle<String> replacement_handle(replacement);
3059 Handle<JSArray> last_match_info_handle(last_match_info);
3060 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3063 last_match_info_handle);
3064 if (match.is_null()) {
3065 return Failure::Exception();
3067 if (match->IsNull()) {
3068 return *subject_handle;
3071 int capture_count = regexp_handle->CaptureCount();
3073 // CompiledReplacement uses zone allocation.
3074 ZoneScope zone(isolate, DELETE_ON_EXIT);
3075 CompiledReplacement compiled_replacement;
3076 compiled_replacement.Compile(replacement_handle,
3080 bool is_global = regexp_handle->GetFlags().is_global();
3082 // Shortcut for simple non-regexp global replacements
3084 regexp_handle->TypeTag() == JSRegExp::ATOM &&
3085 compiled_replacement.simple_hint()) {
3086 if (subject_handle->HasOnlyAsciiChars() &&
3087 replacement_handle->HasOnlyAsciiChars()) {
3088 return StringReplaceAtomRegExpWithString<SeqAsciiString>(
3093 last_match_info_handle);
3095 return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
3100 last_match_info_handle);
3104 // Guessing the number of parts that the final result string is built
3105 // from. Global regexps can match any number of times, so we guess
3107 int expected_parts =
3108 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
3109 ReplacementStringBuilder builder(isolate->heap(),
3113 // Index of end of last match.
3116 // Number of parts added by compiled replacement plus preceeding
3117 // string and possibly suffix after last match. It is possible for
3118 // all components to use two elements when encoded as two smis.
3119 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
3120 bool matched = true;
3122 ASSERT(last_match_info_handle->HasFastElements());
3123 // Increase the capacity of the builder before entering local handle-scope,
3124 // so its internal buffer can safely allocate a new handle if it grows.
3125 builder.EnsureCapacity(parts_added_per_loop);
3127 HandleScope loop_scope(isolate);
3130 AssertNoAllocation match_info_array_is_not_in_a_handle;
3131 FixedArray* match_info_array =
3132 FixedArray::cast(last_match_info_handle->elements());
3134 ASSERT_EQ(capture_count * 2 + 2,
3135 RegExpImpl::GetLastCaptureCount(match_info_array));
3136 start = RegExpImpl::GetCapture(match_info_array, 0);
3137 end = RegExpImpl::GetCapture(match_info_array, 1);
3141 builder.AddSubjectSlice(prev, start);
3143 compiled_replacement.Apply(&builder,
3146 last_match_info_handle);
3149 // Only continue checking for global regexps.
3150 if (!is_global) break;
3152 // Continue from where the match ended, unless it was an empty match.
3156 if (next > length) break;
3159 match = RegExpImpl::Exec(regexp_handle,
3162 last_match_info_handle);
3163 if (match.is_null()) {
3164 return Failure::Exception();
3166 matched = !match->IsNull();
3169 if (prev < length) {
3170 builder.AddSubjectSlice(prev, length);
3173 return *(builder.ToString());
3177 template <typename ResultSeqString>
3178 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
3182 JSArray* last_match_info) {
3183 ASSERT(subject->IsFlat());
3185 HandleScope handles(isolate);
3187 Handle<String> subject_handle(subject);
3188 Handle<JSRegExp> regexp_handle(regexp);
3189 Handle<JSArray> last_match_info_handle(last_match_info);
3191 // Shortcut for simple non-regexp global replacements
3192 if (regexp_handle->GetFlags().is_global() &&
3193 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3194 Handle<String> empty_string_handle(HEAP->empty_string());
3195 if (subject_handle->HasOnlyAsciiChars()) {
3196 return StringReplaceAtomRegExpWithString<SeqAsciiString>(
3200 empty_string_handle,
3201 last_match_info_handle);
3203 return StringReplaceAtomRegExpWithString<SeqTwoByteString>(
3207 empty_string_handle,
3208 last_match_info_handle);
3212 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3215 last_match_info_handle);
3216 if (match.is_null()) return Failure::Exception();
3217 if (match->IsNull()) return *subject_handle;
3219 ASSERT(last_match_info_handle->HasFastElements());
3223 AssertNoAllocation match_info_array_is_not_in_a_handle;
3224 FixedArray* match_info_array =
3225 FixedArray::cast(last_match_info_handle->elements());
3227 start = RegExpImpl::GetCapture(match_info_array, 0);
3228 end = RegExpImpl::GetCapture(match_info_array, 1);
3231 bool global = regexp_handle->GetFlags().is_global();
3233 if (start == end && !global) return *subject_handle;
3235 int length = subject_handle->length();
3236 int new_length = length - (end - start);
3237 if (new_length == 0) {
3238 return isolate->heap()->empty_string();
3240 Handle<ResultSeqString> answer;
3241 if (ResultSeqString::kHasAsciiEncoding) {
3242 answer = Handle<ResultSeqString>::cast(
3243 isolate->factory()->NewRawAsciiString(new_length));
3245 answer = Handle<ResultSeqString>::cast(
3246 isolate->factory()->NewRawTwoByteString(new_length));
3249 // If the regexp isn't global, only match once.
3252 String::WriteToFlat(*subject_handle,
3258 String::WriteToFlat(*subject_handle,
3259 answer->GetChars() + start,
3266 int prev = 0; // Index of end of last match.
3267 int next = 0; // Start of next search (prev unless last match was empty).
3272 // Add substring subject[prev;start] to answer string.
3273 String::WriteToFlat(*subject_handle,
3274 answer->GetChars() + position,
3277 position += start - prev;
3281 // Continue from where the match ended, unless it was an empty match.
3284 if (next > length) break;
3286 match = RegExpImpl::Exec(regexp_handle,
3289 last_match_info_handle);
3290 if (match.is_null()) return Failure::Exception();
3291 if (match->IsNull()) break;
3293 ASSERT(last_match_info_handle->HasFastElements());
3294 HandleScope loop_scope(isolate);
3296 AssertNoAllocation match_info_array_is_not_in_a_handle;
3297 FixedArray* match_info_array =
3298 FixedArray::cast(last_match_info_handle->elements());
3299 start = RegExpImpl::GetCapture(match_info_array, 0);
3300 end = RegExpImpl::GetCapture(match_info_array, 1);
3304 if (prev < length) {
3305 // Add substring subject[prev;length] to answer string.
3306 String::WriteToFlat(*subject_handle,
3307 answer->GetChars() + position,
3310 position += length - prev;
3313 if (position == 0) {
3314 return isolate->heap()->empty_string();
3317 // Shorten string and fill
3318 int string_size = ResultSeqString::SizeFor(position);
3319 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3320 int delta = allocated_string_size - string_size;
3322 answer->set_length(position);
3323 if (delta == 0) return *answer;
3325 Address end_of_string = answer->address() + string_size;
3326 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
3327 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3328 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
3335 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
3336 ASSERT(args.length() == 4);
3338 CONVERT_ARG_CHECKED(String, subject, 0);
3339 if (!subject->IsFlat()) {
3340 Object* flat_subject;
3341 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3342 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3343 return maybe_flat_subject;
3346 subject = String::cast(flat_subject);
3349 CONVERT_ARG_CHECKED(String, replacement, 2);
3350 if (!replacement->IsFlat()) {
3351 Object* flat_replacement;
3352 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3353 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3354 return maybe_flat_replacement;
3357 replacement = String::cast(flat_replacement);
3360 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3361 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
3363 ASSERT(last_match_info->HasFastElements());
3365 if (replacement->length() == 0) {
3366 if (subject->HasOnlyAsciiChars()) {
3367 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
3368 isolate, subject, regexp, last_match_info);
3370 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
3371 isolate, subject, regexp, last_match_info);
3375 return StringReplaceRegExpWithString(isolate,
3383 Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3384 Handle<String> subject,
3385 Handle<String> search,
3386 Handle<String> replace,
3388 int recursion_limit) {
3389 if (recursion_limit == 0) return Handle<String>::null();
3390 if (subject->IsConsString()) {
3391 ConsString* cons = ConsString::cast(*subject);
3392 Handle<String> first = Handle<String>(cons->first());
3393 Handle<String> second = Handle<String>(cons->second());
3394 Handle<String> new_first =
3395 StringReplaceOneCharWithString(isolate,
3400 recursion_limit - 1);
3401 if (*found) return isolate->factory()->NewConsString(new_first, second);
3402 if (new_first.is_null()) return new_first;
3404 Handle<String> new_second =
3405 StringReplaceOneCharWithString(isolate,
3410 recursion_limit - 1);
3411 if (*found) return isolate->factory()->NewConsString(first, new_second);
3412 if (new_second.is_null()) return new_second;
3416 int index = StringMatch(isolate, subject, search, 0);
3417 if (index == -1) return subject;
3419 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3420 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3421 Handle<String> second =
3422 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3423 return isolate->factory()->NewConsString(cons1, second);
3428 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3429 ASSERT(args.length() == 3);
3430 HandleScope scope(isolate);
3431 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3432 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3433 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
3435 // If the cons string tree is too deep, we simply abort the recursion and
3436 // retry with a flattened subject string.
3437 const int kRecursionLimit = 0x1000;
3439 Handle<String> result =
3440 Runtime::StringReplaceOneCharWithString(isolate,
3446 if (!result.is_null()) return *result;
3447 return *Runtime::StringReplaceOneCharWithString(isolate,
3448 FlattenGetString(subject),
3456 // Perform string match of pattern on subject, starting at start index.
3457 // Caller must ensure that 0 <= start_index <= sub->length(),
3458 // and should check that pat->length() + start_index <= sub->length().
3459 int Runtime::StringMatch(Isolate* isolate,
3463 ASSERT(0 <= start_index);
3464 ASSERT(start_index <= sub->length());
3466 int pattern_length = pat->length();
3467 if (pattern_length == 0) return start_index;
3469 int subject_length = sub->length();
3470 if (start_index + pattern_length > subject_length) return -1;
3472 if (!sub->IsFlat()) FlattenString(sub);
3473 if (!pat->IsFlat()) FlattenString(pat);
3475 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3476 // Extract flattened substrings of cons strings before determining asciiness.
3477 String::FlatContent seq_sub = sub->GetFlatContent();
3478 String::FlatContent seq_pat = pat->GetFlatContent();
3480 // dispatch on type of strings
3481 if (seq_pat.IsAscii()) {
3482 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3483 if (seq_sub.IsAscii()) {
3484 return SearchString(isolate,
3485 seq_sub.ToAsciiVector(),
3489 return SearchString(isolate,
3490 seq_sub.ToUC16Vector(),
3494 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3495 if (seq_sub.IsAscii()) {
3496 return SearchString(isolate,
3497 seq_sub.ToAsciiVector(),
3501 return SearchString(isolate,
3502 seq_sub.ToUC16Vector(),
3508 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
3509 HandleScope scope(isolate); // create a new handle scope
3510 ASSERT(args.length() == 3);
3512 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3513 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
3515 Object* index = args[2];
3516 uint32_t start_index;
3517 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
3519 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
3521 Runtime::StringMatch(isolate, sub, pat, start_index);
3522 return Smi::FromInt(position);
3526 template <typename schar, typename pchar>
3527 static int StringMatchBackwards(Vector<const schar> subject,
3528 Vector<const pchar> pattern,
3530 int pattern_length = pattern.length();
3531 ASSERT(pattern_length >= 1);
3532 ASSERT(idx + pattern_length <= subject.length());
3534 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
3535 for (int i = 0; i < pattern_length; i++) {
3536 uc16 c = pattern[i];
3537 if (c > String::kMaxAsciiCharCode) {
3543 pchar pattern_first_char = pattern[0];
3544 for (int i = idx; i >= 0; i--) {
3545 if (subject[i] != pattern_first_char) continue;
3547 while (j < pattern_length) {
3548 if (pattern[j] != subject[i+j]) {
3553 if (j == pattern_length) {
3560 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
3561 HandleScope scope(isolate); // create a new handle scope
3562 ASSERT(args.length() == 3);
3564 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3565 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
3567 Object* index = args[2];
3568 uint32_t start_index;
3569 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
3571 uint32_t pat_length = pat->length();
3572 uint32_t sub_length = sub->length();
3574 if (start_index + pat_length > sub_length) {
3575 start_index = sub_length - pat_length;
3578 if (pat_length == 0) {
3579 return Smi::FromInt(start_index);
3582 if (!sub->IsFlat()) FlattenString(sub);
3583 if (!pat->IsFlat()) FlattenString(pat);
3586 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3588 String::FlatContent sub_content = sub->GetFlatContent();
3589 String::FlatContent pat_content = pat->GetFlatContent();
3591 if (pat_content.IsAscii()) {
3592 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3593 if (sub_content.IsAscii()) {
3594 position = StringMatchBackwards(sub_content.ToAsciiVector(),
3598 position = StringMatchBackwards(sub_content.ToUC16Vector(),
3603 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3604 if (sub_content.IsAscii()) {
3605 position = StringMatchBackwards(sub_content.ToAsciiVector(),
3609 position = StringMatchBackwards(sub_content.ToUC16Vector(),
3615 return Smi::FromInt(position);
3619 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
3620 NoHandleAllocation ha;
3621 ASSERT(args.length() == 2);
3623 CONVERT_ARG_CHECKED(String, str1, 0);
3624 CONVERT_ARG_CHECKED(String, str2, 1);
3626 if (str1 == str2) return Smi::FromInt(0); // Equal.
3627 int str1_length = str1->length();
3628 int str2_length = str2->length();
3630 // Decide trivial cases without flattening.
3631 if (str1_length == 0) {
3632 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3633 return Smi::FromInt(-str2_length);
3635 if (str2_length == 0) return Smi::FromInt(str1_length);
3638 int end = str1_length < str2_length ? str1_length : str2_length;
3640 // No need to flatten if we are going to find the answer on the first
3641 // character. At this point we know there is at least one character
3642 // in each string, due to the trivial case handling above.
3643 int d = str1->Get(0) - str2->Get(0);
3644 if (d != 0) return Smi::FromInt(d);
3649 StringInputBuffer& buf1 =
3650 *isolate->runtime_state()->string_locale_compare_buf1();
3651 StringInputBuffer& buf2 =
3652 *isolate->runtime_state()->string_locale_compare_buf2();
3657 for (int i = 0; i < end; i++) {
3658 uint16_t char1 = buf1.GetNext();
3659 uint16_t char2 = buf2.GetNext();
3660 if (char1 != char2) return Smi::FromInt(char1 - char2);
3663 return Smi::FromInt(str1_length - str2_length);
3667 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
3668 NoHandleAllocation ha;
3669 ASSERT(args.length() == 3);
3671 CONVERT_ARG_CHECKED(String, value, 0);
3673 // We have a fast integer-only case here to avoid a conversion to double in
3674 // the common case where from and to are Smis.
3675 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3676 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3677 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3678 start = from_number;
3681 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3682 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
3683 start = FastD2I(from_number);
3684 end = FastD2I(to_number);
3686 RUNTIME_ASSERT(end >= start);
3687 RUNTIME_ASSERT(start >= 0);
3688 RUNTIME_ASSERT(end <= value->length());
3689 isolate->counters()->sub_string_runtime()->Increment();
3690 return value->SubString(start, end);
3694 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
3695 ASSERT_EQ(3, args.length());
3697 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3698 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3699 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
3700 HandleScope handles;
3702 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3704 if (match.is_null()) {
3705 return Failure::Exception();
3707 if (match->IsNull()) {
3708 return isolate->heap()->null_value();
3710 int length = subject->length();
3712 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
3713 ZoneList<int> offsets(8);
3718 AssertNoAllocation no_alloc;
3719 FixedArray* elements = FixedArray::cast(regexp_info->elements());
3720 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3721 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3725 if (start == end) if (++end > length) break;
3726 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
3727 if (match.is_null()) {
3728 return Failure::Exception();
3730 } while (!match->IsNull());
3731 int matches = offsets.length() / 2;
3732 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
3733 Handle<String> substring = isolate->factory()->
3734 NewSubString(subject, offsets.at(0), offsets.at(1));
3735 elements->set(0, *substring);
3736 for (int i = 1; i < matches ; i++) {
3737 int from = offsets.at(i * 2);
3738 int to = offsets.at(i * 2 + 1);
3739 Handle<String> substring = isolate->factory()->
3740 NewProperSubString(subject, from, to);
3741 elements->set(i, *substring);
3743 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
3744 result->set_length(Smi::FromInt(matches));
3749 static bool SearchStringMultiple(Isolate* isolate,
3750 Handle<String> subject,
3751 Handle<String> pattern,
3752 Handle<JSArray> last_match_info,
3753 FixedArrayBuilder* builder) {
3754 ASSERT(subject->IsFlat());
3755 ASSERT(pattern->IsFlat());
3757 // Treating as if a previous match was before first character.
3758 int match_pos = -pattern->length();
3760 for (;;) { // Break when search complete.
3761 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3762 AssertNoAllocation no_gc;
3763 String::FlatContent subject_content = subject->GetFlatContent();
3764 String::FlatContent pattern_content = pattern->GetFlatContent();
3765 if (subject_content.IsAscii()) {
3766 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3767 if (pattern_content.IsAscii()) {
3768 if (SearchStringMultiple(isolate,
3770 pattern_content.ToAsciiVector(),
3775 if (SearchStringMultiple(isolate,
3777 pattern_content.ToUC16Vector(),
3783 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3784 if (pattern_content.IsAscii()) {
3785 if (SearchStringMultiple(isolate,
3787 pattern_content.ToAsciiVector(),
3792 if (SearchStringMultiple(isolate,
3794 pattern_content.ToUC16Vector(),
3802 if (match_pos >= 0) {
3803 SetLastMatchInfoNoCaptures(subject,
3806 match_pos + pattern->length());
3809 return false; // No matches at all.
3813 static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3815 Handle<String> subject,
3816 Handle<JSRegExp> regexp,
3817 Handle<JSArray> last_match_array,
3818 FixedArrayBuilder* builder) {
3819 ASSERT(subject->IsFlat());
3820 int match_start = -1;
3823 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3824 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3826 OffsetsVector registers(required_registers, isolate);
3827 Vector<int32_t> register_vector(registers.vector(), registers.length());
3828 int subject_length = subject->length();
3831 for (;;) { // Break on failure, return on exception.
3832 RegExpImpl::IrregexpResult result =
3833 RegExpImpl::IrregexpExecOnce(regexp,
3837 if (result == RegExpImpl::RE_SUCCESS) {
3838 match_start = register_vector[0];
3839 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3840 if (match_end < match_start) {
3841 ReplacementStringBuilder::AddSubjectSlice(builder,
3845 match_end = register_vector[1];
3846 HandleScope loop_scope(isolate);
3848 builder->Add(*isolate->factory()->NewProperSubString(subject,
3852 builder->Add(*isolate->factory()->NewSubString(subject,
3856 if (match_start != match_end) {
3859 pos = match_end + 1;
3860 if (pos > subject_length) break;
3862 } else if (result == RegExpImpl::RE_FAILURE) {
3865 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3871 if (match_start >= 0) {
3872 if (match_end < subject_length) {
3873 ReplacementStringBuilder::AddSubjectSlice(builder,
3877 SetLastMatchInfoNoCaptures(subject,
3881 return RegExpImpl::RE_SUCCESS;
3883 return RegExpImpl::RE_FAILURE; // No matches at all.
3888 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain
3889 // separate last match info. See comment on that function.
3890 static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3892 Handle<String> subject,
3893 Handle<JSRegExp> regexp,
3894 Handle<JSArray> last_match_array,
3895 FixedArrayBuilder* builder) {
3897 ASSERT(subject->IsFlat());
3898 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3899 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3901 OffsetsVector registers(required_registers, isolate);
3902 Vector<int32_t> register_vector(registers.vector(), registers.length());
3904 RegExpImpl::IrregexpResult result =
3905 RegExpImpl::IrregexpExecOnce(regexp,
3910 int capture_count = regexp->CaptureCount();
3911 int subject_length = subject->length();
3913 // Position to search from.
3915 // End of previous match. Differs from pos if match was empty.
3917 if (result == RegExpImpl::RE_SUCCESS) {
3920 int match_start = register_vector[0];
3921 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3922 if (match_end < match_start) {
3923 ReplacementStringBuilder::AddSubjectSlice(builder,
3927 match_end = register_vector[1];
3930 // Avoid accumulating new handles inside loop.
3931 HandleScope temp_scope(isolate);
3932 // Arguments array to replace function is match, captures, index and
3933 // subject, i.e., 3 + capture count in total.
3934 Handle<FixedArray> elements =
3935 isolate->factory()->NewFixedArray(3 + capture_count);
3936 Handle<String> match;
3938 match = isolate->factory()->NewProperSubString(subject,
3942 match = isolate->factory()->NewSubString(subject,
3946 elements->set(0, *match);
3947 for (int i = 1; i <= capture_count; i++) {
3948 int start = register_vector[i * 2];
3950 int end = register_vector[i * 2 + 1];
3951 ASSERT(start <= end);
3952 Handle<String> substring;
3954 substring = isolate->factory()->NewProperSubString(subject,
3958 substring = isolate->factory()->NewSubString(subject, start, end);
3960 elements->set(i, *substring);
3962 ASSERT(register_vector[i * 2 + 1] < 0);
3963 elements->set(i, isolate->heap()->undefined_value());
3966 elements->set(capture_count + 1, Smi::FromInt(match_start));
3967 elements->set(capture_count + 2, *subject);
3968 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
3971 if (match_end > match_start) {
3974 pos = match_end + 1;
3975 if (pos > subject_length) {
3980 result = RegExpImpl::IrregexpExecOnce(regexp,
3985 } while (result == RegExpImpl::RE_SUCCESS);
3987 if (result != RegExpImpl::RE_EXCEPTION) {
3988 // Finished matching, with at least one match.
3989 if (match_end < subject_length) {
3990 ReplacementStringBuilder::AddSubjectSlice(builder,
3995 int last_match_capture_count = (capture_count + 1) * 2;
3996 int last_match_array_size =
3997 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3998 last_match_array->EnsureSize(last_match_array_size);
3999 AssertNoAllocation no_gc;
4000 FixedArray* elements = FixedArray::cast(last_match_array->elements());
4001 // We have to set this even though the rest of the last match array is
4003 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
4004 // These are also read without consulting the override.
4005 RegExpImpl::SetLastSubject(elements, *subject);
4006 RegExpImpl::SetLastInput(elements, *subject);
4007 return RegExpImpl::RE_SUCCESS;
4010 // No matches at all, return failure or exception result directly.
4015 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets
4016 // lastMatchInfoOverride to maintain the last match info, so we don't need to
4017 // set any other last match array info.
4018 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
4019 ASSERT(args.length() == 4);
4020 HandleScope handles(isolate);
4022 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
4023 if (!subject->IsFlat()) FlattenString(subject);
4024 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
4025 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
4026 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
4028 ASSERT(last_match_info->HasFastElements());
4029 ASSERT(regexp->GetFlags().is_global());
4030 Handle<FixedArray> result_elements;
4031 if (result_array->HasFastElements()) {
4033 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
4035 if (result_elements.is_null() || result_elements->length() < 16) {
4036 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
4038 FixedArrayBuilder builder(result_elements);
4040 if (regexp->TypeTag() == JSRegExp::ATOM) {
4041 Handle<String> pattern(
4042 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
4043 ASSERT(pattern->IsFlat());
4044 if (SearchStringMultiple(isolate, subject, pattern,
4045 last_match_info, &builder)) {
4046 return *builder.ToJSArray(result_array);
4048 return isolate->heap()->null_value();
4051 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4053 RegExpImpl::IrregexpResult result;
4054 if (regexp->CaptureCount() == 0) {
4055 result = SearchRegExpNoCaptureMultiple(isolate,
4061 result = SearchRegExpMultiple(isolate,
4067 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
4068 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
4069 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4070 return Failure::Exception();
4074 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
4075 NoHandleAllocation ha;
4076 ASSERT(args.length() == 2);
4077 CONVERT_SMI_ARG_CHECKED(radix, 1);
4078 RUNTIME_ASSERT(2 <= radix && radix <= 36);
4080 // Fast case where the result is a one character string.
4081 if (args[0]->IsSmi()) {
4082 int value = args.smi_at(0);
4083 if (value >= 0 && value < radix) {
4084 // Character array used for conversion.
4085 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
4086 return isolate->heap()->
4087 LookupSingleCharacterStringFromCode(kCharTable[value]);
4092 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4094 return *isolate->factory()->nan_symbol();
4098 return *isolate->factory()->minus_infinity_symbol();
4100 return *isolate->factory()->infinity_symbol();
4102 char* str = DoubleToRadixCString(value, radix);
4103 MaybeObject* result =
4104 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
4110 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
4111 NoHandleAllocation ha;
4112 ASSERT(args.length() == 2);
4114 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4116 return *isolate->factory()->nan_symbol();
4120 return *isolate->factory()->minus_infinity_symbol();
4122 return *isolate->factory()->infinity_symbol();
4124 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4125 int f = FastD2I(f_number);
4126 RUNTIME_ASSERT(f >= 0);
4127 char* str = DoubleToFixedCString(value, f);
4129 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
4135 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
4136 NoHandleAllocation ha;
4137 ASSERT(args.length() == 2);
4139 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4141 return *isolate->factory()->nan_symbol();
4145 return *isolate->factory()->minus_infinity_symbol();
4147 return *isolate->factory()->infinity_symbol();
4149 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4150 int f = FastD2I(f_number);
4151 RUNTIME_ASSERT(f >= -1 && f <= 20);
4152 char* str = DoubleToExponentialCString(value, f);
4154 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
4160 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
4161 NoHandleAllocation ha;
4162 ASSERT(args.length() == 2);
4164 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
4166 return *isolate->factory()->nan_symbol();
4170 return *isolate->factory()->minus_infinity_symbol();
4172 return *isolate->factory()->infinity_symbol();
4174 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
4175 int f = FastD2I(f_number);
4176 RUNTIME_ASSERT(f >= 1 && f <= 21);
4177 char* str = DoubleToPrecisionCString(value, f);
4179 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
4185 // Returns a single character string where first character equals
4186 // string->Get(index).
4187 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
4188 if (index < static_cast<uint32_t>(string->length())) {
4189 string->TryFlatten();
4190 return LookupSingleCharacterStringFromCode(
4191 string->Get(index));
4193 return Execution::CharAt(string, index);
4197 MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4198 Handle<Object> object,
4200 // Handle [] indexing on Strings
4201 if (object->IsString()) {
4202 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4203 if (!result->IsUndefined()) return *result;
4206 // Handle [] indexing on String objects
4207 if (object->IsStringObjectWithCharacterAt(index)) {
4208 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4209 Handle<Object> result =
4210 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4211 if (!result->IsUndefined()) return *result;
4214 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
4215 return object->GetPrototype()->GetElement(index);
4218 return object->GetElement(index);
4222 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4223 Handle<Object> object,
4224 Handle<Object> key) {
4225 HandleScope scope(isolate);
4227 if (object->IsUndefined() || object->IsNull()) {
4228 Handle<Object> args[2] = { key, object };
4229 Handle<Object> error =
4230 isolate->factory()->NewTypeError("non_object_property_load",
4231 HandleVector(args, 2));
4232 return isolate->Throw(*error);
4235 // Check if the given key is an array index.
4237 if (key->ToArrayIndex(&index)) {
4238 return GetElementOrCharAt(isolate, object, index);
4241 // Convert the key to a string - possibly by calling back into JavaScript.
4242 Handle<String> name;
4243 if (key->IsString()) {
4244 name = Handle<String>::cast(key);
4246 bool has_pending_exception = false;
4247 Handle<Object> converted =
4248 Execution::ToString(key, &has_pending_exception);
4249 if (has_pending_exception) return Failure::Exception();
4250 name = Handle<String>::cast(converted);
4253 // Check if the name is trivially convertible to an index and get
4254 // the element if so.
4255 if (name->AsArrayIndex(&index)) {
4256 return GetElementOrCharAt(isolate, object, index);
4258 return object->GetProperty(*name);
4263 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
4264 NoHandleAllocation ha;
4265 ASSERT(args.length() == 2);
4267 Handle<Object> object = args.at<Object>(0);
4268 Handle<Object> key = args.at<Object>(1);
4270 return Runtime::GetObjectProperty(isolate, object, key);
4274 // KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
4275 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
4276 NoHandleAllocation ha;
4277 ASSERT(args.length() == 2);
4279 // Fast cases for getting named properties of the receiver JSObject
4282 // The global proxy objects has to be excluded since LocalLookup on
4283 // the global proxy object can return a valid result even though the
4284 // global proxy object never has properties. This is the case
4285 // because the global proxy object forwards everything to its hidden
4286 // prototype including local lookups.
4288 // Additionally, we need to make sure that we do not cache results
4289 // for objects that require access checks.
4290 if (args[0]->IsJSObject()) {
4291 if (!args[0]->IsJSGlobalProxy() &&
4292 !args[0]->IsAccessCheckNeeded() &&
4293 args[1]->IsString()) {
4294 JSObject* receiver = JSObject::cast(args[0]);
4295 String* key = String::cast(args[1]);
4296 if (receiver->HasFastProperties()) {
4297 // Attempt to use lookup cache.
4298 Map* receiver_map = receiver->map();
4299 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4300 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4302 Object* value = receiver->FastPropertyAt(offset);
4303 return value->IsTheHole()
4304 ? isolate->heap()->undefined_value()
4307 // Lookup cache miss. Perform lookup and update the cache if
4309 LookupResult result(isolate);
4310 receiver->LocalLookup(key, &result);
4311 if (result.IsFound() && result.type() == FIELD) {
4312 int offset = result.GetFieldIndex();
4313 keyed_lookup_cache->Update(receiver_map, key, offset);
4314 return receiver->FastPropertyAt(offset);
4317 // Attempt dictionary lookup.
4318 StringDictionary* dictionary = receiver->property_dictionary();
4319 int entry = dictionary->FindEntry(key);
4320 if ((entry != StringDictionary::kNotFound) &&
4321 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4322 Object* value = dictionary->ValueAt(entry);
4323 if (!receiver->IsGlobalObject()) return value;
4324 value = JSGlobalPropertyCell::cast(value)->value();
4325 if (!value->IsTheHole()) return value;
4326 // If value is the hole do the general lookup.
4329 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4330 // JSObject without a string key. If the key is a Smi, check for a
4331 // definite out-of-bounds access to elements, which is a strong indicator
4332 // that subsequent accesses will also call the runtime. Proactively
4333 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4334 // doubles for those future calls in the case that the elements would
4335 // become FAST_DOUBLE_ELEMENTS.
4336 Handle<JSObject> js_object(args.at<JSObject>(0));
4337 ElementsKind elements_kind = js_object->GetElementsKind();
4338 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4339 elements_kind == FAST_DOUBLE_ELEMENTS) {
4340 FixedArrayBase* elements = js_object->elements();
4341 if (args.at<Smi>(1)->value() >= elements->length()) {
4342 MaybeObject* maybe_object = TransitionElements(js_object,
4345 if (maybe_object->IsFailure()) return maybe_object;
4349 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4350 // Fast case for string indexing using [] with a smi index.
4351 HandleScope scope(isolate);
4352 Handle<String> str = args.at<String>(0);
4353 int index = args.smi_at(1);
4354 if (index >= 0 && index < str->length()) {
4355 Handle<Object> result = GetCharAt(str, index);
4360 // Fall back to GetObjectProperty.
4361 return Runtime::GetObjectProperty(isolate,
4363 args.at<Object>(1));
4367 static bool IsValidAccessor(Handle<Object> obj) {
4368 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4372 // Implements part of 8.12.9 DefineOwnProperty.
4373 // There are 3 cases that lead here:
4374 // Step 4b - define a new accessor property.
4375 // Steps 9c & 12 - replace an existing data property with an accessor property.
4376 // Step 12 - update an existing accessor property with an accessor or generic
4378 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
4379 ASSERT(args.length() == 5);
4380 HandleScope scope(isolate);
4381 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4382 RUNTIME_ASSERT(!obj->IsNull());
4383 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4384 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4385 RUNTIME_ASSERT(IsValidAccessor(getter));
4386 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4387 RUNTIME_ASSERT(IsValidAccessor(setter));
4388 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
4389 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4390 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4392 bool fast = obj->HasFastProperties();
4393 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4394 if (fast) JSObject::TransformToFastProperties(obj, 0);
4395 return isolate->heap()->undefined_value();
4398 // Implements part of 8.12.9 DefineOwnProperty.
4399 // There are 3 cases that lead here:
4400 // Step 4a - define a new data property.
4401 // Steps 9b & 12 - replace an existing accessor property with a data property.
4402 // Step 12 - update an existing data property with a data or generic
4404 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
4405 ASSERT(args.length() == 4);
4406 HandleScope scope(isolate);
4407 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4408 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4409 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
4410 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
4411 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4412 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4414 LookupResult result(isolate);
4415 js_object->LocalLookupRealNamedProperty(*name, &result);
4417 // Special case for callback properties.
4418 if (result.IsFound() && result.type() == CALLBACKS) {
4419 Object* callback = result.GetCallbackObject();
4420 // To be compatible with Safari we do not change the value on API objects
4421 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4423 if (callback->IsAccessorInfo()) {
4424 return isolate->heap()->undefined_value();
4426 // Avoid redefining foreign callback as data property, just use the stored
4427 // setter to update the value instead.
4428 // TODO(mstarzinger): So far this only works if property attributes don't
4429 // change, this should be fixed once we cleanup the underlying code.
4430 if (callback->IsForeign() && result.GetAttributes() == attr) {
4431 return js_object->SetPropertyWithCallback(callback,
4439 // Take special care when attributes are different and there is already
4440 // a property. For simplicity we normalize the property which enables us
4441 // to not worry about changing the instance_descriptor and creating a new
4442 // map. The current version of SetObjectProperty does not handle attributes
4443 // correctly in the case where a property is a field and is reset with
4445 if (result.IsProperty() &&
4446 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
4447 // New attributes - normalize to avoid writing to instance descriptor
4448 if (js_object->IsJSGlobalProxy()) {
4449 // Since the result is a property, the prototype will exist so
4450 // we don't have to check for null.
4451 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
4453 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
4454 // Use IgnoreAttributes version since a readonly property may be
4455 // overridden and SetProperty does not allow this.
4456 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4461 return Runtime::ForceSetObjectProperty(isolate,
4469 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4470 Handle<Object> object,
4472 Handle<Object> value,
4473 PropertyAttributes attr,
4474 StrictModeFlag strict_mode) {
4475 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
4476 HandleScope scope(isolate);
4478 if (object->IsUndefined() || object->IsNull()) {
4479 Handle<Object> args[2] = { key, object };
4480 Handle<Object> error =
4481 isolate->factory()->NewTypeError("non_object_property_store",
4482 HandleVector(args, 2));
4483 return isolate->Throw(*error);
4486 if (object->IsJSProxy()) {
4487 bool has_pending_exception = false;
4488 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4489 if (has_pending_exception) return Failure::Exception();
4490 return JSProxy::cast(*object)->SetProperty(
4491 String::cast(*name), *value, attr, strict_mode);
4494 // If the object isn't a JavaScript object, we ignore the store.
4495 if (!object->IsJSObject()) return *value;
4497 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4499 // Check if the given key is an array index.
4501 if (key->ToArrayIndex(&index)) {
4502 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4503 // of a string using [] notation. We need to support this too in
4505 // In the case of a String object we just need to redirect the assignment to
4506 // the underlying string if the index is in range. Since the underlying
4507 // string does nothing with the assignment then we can ignore such
4509 if (js_object->IsStringObjectWithCharacterAt(index)) {
4513 Handle<Object> result = JSObject::SetElement(
4514 js_object, index, value, attr, strict_mode, set_mode);
4515 if (result.is_null()) return Failure::Exception();
4519 if (key->IsString()) {
4520 Handle<Object> result;
4521 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
4522 result = JSObject::SetElement(
4523 js_object, index, value, attr, strict_mode, set_mode);
4525 Handle<String> key_string = Handle<String>::cast(key);
4526 key_string->TryFlatten();
4527 result = JSReceiver::SetProperty(
4528 js_object, key_string, value, attr, strict_mode);
4530 if (result.is_null()) return Failure::Exception();
4534 // Call-back into JavaScript to convert the key to a string.
4535 bool has_pending_exception = false;
4536 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4537 if (has_pending_exception) return Failure::Exception();
4538 Handle<String> name = Handle<String>::cast(converted);
4540 if (name->AsArrayIndex(&index)) {
4541 return js_object->SetElement(
4542 index, *value, attr, strict_mode, true, set_mode);
4544 return js_object->SetProperty(*name, *value, attr, strict_mode);
4549 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4550 Handle<JSObject> js_object,
4552 Handle<Object> value,
4553 PropertyAttributes attr) {
4554 HandleScope scope(isolate);
4556 // Check if the given key is an array index.
4558 if (key->ToArrayIndex(&index)) {
4559 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4560 // of a string using [] notation. We need to support this too in
4562 // In the case of a String object we just need to redirect the assignment to
4563 // the underlying string if the index is in range. Since the underlying
4564 // string does nothing with the assignment then we can ignore such
4566 if (js_object->IsStringObjectWithCharacterAt(index)) {
4570 return js_object->SetElement(
4571 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
4574 if (key->IsString()) {
4575 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
4576 return js_object->SetElement(
4577 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
4579 Handle<String> key_string = Handle<String>::cast(key);
4580 key_string->TryFlatten();
4581 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4587 // Call-back into JavaScript to convert the key to a string.
4588 bool has_pending_exception = false;
4589 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4590 if (has_pending_exception) return Failure::Exception();
4591 Handle<String> name = Handle<String>::cast(converted);
4593 if (name->AsArrayIndex(&index)) {
4594 return js_object->SetElement(
4595 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
4597 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
4602 MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4603 Handle<JSReceiver> receiver,
4604 Handle<Object> key) {
4605 HandleScope scope(isolate);
4607 // Check if the given key is an array index.
4609 if (key->ToArrayIndex(&index)) {
4610 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4611 // characters of a string using [] notation. In the case of a
4612 // String object we just need to redirect the deletion to the
4613 // underlying string if the index is in range. Since the
4614 // underlying string does nothing with the deletion, we can ignore
4616 if (receiver->IsStringObjectWithCharacterAt(index)) {
4617 return isolate->heap()->true_value();
4620 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
4623 Handle<String> key_string;
4624 if (key->IsString()) {
4625 key_string = Handle<String>::cast(key);
4627 // Call-back into JavaScript to convert the key to a string.
4628 bool has_pending_exception = false;
4629 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4630 if (has_pending_exception) return Failure::Exception();
4631 key_string = Handle<String>::cast(converted);
4634 key_string->TryFlatten();
4635 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
4639 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
4640 NoHandleAllocation ha;
4641 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4643 Handle<Object> object = args.at<Object>(0);
4644 Handle<Object> key = args.at<Object>(1);
4645 Handle<Object> value = args.at<Object>(2);
4646 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
4648 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4649 // Compute attributes.
4650 PropertyAttributes attributes =
4651 static_cast<PropertyAttributes>(unchecked_attributes);
4653 StrictModeFlag strict_mode = kNonStrictMode;
4654 if (args.length() == 5) {
4655 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
4656 strict_mode = strict_mode_flag;
4659 return Runtime::SetObjectProperty(isolate,
4668 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4669 NoHandleAllocation ha;
4670 RUNTIME_ASSERT(args.length() == 1);
4671 Handle<Object> object = args.at<Object>(0);
4672 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4676 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4677 NoHandleAllocation ha;
4678 RUNTIME_ASSERT(args.length() == 1);
4679 Handle<Object> object = args.at<Object>(0);
4680 return TransitionElements(object, FAST_ELEMENTS, isolate);
4684 // Set the native flag on the function.
4685 // This is used to decide if we should transform null and undefined
4686 // into the global object when doing call and apply.
4687 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
4688 NoHandleAllocation ha;
4689 RUNTIME_ASSERT(args.length() == 1);
4691 Handle<Object> object = args.at<Object>(0);
4693 if (object->IsJSFunction()) {
4694 JSFunction* func = JSFunction::cast(*object);
4695 func->shared()->set_native(true);
4697 return isolate->heap()->undefined_value();
4701 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4702 RUNTIME_ASSERT(args.length() == 5);
4703 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
4704 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4705 Handle<Object> value = args.at<Object>(2);
4706 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
4707 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4710 Object* raw_boilerplate_object = literals->get(literal_index);
4711 Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
4713 ElementsKind elements_kind = object->GetElementsKind();
4715 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4716 // Smis should never trigger transitions.
4717 ASSERT(!value->IsSmi());
4719 if (value->IsNumber()) {
4720 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4721 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4722 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4723 FAST_DOUBLE_ELEMENTS)) {
4724 JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
4726 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4727 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
4728 HeapNumber* number = HeapNumber::cast(*value);
4729 double_array->set(store_index, number->Number());
4731 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4732 elements_kind == FAST_DOUBLE_ELEMENTS);
4733 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4734 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4736 JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
4738 FixedArray* object_array = FixedArray::cast(object->elements());
4739 object_array->set(store_index, *value);
4745 // Check whether debugger and is about to step into the callback that is passed
4746 // to a built-in function such as Array.forEach.
4747 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
4748 if (!isolate->IsDebuggerActive()) return isolate->heap()->false_value();
4749 CONVERT_ARG_CHECKED(Object, callback, 0);
4750 // We do not step into the callback if it's a builtin or not even a function.
4751 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
4752 return isolate->heap()->false_value();
4754 return isolate->heap()->true_value();
4758 // Set one shot breakpoints for the callback function that is passed to a
4759 // built-in function such as Array.forEach to enable stepping into the callback.
4760 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
4761 Debug* debug = isolate->debug();
4762 if (!debug->IsStepping()) return NULL;
4763 CONVERT_ARG_CHECKED(Object, callback, 0);
4764 HandleScope scope(isolate);
4765 Handle<SharedFunctionInfo> shared_info(JSFunction::cast(callback)->shared());
4766 // When leaving the callback, step out has been activated, but not performed
4767 // if we do not leave the builtin. To be able to step into the callback
4768 // again, we need to clear the step out at this point.
4769 debug->ClearStepOut();
4770 debug->FloodWithOneShot(shared_info);
4775 // Set a local property, even if it is READ_ONLY. If the property does not
4776 // exist, it will be added with attributes NONE.
4777 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
4778 NoHandleAllocation ha;
4779 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
4780 CONVERT_ARG_CHECKED(JSObject, object, 0);
4781 CONVERT_ARG_CHECKED(String, name, 1);
4782 // Compute attributes.
4783 PropertyAttributes attributes = NONE;
4784 if (args.length() == 4) {
4785 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
4786 // Only attribute bits should be set.
4788 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4789 attributes = static_cast<PropertyAttributes>(unchecked_value);
4793 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
4797 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
4798 NoHandleAllocation ha;
4799 ASSERT(args.length() == 3);
4801 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4802 CONVERT_ARG_CHECKED(String, key, 1);
4803 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
4804 return object->DeleteProperty(key, (strict_mode == kStrictMode)
4805 ? JSReceiver::STRICT_DELETION
4806 : JSReceiver::NORMAL_DELETION);
4810 static Object* HasLocalPropertyImplementation(Isolate* isolate,
4811 Handle<JSObject> object,
4812 Handle<String> key) {
4813 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
4814 // Handle hidden prototypes. If there's a hidden prototype above this thing
4815 // then we have to check it for properties, because they are supposed to
4816 // look like they are on this object.
4817 Handle<Object> proto(object->GetPrototype());
4818 if (proto->IsJSObject() &&
4819 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
4820 return HasLocalPropertyImplementation(isolate,
4821 Handle<JSObject>::cast(proto),
4824 return isolate->heap()->false_value();
4828 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
4829 NoHandleAllocation ha;
4830 ASSERT(args.length() == 2);
4831 CONVERT_ARG_CHECKED(String, key, 1);
4834 const bool key_is_array_index = key->AsArrayIndex(&index);
4836 Object* obj = args[0];
4837 // Only JS objects can have properties.
4838 if (obj->IsJSObject()) {
4839 JSObject* object = JSObject::cast(obj);
4840 // Fast case: either the key is a real named property or it is not
4841 // an array index and there are no interceptors or hidden
4843 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
4844 Map* map = object->map();
4845 if (!key_is_array_index &&
4846 !map->has_named_interceptor() &&
4847 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4848 return isolate->heap()->false_value();
4851 HandleScope scope(isolate);
4852 return HasLocalPropertyImplementation(isolate,
4853 Handle<JSObject>(object),
4854 Handle<String>(key));
4855 } else if (obj->IsString() && key_is_array_index) {
4856 // Well, there is one exception: Handle [] on strings.
4857 String* string = String::cast(obj);
4858 if (index < static_cast<uint32_t>(string->length())) {
4859 return isolate->heap()->true_value();
4862 return isolate->heap()->false_value();
4866 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
4867 NoHandleAllocation na;
4868 ASSERT(args.length() == 2);
4869 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4870 CONVERT_ARG_CHECKED(String, key, 1);
4872 bool result = receiver->HasProperty(key);
4873 if (isolate->has_pending_exception()) return Failure::Exception();
4874 return isolate->heap()->ToBoolean(result);
4878 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
4879 NoHandleAllocation na;
4880 ASSERT(args.length() == 2);
4881 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4882 CONVERT_SMI_ARG_CHECKED(index, 1);
4884 bool result = receiver->HasElement(index);
4885 if (isolate->has_pending_exception()) return Failure::Exception();
4886 return isolate->heap()->ToBoolean(result);
4890 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
4891 NoHandleAllocation ha;
4892 ASSERT(args.length() == 2);
4894 CONVERT_ARG_CHECKED(JSObject, object, 0);
4895 CONVERT_ARG_CHECKED(String, key, 1);
4898 if (key->AsArrayIndex(&index)) {
4899 JSObject::LocalElementType type = object->HasLocalElement(index);
4901 case JSObject::UNDEFINED_ELEMENT:
4902 case JSObject::STRING_CHARACTER_ELEMENT:
4903 return isolate->heap()->false_value();
4904 case JSObject::INTERCEPTED_ELEMENT:
4905 case JSObject::FAST_ELEMENT:
4906 return isolate->heap()->true_value();
4907 case JSObject::DICTIONARY_ELEMENT: {
4908 if (object->IsJSGlobalProxy()) {
4909 Object* proto = object->GetPrototype();
4910 if (proto->IsNull()) {
4911 return isolate->heap()->false_value();
4913 ASSERT(proto->IsJSGlobalObject());
4914 object = JSObject::cast(proto);
4916 FixedArray* elements = FixedArray::cast(object->elements());
4917 SeededNumberDictionary* dictionary = NULL;
4918 if (elements->map() ==
4919 isolate->heap()->non_strict_arguments_elements_map()) {
4920 dictionary = SeededNumberDictionary::cast(elements->get(1));
4922 dictionary = SeededNumberDictionary::cast(elements);
4924 int entry = dictionary->FindEntry(index);
4925 ASSERT(entry != SeededNumberDictionary::kNotFound);
4926 PropertyDetails details = dictionary->DetailsAt(entry);
4927 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4932 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4933 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
4937 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
4938 HandleScope scope(isolate);
4939 ASSERT(args.length() == 1);
4940 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
4942 Handle<JSArray> result = GetKeysFor(object, &threw);
4943 if (threw) return Failure::Exception();
4948 // Returns either a FixedArray as Runtime_GetPropertyNames,
4949 // or, if the given object has an enum cache that contains
4950 // all enumerable properties of the object and its prototypes
4951 // have none, the map of the object. This is used to speed up
4952 // the check for deletions during a for-in.
4953 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
4954 ASSERT(args.length() == 1);
4956 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
4958 if (raw_object->IsSimpleEnum()) return raw_object->map();
4960 HandleScope scope(isolate);
4961 Handle<JSReceiver> object(raw_object);
4963 Handle<FixedArray> content =
4964 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4965 if (threw) return Failure::Exception();
4967 // Test again, since cache may have been built by preceding call.
4968 if (object->IsSimpleEnum()) return object->map();
4974 // Find the length of the prototype chain that is to to handled as one. If a
4975 // prototype object is hidden it is to be viewed as part of the the object it
4976 // is prototype for.
4977 static int LocalPrototypeChainLength(JSObject* obj) {
4979 Object* proto = obj->GetPrototype();
4980 while (proto->IsJSObject() &&
4981 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4983 proto = JSObject::cast(proto)->GetPrototype();
4989 // Return the names of the local named properties.
4991 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
4992 HandleScope scope(isolate);
4993 ASSERT(args.length() == 1);
4994 if (!args[0]->IsJSObject()) {
4995 return isolate->heap()->undefined_value();
4997 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4999 // Skip the global proxy as it has no properties and always delegates to the
5000 // real global object.
5001 if (obj->IsJSGlobalProxy()) {
5002 // Only collect names if access is permitted.
5003 if (obj->IsAccessCheckNeeded() &&
5004 !isolate->MayNamedAccess(*obj,
5005 isolate->heap()->undefined_value(),
5007 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
5008 return *isolate->factory()->NewJSArray(0);
5010 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
5013 // Find the number of objects making up this.
5014 int length = LocalPrototypeChainLength(*obj);
5016 // Find the number of local properties for each of the objects.
5017 ScopedVector<int> local_property_count(length);
5018 int total_property_count = 0;
5019 Handle<JSObject> jsproto = obj;
5020 for (int i = 0; i < length; i++) {
5021 // Only collect names if access is permitted.
5022 if (jsproto->IsAccessCheckNeeded() &&
5023 !isolate->MayNamedAccess(*jsproto,
5024 isolate->heap()->undefined_value(),
5026 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5027 return *isolate->factory()->NewJSArray(0);
5030 n = jsproto->NumberOfLocalProperties();
5031 local_property_count[i] = n;
5032 total_property_count += n;
5033 if (i < length - 1) {
5034 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5038 // Allocate an array with storage for all the property names.
5039 Handle<FixedArray> names =
5040 isolate->factory()->NewFixedArray(total_property_count);
5042 // Get the property names.
5044 int proto_with_hidden_properties = 0;
5045 int next_copy_index = 0;
5046 for (int i = 0; i < length; i++) {
5047 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5048 next_copy_index += local_property_count[i];
5049 if (jsproto->HasHiddenProperties()) {
5050 proto_with_hidden_properties++;
5052 if (i < length - 1) {
5053 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5057 // Filter out name of hidden propeties object.
5058 if (proto_with_hidden_properties > 0) {
5059 Handle<FixedArray> old_names = names;
5060 names = isolate->factory()->NewFixedArray(
5061 names->length() - proto_with_hidden_properties);
5063 for (int i = 0; i < total_property_count; i++) {
5064 Object* name = old_names->get(i);
5065 if (name == isolate->heap()->hidden_symbol()) {
5068 names->set(dest_pos++, name);
5072 return *isolate->factory()->NewJSArrayWithElements(names);
5076 // Return the names of the local indexed properties.
5078 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
5079 HandleScope scope(isolate);
5080 ASSERT(args.length() == 1);
5081 if (!args[0]->IsJSObject()) {
5082 return isolate->heap()->undefined_value();
5084 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5086 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
5087 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
5088 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
5089 return *isolate->factory()->NewJSArrayWithElements(names);
5093 // Return information on whether an object has a named or indexed interceptor.
5095 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
5096 HandleScope scope(isolate);
5097 ASSERT(args.length() == 1);
5098 if (!args[0]->IsJSObject()) {
5099 return Smi::FromInt(0);
5101 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5104 if (obj->HasNamedInterceptor()) result |= 2;
5105 if (obj->HasIndexedInterceptor()) result |= 1;
5107 return Smi::FromInt(result);
5111 // Return property names from named interceptor.
5113 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
5114 HandleScope scope(isolate);
5115 ASSERT(args.length() == 1);
5116 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5118 if (obj->HasNamedInterceptor()) {
5119 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5120 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5122 return isolate->heap()->undefined_value();
5126 // Return element names from indexed interceptor.
5128 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
5129 HandleScope scope(isolate);
5130 ASSERT(args.length() == 1);
5131 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
5133 if (obj->HasIndexedInterceptor()) {
5134 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5135 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5137 return isolate->heap()->undefined_value();
5141 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
5142 ASSERT_EQ(args.length(), 1);
5143 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
5144 HandleScope scope(isolate);
5145 Handle<JSObject> object(raw_object);
5147 if (object->IsJSGlobalProxy()) {
5148 // Do access checks before going to the global object.
5149 if (object->IsAccessCheckNeeded() &&
5150 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
5152 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5153 return *isolate->factory()->NewJSArray(0);
5156 Handle<Object> proto(object->GetPrototype());
5157 // If proxy is detached we simply return an empty array.
5158 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
5159 object = Handle<JSObject>::cast(proto);
5163 Handle<FixedArray> contents =
5164 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5165 if (threw) return Failure::Exception();
5167 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5168 // property array and since the result is mutable we have to create
5169 // a fresh clone on each invocation.
5170 int length = contents->length();
5171 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
5172 for (int i = 0; i < length; i++) {
5173 Object* entry = contents->get(i);
5174 if (entry->IsString()) {
5175 copy->set(i, entry);
5177 ASSERT(entry->IsNumber());
5178 HandleScope scope(isolate);
5179 Handle<Object> entry_handle(entry, isolate);
5180 Handle<Object> entry_str =
5181 isolate->factory()->NumberToString(entry_handle);
5182 copy->set(i, *entry_str);
5185 return *isolate->factory()->NewJSArrayWithElements(copy);
5189 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
5190 NoHandleAllocation ha;
5191 ASSERT(args.length() == 1);
5193 // Compute the frame holding the arguments.
5194 JavaScriptFrameIterator it(isolate);
5195 it.AdvanceToArgumentsFrame();
5196 JavaScriptFrame* frame = it.frame();
5198 // Get the actual number of provided arguments.
5199 const uint32_t n = frame->ComputeParametersCount();
5201 // Try to convert the key to an index. If successful and within
5202 // index return the the argument from the frame.
5204 if (args[0]->ToArrayIndex(&index) && index < n) {
5205 return frame->GetParameter(index);
5208 // Convert the key to a string.
5209 HandleScope scope(isolate);
5210 bool exception = false;
5211 Handle<Object> converted =
5212 Execution::ToString(args.at<Object>(0), &exception);
5213 if (exception) return Failure::Exception();
5214 Handle<String> key = Handle<String>::cast(converted);
5216 // Try to convert the string key into an array index.
5217 if (key->AsArrayIndex(&index)) {
5219 return frame->GetParameter(index);
5221 return isolate->initial_object_prototype()->GetElement(index);
5225 // Handle special arguments properties.
5226 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5227 if (key->Equals(isolate->heap()->callee_symbol())) {
5228 Object* function = frame->function();
5229 if (function->IsJSFunction() &&
5230 !JSFunction::cast(function)->shared()->is_classic_mode()) {
5231 return isolate->Throw(*isolate->factory()->NewTypeError(
5232 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5237 // Lookup in the initial Object.prototype object.
5238 return isolate->initial_object_prototype()->GetProperty(*key);
5242 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
5243 ASSERT(args.length() == 1);
5244 Object* object = args[0];
5245 return (object->IsJSObject() && !object->IsGlobalObject())
5246 ? JSObject::cast(object)->TransformToFastProperties(0)
5251 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
5252 ASSERT(args.length() == 1);
5253 Object* obj = args[0];
5254 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5255 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5260 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
5261 NoHandleAllocation ha;
5262 ASSERT(args.length() == 1);
5264 return args[0]->ToBoolean();
5268 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5269 // Possible optimizations: put the type string into the oddballs.
5270 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
5271 NoHandleAllocation ha;
5273 Object* obj = args[0];
5274 if (obj->IsNumber()) return isolate->heap()->number_symbol();
5275 HeapObject* heap_obj = HeapObject::cast(obj);
5277 // typeof an undetectable object is 'undefined'
5278 if (heap_obj->map()->is_undetectable()) {
5279 return isolate->heap()->undefined_symbol();
5282 InstanceType instance_type = heap_obj->map()->instance_type();
5283 if (instance_type < FIRST_NONSTRING_TYPE) {
5284 return isolate->heap()->string_symbol();
5287 switch (instance_type) {
5289 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
5290 return isolate->heap()->boolean_symbol();
5292 if (heap_obj->IsNull()) {
5293 return FLAG_harmony_typeof
5294 ? isolate->heap()->null_symbol()
5295 : isolate->heap()->object_symbol();
5297 ASSERT(heap_obj->IsUndefined());
5298 return isolate->heap()->undefined_symbol();
5299 case JS_FUNCTION_TYPE:
5300 case JS_FUNCTION_PROXY_TYPE:
5301 return isolate->heap()->function_symbol();
5303 // For any kind of object not handled above, the spec rule for
5304 // host objects gives that it is okay to return "object"
5305 return isolate->heap()->object_symbol();
5310 static bool AreDigits(const char*s, int from, int to) {
5311 for (int i = from; i < to; i++) {
5312 if (s[i] < '0' || s[i] > '9') return false;
5319 static int ParseDecimalInteger(const char*s, int from, int to) {
5320 ASSERT(to - from < 10); // Overflow is not possible.
5322 int d = s[from] - '0';
5324 for (int i = from + 1; i < to; i++) {
5325 d = 10 * d + (s[i] - '0');
5332 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
5333 NoHandleAllocation ha;
5334 ASSERT(args.length() == 1);
5335 CONVERT_ARG_CHECKED(String, subject, 0);
5336 subject->TryFlatten();
5338 // Fast case: short integer or some sorts of junk values.
5339 int len = subject->length();
5340 if (subject->IsSeqAsciiString()) {
5341 if (len == 0) return Smi::FromInt(0);
5343 char const* data = SeqAsciiString::cast(subject)->GetChars();
5344 bool minus = (data[0] == '-');
5345 int start_pos = (minus ? 1 : 0);
5347 if (start_pos == len) {
5348 return isolate->heap()->nan_value();
5349 } else if (data[start_pos] > '9') {
5350 // Fast check for a junk value. A valid string may start from a
5351 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5352 // the 'I' character ('Infinity'). All of that have codes not greater than
5354 if (data[start_pos] != 'I') {
5355 return isolate->heap()->nan_value();
5357 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5358 // The maximal/minimal smi has 10 digits. If the string has less digits we
5359 // know it will fit into the smi-data type.
5360 int d = ParseDecimalInteger(data, start_pos, len);
5362 if (d == 0) return isolate->heap()->minus_zero_value();
5364 } else if (!subject->HasHashCode() &&
5365 len <= String::kMaxArrayIndexSize &&
5366 (len == 1 || data[0] != '0')) {
5367 // String hash is not calculated yet but all the data are present.
5368 // Update the hash field to speed up sequential convertions.
5369 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
5371 subject->Hash(); // Force hash calculation.
5372 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5373 static_cast<int>(hash));
5375 subject->set_hash_field(hash);
5377 return Smi::FromInt(d);
5382 return isolate->heap()->NumberFromDouble(
5383 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
5387 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
5388 NoHandleAllocation ha;
5389 ASSERT(args.length() == 1);
5391 CONVERT_ARG_CHECKED(JSArray, codes, 0);
5392 int length = Smi::cast(codes->length())->value();
5394 // Check if the string can be ASCII.
5396 for (i = 0; i < length; i++) {
5398 { MaybeObject* maybe_element = codes->GetElement(i);
5399 // We probably can't get an exception here, but just in order to enforce
5400 // the checking of inputs in the runtime calls we check here.
5401 if (!maybe_element->ToObject(&element)) return maybe_element;
5403 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5404 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5408 MaybeObject* maybe_object = NULL;
5409 if (i == length) { // The string is ASCII.
5410 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
5411 } else { // The string is not ASCII.
5412 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
5415 Object* object = NULL;
5416 if (!maybe_object->ToObject(&object)) return maybe_object;
5417 String* result = String::cast(object);
5418 for (int i = 0; i < length; i++) {
5420 { MaybeObject* maybe_element = codes->GetElement(i);
5421 if (!maybe_element->ToObject(&element)) return maybe_element;
5423 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5424 result->Set(i, chr & 0xffff);
5430 // kNotEscaped is generated by the following:
5433 // for (my $i = 0; $i < 256; $i++) {
5434 // print "\n" if $i % 16 == 0;
5437 // $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5438 // print $escaped ? "0, " : "1, ";
5442 static bool IsNotEscaped(uint16_t character) {
5443 // Only for 8 bit characters, the rest are always escaped (in a different way)
5444 ASSERT(character < 256);
5445 static const char kNotEscaped[256] = {
5446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5448 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5452 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5454 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5457 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5458 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5459 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5463 return kNotEscaped[character] != 0;
5467 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
5468 const char hex_chars[] = "0123456789ABCDEF";
5469 NoHandleAllocation ha;
5470 ASSERT(args.length() == 1);
5471 CONVERT_ARG_CHECKED(String, source, 0);
5473 source->TryFlatten();
5475 int escaped_length = 0;
5476 int length = source->length();
5478 Access<StringInputBuffer> buffer(
5479 isolate->runtime_state()->string_input_buffer());
5480 buffer->Reset(source);
5481 while (buffer->has_more()) {
5482 uint16_t character = buffer->GetNext();
5483 if (character >= 256) {
5484 escaped_length += 6;
5485 } else if (IsNotEscaped(character)) {
5488 escaped_length += 3;
5490 // We don't allow strings that are longer than a maximal length.
5491 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
5492 if (escaped_length > String::kMaxLength) {
5493 isolate->context()->mark_out_of_memory();
5494 return Failure::OutOfMemoryException();
5498 // No length change implies no change. Return original string if no change.
5499 if (escaped_length == length) {
5503 { MaybeObject* maybe_o =
5504 isolate->heap()->AllocateRawAsciiString(escaped_length);
5505 if (!maybe_o->ToObject(&o)) return maybe_o;
5507 String* destination = String::cast(o);
5508 int dest_position = 0;
5510 Access<StringInputBuffer> buffer(
5511 isolate->runtime_state()->string_input_buffer());
5513 while (buffer->has_more()) {
5514 uint16_t chr = buffer->GetNext();
5516 destination->Set(dest_position, '%');
5517 destination->Set(dest_position+1, 'u');
5518 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5519 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5520 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5521 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
5523 } else if (IsNotEscaped(chr)) {
5524 destination->Set(dest_position, chr);
5527 destination->Set(dest_position, '%');
5528 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5529 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
5537 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5538 static const signed char kHexValue['g'] = {
5539 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5540 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5541 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5542 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5543 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5544 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5545 -1, 10, 11, 12, 13, 14, 15 };
5547 if (character1 > 'f') return -1;
5548 int hi = kHexValue[character1];
5549 if (hi == -1) return -1;
5550 if (character2 > 'f') return -1;
5551 int lo = kHexValue[character2];
5552 if (lo == -1) return -1;
5553 return (hi << 4) + lo;
5557 static inline int Unescape(String* source,
5561 uint16_t character = source->Get(i);
5564 if (character == '%' &&
5566 source->Get(i + 1) == 'u' &&
5567 (hi = TwoDigitHex(source->Get(i + 2),
5568 source->Get(i + 3))) != -1 &&
5569 (lo = TwoDigitHex(source->Get(i + 4),
5570 source->Get(i + 5))) != -1) {
5572 return (hi << 8) + lo;
5573 } else if (character == '%' &&
5575 (lo = TwoDigitHex(source->Get(i + 1),
5576 source->Get(i + 2))) != -1) {
5586 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
5587 NoHandleAllocation ha;
5588 ASSERT(args.length() == 1);
5589 CONVERT_ARG_CHECKED(String, source, 0);
5591 source->TryFlatten();
5594 int length = source->length();
5596 int unescaped_length = 0;
5597 for (int i = 0; i < length; unescaped_length++) {
5599 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
5605 // No length change implies no change. Return original string if no change.
5606 if (unescaped_length == length)
5610 { MaybeObject* maybe_o =
5612 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5613 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
5614 if (!maybe_o->ToObject(&o)) return maybe_o;
5616 String* destination = String::cast(o);
5618 int dest_position = 0;
5619 for (int i = 0; i < length; dest_position++) {
5621 destination->Set(dest_position, Unescape(source, i, length, &step));
5628 static const unsigned int kQuoteTableLength = 128u;
5630 static const int kJsonQuotesCharactersPerEntry = 8;
5631 static const char* const JsonQuotes =
5632 "\\u0000 \\u0001 \\u0002 \\u0003 "
5633 "\\u0004 \\u0005 \\u0006 \\u0007 "
5634 "\\b \\t \\n \\u000b "
5635 "\\f \\r \\u000e \\u000f "
5636 "\\u0010 \\u0011 \\u0012 \\u0013 "
5637 "\\u0014 \\u0015 \\u0016 \\u0017 "
5638 "\\u0018 \\u0019 \\u001a \\u001b "
5639 "\\u001c \\u001d \\u001e \\u001f "
5666 // For a string that is less than 32k characters it should always be
5667 // possible to allocate it in new space.
5668 static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5671 // Doing JSON quoting cannot make the string more than this many times larger.
5672 static const int kJsonQuoteWorstCaseBlowup = 6;
5674 static const int kSpaceForQuotesAndComma = 3;
5675 static const int kSpaceForBrackets = 2;
5677 // Covers the entire ASCII range (all other characters are unchanged by JSON
5679 static const byte JsonQuoteLengths[kQuoteTableLength] = {
5680 6, 6, 6, 6, 6, 6, 6, 6,
5681 2, 2, 2, 6, 2, 2, 6, 6,
5682 6, 6, 6, 6, 6, 6, 6, 6,
5683 6, 6, 6, 6, 6, 6, 6, 6,
5684 1, 1, 2, 1, 1, 1, 1, 1,
5685 1, 1, 1, 1, 1, 1, 1, 1,
5686 1, 1, 1, 1, 1, 1, 1, 1,
5687 1, 1, 1, 1, 1, 1, 1, 1,
5688 1, 1, 1, 1, 1, 1, 1, 1,
5689 1, 1, 1, 1, 1, 1, 1, 1,
5690 1, 1, 1, 1, 1, 1, 1, 1,
5691 1, 1, 1, 1, 2, 1, 1, 1,
5692 1, 1, 1, 1, 1, 1, 1, 1,
5693 1, 1, 1, 1, 1, 1, 1, 1,
5694 1, 1, 1, 1, 1, 1, 1, 1,
5695 1, 1, 1, 1, 1, 1, 1, 1,
5699 template <typename StringType>
5700 MaybeObject* AllocateRawString(Isolate* isolate, int length);
5704 MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5705 return isolate->heap()->AllocateRawTwoByteString(length);
5710 MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5711 return isolate->heap()->AllocateRawAsciiString(length);
5715 template <typename Char, typename StringType, bool comma>
5716 static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5717 Vector<const Char> characters) {
5718 int length = characters.length();
5719 const Char* read_cursor = characters.start();
5720 const Char* end = read_cursor + length;
5721 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
5722 int quoted_length = kSpaceForQuotes;
5723 while (read_cursor < end) {
5724 Char c = *(read_cursor++);
5725 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5728 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
5731 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5734 if (!new_alloc->ToObject(&new_object)) {
5737 StringType* new_string = StringType::cast(new_object);
5739 Char* write_cursor = reinterpret_cast<Char*>(
5740 new_string->address() + SeqString::kHeaderSize);
5741 if (comma) *(write_cursor++) = ',';
5742 *(write_cursor++) = '"';
5744 read_cursor = characters.start();
5745 while (read_cursor < end) {
5746 Char c = *(read_cursor++);
5747 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5748 *(write_cursor++) = c;
5750 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5751 const char* replacement = JsonQuotes +
5752 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5753 for (int i = 0; i < len; i++) {
5754 *write_cursor++ = *replacement++;
5758 *(write_cursor++) = '"';
5763 template <typename SinkChar, typename SourceChar>
5764 static inline SinkChar* WriteQuoteJsonString(
5766 SinkChar* write_cursor,
5767 Vector<const SourceChar> characters) {
5768 // SinkChar is only char if SourceChar is guaranteed to be char.
5769 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
5770 const SourceChar* read_cursor = characters.start();
5771 const SourceChar* end = read_cursor + characters.length();
5772 *(write_cursor++) = '"';
5773 while (read_cursor < end) {
5774 SourceChar c = *(read_cursor++);
5775 if (sizeof(SourceChar) > 1u &&
5776 static_cast<unsigned>(c) >= kQuoteTableLength) {
5777 *(write_cursor++) = static_cast<SinkChar>(c);
5779 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5780 const char* replacement = JsonQuotes +
5781 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5782 write_cursor[0] = replacement[0];
5784 write_cursor[1] = replacement[1];
5787 write_cursor[2] = replacement[2];
5788 write_cursor[3] = replacement[3];
5789 write_cursor[4] = replacement[4];
5790 write_cursor[5] = replacement[5];
5793 write_cursor += len;
5796 *(write_cursor++) = '"';
5797 return write_cursor;
5801 template <typename Char, typename StringType, bool comma>
5802 static MaybeObject* QuoteJsonString(Isolate* isolate,
5803 Vector<const Char> characters) {
5804 int length = characters.length();
5805 isolate->counters()->quote_json_char_count()->Increment(length);
5806 int worst_case_length =
5807 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
5808 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5809 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5812 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5815 if (!new_alloc->ToObject(&new_object)) {
5818 if (!isolate->heap()->new_space()->Contains(new_object)) {
5819 // Even if our string is small enough to fit in new space we still have to
5820 // handle it being allocated in old space as may happen in the third
5821 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5822 // CEntryStub::GenerateCore.
5823 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
5825 StringType* new_string = StringType::cast(new_object);
5826 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5828 Char* write_cursor = reinterpret_cast<Char*>(
5829 new_string->address() + SeqString::kHeaderSize);
5830 if (comma) *(write_cursor++) = ',';
5831 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5834 int final_length = static_cast<int>(
5835 write_cursor - reinterpret_cast<Char*>(
5836 new_string->address() + SeqString::kHeaderSize));
5837 isolate->heap()->new_space()->
5838 template ShrinkStringAtAllocationBoundary<StringType>(
5839 new_string, final_length);
5844 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
5845 NoHandleAllocation ha;
5846 CONVERT_ARG_CHECKED(String, str, 0);
5847 if (!str->IsFlat()) {
5848 MaybeObject* try_flatten = str->TryFlatten();
5850 if (!try_flatten->ToObject(&flat)) {
5853 str = String::cast(flat);
5854 ASSERT(str->IsFlat());
5856 String::FlatContent flat = str->GetFlatContent();
5857 ASSERT(flat.IsFlat());
5858 if (flat.IsTwoByte()) {
5859 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5860 flat.ToUC16Vector());
5862 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5863 flat.ToAsciiVector());
5868 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
5869 NoHandleAllocation ha;
5870 CONVERT_ARG_CHECKED(String, str, 0);
5871 if (!str->IsFlat()) {
5872 MaybeObject* try_flatten = str->TryFlatten();
5874 if (!try_flatten->ToObject(&flat)) {
5877 str = String::cast(flat);
5878 ASSERT(str->IsFlat());
5880 String::FlatContent flat = str->GetFlatContent();
5881 if (flat.IsTwoByte()) {
5882 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5883 flat.ToUC16Vector());
5885 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5886 flat.ToAsciiVector());
5891 template <typename Char, typename StringType>
5892 static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5894 int worst_case_length) {
5895 int length = array->length();
5897 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5900 if (!new_alloc->ToObject(&new_object)) {
5903 if (!isolate->heap()->new_space()->Contains(new_object)) {
5904 // Even if our string is small enough to fit in new space we still have to
5905 // handle it being allocated in old space as may happen in the third
5906 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5907 // CEntryStub::GenerateCore.
5908 return isolate->heap()->undefined_value();
5910 AssertNoAllocation no_gc;
5911 StringType* new_string = StringType::cast(new_object);
5912 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5914 Char* write_cursor = reinterpret_cast<Char*>(
5915 new_string->address() + SeqString::kHeaderSize);
5916 *(write_cursor++) = '[';
5917 for (int i = 0; i < length; i++) {
5918 if (i != 0) *(write_cursor++) = ',';
5919 String* str = String::cast(array->get(i));
5920 String::FlatContent content = str->GetFlatContent();
5921 ASSERT(content.IsFlat());
5922 if (content.IsTwoByte()) {
5923 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5925 content.ToUC16Vector());
5927 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5929 content.ToAsciiVector());
5932 *(write_cursor++) = ']';
5934 int final_length = static_cast<int>(
5935 write_cursor - reinterpret_cast<Char*>(
5936 new_string->address() + SeqString::kHeaderSize));
5937 isolate->heap()->new_space()->
5938 template ShrinkStringAtAllocationBoundary<StringType>(
5939 new_string, final_length);
5944 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5945 NoHandleAllocation ha;
5946 ASSERT(args.length() == 1);
5947 CONVERT_ARG_CHECKED(JSArray, array, 0);
5949 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5950 FixedArray* elements = FixedArray::cast(array->elements());
5951 int n = elements->length();
5953 int total_length = 0;
5955 for (int i = 0; i < n; i++) {
5956 Object* elt = elements->get(i);
5957 if (!elt->IsString()) return isolate->heap()->undefined_value();
5958 String* element = String::cast(elt);
5959 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5960 total_length += element->length();
5961 if (ascii && element->IsTwoByteRepresentation()) {
5966 int worst_case_length =
5967 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5968 + total_length * kJsonQuoteWorstCaseBlowup;
5970 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5971 return isolate->heap()->undefined_value();
5975 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5979 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5986 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
5987 NoHandleAllocation ha;
5989 CONVERT_ARG_CHECKED(String, s, 0);
5990 CONVERT_SMI_ARG_CHECKED(radix, 1);
5994 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
5995 double value = StringToInt(isolate->unicode_cache(), s, radix);
5996 return isolate->heap()->NumberFromDouble(value);
6000 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
6001 NoHandleAllocation ha;
6002 CONVERT_ARG_CHECKED(String, str, 0);
6004 // ECMA-262 section 15.1.2.3, empty string is NaN
6005 double value = StringToDouble(isolate->unicode_cache(),
6006 str, ALLOW_TRAILING_JUNK, OS::nan_value());
6008 // Create a number object from the value.
6009 return isolate->heap()->NumberFromDouble(value);
6013 template <class Converter>
6014 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
6018 int input_string_length,
6019 unibrow::Mapping<Converter, 128>* mapping) {
6020 // We try this twice, once with the assumption that the result is no longer
6021 // than the input and, if that assumption breaks, again with the exact
6022 // length. This may not be pretty, but it is nicer than what was here before
6023 // and I hereby claim my vaffel-is.
6025 // Allocate the resulting string.
6027 // NOTE: This assumes that the upper/lower case of an ASCII
6028 // character is also ASCII. This is currently the case, but it
6029 // might break in the future if we implement more context and locale
6030 // dependent upper/lower conversions.
6032 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
6033 ? isolate->heap()->AllocateRawAsciiString(length)
6034 : isolate->heap()->AllocateRawTwoByteString(length);
6035 if (!maybe_o->ToObject(&o)) return maybe_o;
6037 String* result = String::cast(o);
6038 bool has_changed_character = false;
6040 // Convert all characters to upper case, assuming that they will fit
6042 Access<StringInputBuffer> buffer(
6043 isolate->runtime_state()->string_input_buffer());
6045 unibrow::uchar chars[Converter::kMaxWidth];
6046 // We can assume that the string is not empty
6047 uc32 current = buffer->GetNext();
6048 for (int i = 0; i < length;) {
6049 bool has_next = buffer->has_more();
6050 uc32 next = has_next ? buffer->GetNext() : 0;
6051 int char_length = mapping->get(current, next, chars);
6052 if (char_length == 0) {
6053 // The case conversion of this character is the character itself.
6054 result->Set(i, current);
6056 } else if (char_length == 1) {
6057 // Common case: converting the letter resulted in one character.
6058 ASSERT(static_cast<uc32>(chars[0]) != current);
6059 result->Set(i, chars[0]);
6060 has_changed_character = true;
6062 } else if (length == input_string_length) {
6063 // We've assumed that the result would be as long as the
6064 // input but here is a character that converts to several
6065 // characters. No matter, we calculate the exact length
6066 // of the result and try the whole thing again.
6068 // Note that this leaves room for optimization. We could just
6069 // memcpy what we already have to the result string. Also,
6070 // the result string is the last object allocated we could
6071 // "realloc" it and probably, in the vast majority of cases,
6072 // extend the existing string to be able to hold the full
6074 int next_length = 0;
6076 next_length = mapping->get(next, 0, chars);
6077 if (next_length == 0) next_length = 1;
6079 int current_length = i + char_length + next_length;
6080 while (buffer->has_more()) {
6081 current = buffer->GetNext();
6082 // NOTE: we use 0 as the next character here because, while
6083 // the next character may affect what a character converts to,
6084 // it does not in any case affect the length of what it convert
6086 int char_length = mapping->get(current, 0, chars);
6087 if (char_length == 0) char_length = 1;
6088 current_length += char_length;
6089 if (current_length > Smi::kMaxValue) {
6090 isolate->context()->mark_out_of_memory();
6091 return Failure::OutOfMemoryException();
6094 // Try again with the real length.
6095 return Smi::FromInt(current_length);
6097 for (int j = 0; j < char_length; j++) {
6098 result->Set(i, chars[j]);
6101 has_changed_character = true;
6105 if (has_changed_character) {
6108 // If we didn't actually change anything in doing the conversion
6109 // we simple return the result and let the converted string
6110 // become garbage; there is no reason to keep two identical strings
6119 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6122 // Given a word and two range boundaries returns a word with high bit
6123 // set in every byte iff the corresponding input byte was strictly in
6124 // the range (m, n). All the other bits in the result are cleared.
6125 // This function is only useful when it can be inlined and the
6126 // boundaries are statically known.
6127 // Requires: all bytes in the input word and the boundaries must be
6128 // ASCII (less than 0x7F).
6129 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6130 // Every byte in an ASCII string is less than or equal to 0x7F.
6131 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6132 // Use strict inequalities since in edge cases the function could be
6133 // further simplified.
6134 ASSERT(0 < m && m < n && n < 0x7F);
6135 // Has high bit set in every w byte less than n.
6136 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6137 // Has high bit set in every w byte greater than m.
6138 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6139 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6143 enum AsciiCaseConversion {
6149 template <AsciiCaseConversion dir>
6150 struct FastAsciiConverter {
6151 static bool Convert(char* dst, char* src, int length) {
6153 char* saved_dst = dst;
6154 char* saved_src = src;
6156 // We rely on the distance between upper and lower case letters
6157 // being a known power of 2.
6158 ASSERT('a' - 'A' == (1 << 5));
6159 // Boundaries for the range of input characters than require conversion.
6160 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6161 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6162 bool changed = false;
6163 char* const limit = src + length;
6164 #ifdef V8_HOST_CAN_READ_UNALIGNED
6165 // Process the prefix of the input that requires no conversion one
6166 // (machine) word at a time.
6167 while (src <= limit - sizeof(uintptr_t)) {
6168 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6169 if (AsciiRangeMask(w, lo, hi) != 0) {
6173 *reinterpret_cast<uintptr_t*>(dst) = w;
6174 src += sizeof(uintptr_t);
6175 dst += sizeof(uintptr_t);
6177 // Process the remainder of the input performing conversion when
6178 // required one word at a time.
6179 while (src <= limit - sizeof(uintptr_t)) {
6180 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6181 uintptr_t m = AsciiRangeMask(w, lo, hi);
6182 // The mask has high (7th) bit set in every byte that needs
6183 // conversion and we know that the distance between cases is
6185 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6186 src += sizeof(uintptr_t);
6187 dst += sizeof(uintptr_t);
6190 // Process the last few bytes of the input (or the whole input if
6191 // unaligned access is not supported).
6192 while (src < limit) {
6194 if (lo < c && c < hi) {
6203 CheckConvert(saved_dst, saved_src, length, changed);
6209 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6210 bool expected_changed = false;
6211 for (int i = 0; i < length; i++) {
6212 if (dst[i] == src[i]) continue;
6213 expected_changed = true;
6214 if (dir == ASCII_TO_LOWER) {
6215 ASSERT('A' <= src[i] && src[i] <= 'Z');
6216 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6218 ASSERT(dir == ASCII_TO_UPPER);
6219 ASSERT('a' <= src[i] && src[i] <= 'z');
6220 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6223 ASSERT(expected_changed == changed);
6229 struct ToLowerTraits {
6230 typedef unibrow::ToLowercase UnibrowConverter;
6232 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
6236 struct ToUpperTraits {
6237 typedef unibrow::ToUppercase UnibrowConverter;
6239 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
6245 template <typename ConvertTraits>
6246 MUST_USE_RESULT static MaybeObject* ConvertCase(
6249 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
6250 NoHandleAllocation ha;
6251 CONVERT_ARG_CHECKED(String, s, 0);
6252 s = s->TryFlattenGetString();
6254 const int length = s->length();
6255 // Assume that the string is not empty; we need this assumption later
6256 if (length == 0) return s;
6258 // Simpler handling of ASCII strings.
6260 // NOTE: This assumes that the upper/lower case of an ASCII
6261 // character is also ASCII. This is currently the case, but it
6262 // might break in the future if we implement more context and locale
6263 // dependent upper/lower conversions.
6264 if (s->IsSeqAsciiString()) {
6266 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
6267 if (!maybe_o->ToObject(&o)) return maybe_o;
6269 SeqAsciiString* result = SeqAsciiString::cast(o);
6270 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
6271 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
6272 return has_changed_character ? result : s;
6276 { MaybeObject* maybe_answer =
6277 ConvertCaseHelper(isolate, s, length, length, mapping);
6278 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6280 if (answer->IsSmi()) {
6281 // Retry with correct length.
6282 { MaybeObject* maybe_answer =
6283 ConvertCaseHelper(isolate,
6284 s, Smi::cast(answer)->value(), length, mapping);
6285 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6292 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
6293 return ConvertCase<ToLowerTraits>(
6294 args, isolate, isolate->runtime_state()->to_lower_mapping());
6298 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
6299 return ConvertCase<ToUpperTraits>(
6300 args, isolate, isolate->runtime_state()->to_upper_mapping());
6304 static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6305 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
6309 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
6310 NoHandleAllocation ha;
6311 ASSERT(args.length() == 3);
6313 CONVERT_ARG_CHECKED(String, s, 0);
6314 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6315 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
6318 int length = s->length();
6322 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6329 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6333 return s->SubString(left, right);
6337 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
6338 ASSERT(args.length() == 3);
6339 HandleScope handle_scope(isolate);
6340 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6341 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
6342 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6344 int subject_length = subject->length();
6345 int pattern_length = pattern->length();
6346 RUNTIME_ASSERT(pattern_length > 0);
6348 if (limit == 0xffffffffu) {
6349 Handle<Object> cached_answer(StringSplitCache::Lookup(
6350 isolate->heap()->string_split_cache(),
6353 if (*cached_answer != Smi::FromInt(0)) {
6354 Handle<JSArray> result =
6355 isolate->factory()->NewJSArrayWithElements(
6356 Handle<FixedArray>::cast(cached_answer));
6361 // The limit can be very large (0xffffffffu), but since the pattern
6362 // isn't empty, we can never create more parts than ~half the length
6365 if (!subject->IsFlat()) FlattenString(subject);
6367 static const int kMaxInitialListCapacity = 16;
6369 ZoneScope scope(isolate, DELETE_ON_EXIT);
6371 // Find (up to limit) indices of separator and end-of-string in subject
6372 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6373 ZoneList<int> indices(initial_capacity);
6374 if (!pattern->IsFlat()) FlattenString(pattern);
6376 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
6378 if (static_cast<uint32_t>(indices.length()) < limit) {
6379 indices.Add(subject_length);
6382 // The list indices now contains the end of each part to create.
6384 // Create JSArray of substrings separated by separator.
6385 int part_count = indices.length();
6387 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
6388 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
6389 if (maybe_result->IsFailure()) return maybe_result;
6390 result->set_length(Smi::FromInt(part_count));
6392 ASSERT(result->HasFastElements());
6394 if (part_count == 1 && indices.at(0) == subject_length) {
6395 FixedArray::cast(result->elements())->set(0, *subject);
6399 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6401 for (int i = 0; i < part_count; i++) {
6402 HandleScope local_loop_handle;
6403 int part_end = indices.at(i);
6404 Handle<String> substring =
6405 isolate->factory()->NewProperSubString(subject, part_start, part_end);
6406 elements->set(i, *substring);
6407 part_start = part_end + pattern_length;
6410 if (limit == 0xffffffffu) {
6411 if (result->HasFastElements()) {
6412 StringSplitCache::Enter(isolate->heap(),
6413 isolate->heap()->string_split_cache(),
6424 // Copies ASCII characters to the given fixed array looking up
6425 // one-char strings in the cache. Gives up on the first char that is
6426 // not in the cache and fills the remainder with smi zeros. Returns
6427 // the length of the successfully copied prefix.
6428 static int CopyCachedAsciiCharsToArray(Heap* heap,
6430 FixedArray* elements,
6432 AssertNoAllocation no_gc;
6433 FixedArray* ascii_cache = heap->single_character_string_cache();
6434 Object* undefined = heap->undefined_value();
6436 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
6437 for (i = 0; i < length; ++i) {
6438 Object* value = ascii_cache->get(chars[i]);
6439 if (value == undefined) break;
6440 elements->set(i, value, mode);
6443 ASSERT(Smi::FromInt(0) == 0);
6444 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6447 for (int j = 0; j < length; ++j) {
6448 Object* element = elements->get(j);
6449 ASSERT(element == Smi::FromInt(0) ||
6450 (element->IsString() && String::cast(element)->LooksValid()));
6457 // Converts a String to JSArray.
6458 // For example, "foo" => ["f", "o", "o"].
6459 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
6460 HandleScope scope(isolate);
6461 ASSERT(args.length() == 2);
6462 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
6463 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
6465 s = FlattenGetString(s);
6466 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
6468 Handle<FixedArray> elements;
6470 if (s->IsFlat() && s->IsAsciiRepresentation()) {
6471 // Try using cached chars where possible.
6473 { MaybeObject* maybe_obj =
6474 isolate->heap()->AllocateUninitializedFixedArray(length);
6475 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6477 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
6478 String::FlatContent content = s->GetFlatContent();
6479 if (content.IsAscii()) {
6480 Vector<const char> chars = content.ToAsciiVector();
6481 // Note, this will initialize all elements (not only the prefix)
6482 // to prevent GC from seeing partially initialized array.
6483 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6488 MemsetPointer(elements->data_start(),
6489 isolate->heap()->undefined_value(),
6493 elements = isolate->factory()->NewFixedArray(length);
6495 for (int i = position; i < length; ++i) {
6496 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6497 elements->set(i, *str);
6501 for (int i = 0; i < length; ++i) {
6502 ASSERT(String::cast(elements->get(i))->length() == 1);
6506 return *isolate->factory()->NewJSArrayWithElements(elements);
6510 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
6511 NoHandleAllocation ha;
6512 ASSERT(args.length() == 1);
6513 CONVERT_ARG_CHECKED(String, value, 0);
6514 return value->ToObject();
6518 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
6519 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
6520 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
6521 return char_length == 0;
6525 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
6526 NoHandleAllocation ha;
6527 ASSERT(args.length() == 1);
6529 Object* number = args[0];
6530 RUNTIME_ASSERT(number->IsNumber());
6532 return isolate->heap()->NumberToString(number);
6536 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
6537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
6540 Object* number = args[0];
6541 RUNTIME_ASSERT(number->IsNumber());
6543 return isolate->heap()->NumberToString(number, false);
6547 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
6548 NoHandleAllocation ha;
6549 ASSERT(args.length() == 1);
6551 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6553 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6554 if (number > 0 && number <= Smi::kMaxValue) {
6555 return Smi::FromInt(static_cast<int>(number));
6557 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
6561 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
6562 NoHandleAllocation ha;
6563 ASSERT(args.length() == 1);
6565 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6567 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6568 if (number > 0 && number <= Smi::kMaxValue) {
6569 return Smi::FromInt(static_cast<int>(number));
6572 double double_value = DoubleToInteger(number);
6573 // Map both -0 and +0 to +0.
6574 if (double_value == 0) double_value = 0;
6576 return isolate->heap()->NumberFromDouble(double_value);
6580 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
6581 NoHandleAllocation ha;
6582 ASSERT(args.length() == 1);
6584 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
6585 return isolate->heap()->NumberFromUint32(number);
6589 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
6590 NoHandleAllocation ha;
6591 ASSERT(args.length() == 1);
6593 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
6595 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6596 if (number > 0 && number <= Smi::kMaxValue) {
6597 return Smi::FromInt(static_cast<int>(number));
6599 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
6603 // Converts a Number to a Smi, if possible. Returns NaN if the number is not
6605 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
6606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 1);
6609 Object* obj = args[0];
6613 if (obj->IsHeapNumber()) {
6614 double value = HeapNumber::cast(obj)->value();
6615 int int_value = FastD2I(value);
6616 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6617 return Smi::FromInt(int_value);
6620 return isolate->heap()->nan_value();
6624 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
6625 NoHandleAllocation ha;
6626 ASSERT(args.length() == 0);
6627 return isolate->heap()->AllocateHeapNumber(0);
6631 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
6632 NoHandleAllocation ha;
6633 ASSERT(args.length() == 2);
6635 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6636 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6637 return isolate->heap()->NumberFromDouble(x + y);
6641 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
6642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 2);
6645 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6646 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6647 return isolate->heap()->NumberFromDouble(x - y);
6651 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
6652 NoHandleAllocation ha;
6653 ASSERT(args.length() == 2);
6655 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6656 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6657 return isolate->heap()->NumberFromDouble(x * y);
6661 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
6662 NoHandleAllocation ha;
6663 ASSERT(args.length() == 1);
6665 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6666 return isolate->heap()->NumberFromDouble(-x);
6670 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
6671 NoHandleAllocation ha;
6672 ASSERT(args.length() == 0);
6674 return isolate->heap()->NumberFromDouble(9876543210.0);
6678 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
6679 NoHandleAllocation ha;
6680 ASSERT(args.length() == 2);
6682 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6683 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6684 return isolate->heap()->NumberFromDouble(x / y);
6688 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
6689 NoHandleAllocation ha;
6690 ASSERT(args.length() == 2);
6692 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6693 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
6696 // NumberFromDouble may return a Smi instead of a Number object
6697 return isolate->heap()->NumberFromDouble(x);
6701 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
6702 NoHandleAllocation ha;
6703 ASSERT(args.length() == 2);
6704 CONVERT_ARG_CHECKED(String, str1, 0);
6705 CONVERT_ARG_CHECKED(String, str2, 1);
6706 isolate->counters()->string_add_runtime()->Increment();
6707 return isolate->heap()->AllocateConsString(str1, str2);
6711 template <typename sinkchar>
6712 static inline void StringBuilderConcatHelper(String* special,
6714 FixedArray* fixed_array,
6717 for (int i = 0; i < array_length; i++) {
6718 Object* element = fixed_array->get(i);
6719 if (element->IsSmi()) {
6720 // Smi encoding of position and length.
6721 int encoded_slice = Smi::cast(element)->value();
6724 if (encoded_slice > 0) {
6725 // Position and length encoded in one smi.
6726 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6727 len = StringBuilderSubstringLength::decode(encoded_slice);
6729 // Position and length encoded in two smis.
6730 Object* obj = fixed_array->get(++i);
6731 ASSERT(obj->IsSmi());
6732 pos = Smi::cast(obj)->value();
6733 len = -encoded_slice;
6735 String::WriteToFlat(special,
6741 String* string = String::cast(element);
6742 int element_length = string->length();
6743 String::WriteToFlat(string, sink + position, 0, element_length);
6744 position += element_length;
6750 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
6751 NoHandleAllocation ha;
6752 ASSERT(args.length() == 3);
6753 CONVERT_ARG_CHECKED(JSArray, array, 0);
6754 if (!args[1]->IsSmi()) {
6755 isolate->context()->mark_out_of_memory();
6756 return Failure::OutOfMemoryException();
6758 int array_length = args.smi_at(1);
6759 CONVERT_ARG_CHECKED(String, special, 2);
6761 // This assumption is used by the slice encoding in one or two smis.
6762 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6764 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
6765 if (maybe_result->IsFailure()) return maybe_result;
6767 int special_length = special->length();
6768 if (!array->HasFastElements()) {
6769 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6771 FixedArray* fixed_array = FixedArray::cast(array->elements());
6772 if (fixed_array->length() < array_length) {
6773 array_length = fixed_array->length();
6776 if (array_length == 0) {
6777 return isolate->heap()->empty_string();
6778 } else if (array_length == 1) {
6779 Object* first = fixed_array->get(0);
6780 if (first->IsString()) return first;
6783 bool ascii = special->HasOnlyAsciiChars();
6785 for (int i = 0; i < array_length; i++) {
6787 Object* elt = fixed_array->get(i);
6789 // Smi encoding of position and length.
6790 int smi_value = Smi::cast(elt)->value();
6793 if (smi_value > 0) {
6794 // Position and length encoded in one smi.
6795 pos = StringBuilderSubstringPosition::decode(smi_value);
6796 len = StringBuilderSubstringLength::decode(smi_value);
6798 // Position and length encoded in two smis.
6800 // Get the position and check that it is a positive smi.
6802 if (i >= array_length) {
6803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6805 Object* next_smi = fixed_array->get(i);
6806 if (!next_smi->IsSmi()) {
6807 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6809 pos = Smi::cast(next_smi)->value();
6811 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6816 if (pos > special_length || len > special_length - pos) {
6817 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6820 } else if (elt->IsString()) {
6821 String* element = String::cast(elt);
6822 int element_length = element->length();
6823 increment = element_length;
6824 if (ascii && !element->HasOnlyAsciiChars()) {
6828 ASSERT(!elt->IsTheHole());
6829 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6831 if (increment > String::kMaxLength - position) {
6832 isolate->context()->mark_out_of_memory();
6833 return Failure::OutOfMemoryException();
6835 position += increment;
6838 int length = position;
6842 { MaybeObject* maybe_object =
6843 isolate->heap()->AllocateRawAsciiString(length);
6844 if (!maybe_object->ToObject(&object)) return maybe_object;
6846 SeqAsciiString* answer = SeqAsciiString::cast(object);
6847 StringBuilderConcatHelper(special,
6853 { MaybeObject* maybe_object =
6854 isolate->heap()->AllocateRawTwoByteString(length);
6855 if (!maybe_object->ToObject(&object)) return maybe_object;
6857 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6858 StringBuilderConcatHelper(special,
6867 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
6868 NoHandleAllocation ha;
6869 ASSERT(args.length() == 3);
6870 CONVERT_ARG_CHECKED(JSArray, array, 0);
6871 if (!args[1]->IsSmi()) {
6872 isolate->context()->mark_out_of_memory();
6873 return Failure::OutOfMemoryException();
6875 int array_length = args.smi_at(1);
6876 CONVERT_ARG_CHECKED(String, separator, 2);
6878 if (!array->HasFastElements()) {
6879 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6881 FixedArray* fixed_array = FixedArray::cast(array->elements());
6882 if (fixed_array->length() < array_length) {
6883 array_length = fixed_array->length();
6886 if (array_length == 0) {
6887 return isolate->heap()->empty_string();
6888 } else if (array_length == 1) {
6889 Object* first = fixed_array->get(0);
6890 if (first->IsString()) return first;
6893 int separator_length = separator->length();
6894 int max_nof_separators =
6895 (String::kMaxLength + separator_length - 1) / separator_length;
6896 if (max_nof_separators < (array_length - 1)) {
6897 isolate->context()->mark_out_of_memory();
6898 return Failure::OutOfMemoryException();
6900 int length = (array_length - 1) * separator_length;
6901 for (int i = 0; i < array_length; i++) {
6902 Object* element_obj = fixed_array->get(i);
6903 if (!element_obj->IsString()) {
6904 // TODO(1161): handle this case.
6905 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
6907 String* element = String::cast(element_obj);
6908 int increment = element->length();
6909 if (increment > String::kMaxLength - length) {
6910 isolate->context()->mark_out_of_memory();
6911 return Failure::OutOfMemoryException();
6913 length += increment;
6917 { MaybeObject* maybe_object =
6918 isolate->heap()->AllocateRawTwoByteString(length);
6919 if (!maybe_object->ToObject(&object)) return maybe_object;
6921 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6923 uc16* sink = answer->GetChars();
6925 uc16* end = sink + length;
6928 String* first = String::cast(fixed_array->get(0));
6929 int first_length = first->length();
6930 String::WriteToFlat(first, sink, 0, first_length);
6931 sink += first_length;
6933 for (int i = 1; i < array_length; i++) {
6934 ASSERT(sink + separator_length <= end);
6935 String::WriteToFlat(separator, sink, 0, separator_length);
6936 sink += separator_length;
6938 String* element = String::cast(fixed_array->get(i));
6939 int element_length = element->length();
6940 ASSERT(sink + element_length <= end);
6941 String::WriteToFlat(element, sink, 0, element_length);
6942 sink += element_length;
6944 ASSERT(sink == end);
6946 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6950 template <typename Char>
6951 static void JoinSparseArrayWithSeparator(FixedArray* elements,
6952 int elements_length,
6953 uint32_t array_length,
6955 Vector<Char> buffer) {
6956 int previous_separator_position = 0;
6957 int separator_length = separator->length();
6959 for (int i = 0; i < elements_length; i += 2) {
6960 int position = NumberToInt32(elements->get(i));
6961 String* string = String::cast(elements->get(i + 1));
6962 int string_length = string->length();
6963 if (string->length() > 0) {
6964 while (previous_separator_position < position) {
6965 String::WriteToFlat<Char>(separator, &buffer[cursor],
6966 0, separator_length);
6967 cursor += separator_length;
6968 previous_separator_position++;
6970 String::WriteToFlat<Char>(string, &buffer[cursor],
6972 cursor += string->length();
6975 if (separator_length > 0) {
6976 // Array length must be representable as a signed 32-bit number,
6977 // otherwise the total string length would have been too large.
6978 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6979 int last_array_index = static_cast<int>(array_length - 1);
6980 while (previous_separator_position < last_array_index) {
6981 String::WriteToFlat<Char>(separator, &buffer[cursor],
6982 0, separator_length);
6983 cursor += separator_length;
6984 previous_separator_position++;
6987 ASSERT(cursor <= buffer.length());
6991 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6992 NoHandleAllocation ha;
6993 ASSERT(args.length() == 3);
6994 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
6995 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6996 elements_array->HasFastSmiOnlyElements());
6997 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6998 CONVERT_ARG_CHECKED(String, separator, 2);
6999 // elements_array is fast-mode JSarray of alternating positions
7000 // (increasing order) and strings.
7001 // array_length is length of original array (used to add separators);
7002 // separator is string to put between elements. Assumed to be non-empty.
7004 // Find total length of join result.
7005 int string_length = 0;
7006 bool is_ascii = separator->IsAsciiRepresentation();
7007 int max_string_length;
7009 max_string_length = SeqAsciiString::kMaxLength;
7011 max_string_length = SeqTwoByteString::kMaxLength;
7013 bool overflow = false;
7014 CONVERT_NUMBER_CHECKED(int, elements_length,
7015 Int32, elements_array->length());
7016 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7017 FixedArray* elements = FixedArray::cast(elements_array->elements());
7018 for (int i = 0; i < elements_length; i += 2) {
7019 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7020 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7021 String* string = String::cast(elements->get(i + 1));
7022 int length = string->length();
7023 if (is_ascii && !string->IsAsciiRepresentation()) {
7025 max_string_length = SeqTwoByteString::kMaxLength;
7027 if (length > max_string_length ||
7028 max_string_length - length < string_length) {
7032 string_length += length;
7034 int separator_length = separator->length();
7035 if (!overflow && separator_length > 0) {
7036 if (array_length <= 0x7fffffffu) {
7037 int separator_count = static_cast<int>(array_length) - 1;
7038 int remaining_length = max_string_length - string_length;
7039 if ((remaining_length / separator_length) >= separator_count) {
7040 string_length += separator_length * (array_length - 1);
7042 // Not room for the separators within the maximal string length.
7046 // Nonempty separator and at least 2^31-1 separators necessary
7047 // means that the string is too large to create.
7048 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7053 // Throw OutOfMemory exception for creating too large a string.
7054 V8::FatalProcessOutOfMemory("Array join result too large.");
7058 MaybeObject* result_allocation =
7059 isolate->heap()->AllocateRawAsciiString(string_length);
7060 if (result_allocation->IsFailure()) return result_allocation;
7061 SeqAsciiString* result_string =
7062 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7063 JoinSparseArrayWithSeparator<char>(elements,
7067 Vector<char>(result_string->GetChars(),
7069 return result_string;
7071 MaybeObject* result_allocation =
7072 isolate->heap()->AllocateRawTwoByteString(string_length);
7073 if (result_allocation->IsFailure()) return result_allocation;
7074 SeqTwoByteString* result_string =
7075 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7076 JoinSparseArrayWithSeparator<uc16>(elements,
7080 Vector<uc16>(result_string->GetChars(),
7082 return result_string;
7087 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
7088 NoHandleAllocation ha;
7089 ASSERT(args.length() == 2);
7091 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7092 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7093 return isolate->heap()->NumberFromInt32(x | y);
7097 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
7098 NoHandleAllocation ha;
7099 ASSERT(args.length() == 2);
7101 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7102 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7103 return isolate->heap()->NumberFromInt32(x & y);
7107 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
7108 NoHandleAllocation ha;
7109 ASSERT(args.length() == 2);
7111 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7112 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7113 return isolate->heap()->NumberFromInt32(x ^ y);
7117 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
7118 NoHandleAllocation ha;
7119 ASSERT(args.length() == 1);
7121 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7122 return isolate->heap()->NumberFromInt32(~x);
7126 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
7127 NoHandleAllocation ha;
7128 ASSERT(args.length() == 2);
7130 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7131 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7132 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
7136 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
7137 NoHandleAllocation ha;
7138 ASSERT(args.length() == 2);
7140 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7141 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7142 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
7146 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
7147 NoHandleAllocation ha;
7148 ASSERT(args.length() == 2);
7150 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7151 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
7152 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
7156 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
7157 NoHandleAllocation ha;
7158 ASSERT(args.length() == 2);
7160 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7161 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7162 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7163 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7164 if (x == y) return Smi::FromInt(EQUAL);
7166 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7167 result = Smi::FromInt(EQUAL);
7169 result = Smi::FromInt(NOT_EQUAL);
7175 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
7176 NoHandleAllocation ha;
7177 ASSERT(args.length() == 2);
7179 CONVERT_ARG_CHECKED(String, x, 0);
7180 CONVERT_ARG_CHECKED(String, y, 1);
7182 bool not_equal = !x->Equals(y);
7183 // This is slightly convoluted because the value that signifies
7184 // equality is 0 and inequality is 1 so we have to negate the result
7185 // from String::Equals.
7186 ASSERT(not_equal == 0 || not_equal == 1);
7187 STATIC_CHECK(EQUAL == 0);
7188 STATIC_CHECK(NOT_EQUAL == 1);
7189 return Smi::FromInt(not_equal);
7193 RUNTIME_FUNCTION(MaybeObject*, Runtime_UserObjectEquals) {
7194 NoHandleAllocation ha;
7195 ASSERT(args.length() == 2);
7197 CONVERT_ARG_CHECKED(JSObject, lhs, 1);
7198 CONVERT_ARG_CHECKED(JSObject, rhs, 0);
7202 v8::UserObjectComparisonCallback callback = isolate->UserObjectComparisonCallback();
7204 HandleScope scope(isolate);
7205 Handle<JSObject> lhs_handle(lhs);
7206 Handle<JSObject> rhs_handle(rhs);
7207 result = callback(v8::Utils::ToLocal(lhs_handle), v8::Utils::ToLocal(rhs_handle));
7209 result = (lhs == rhs);
7212 return Smi::FromInt(result?0:1);
7216 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
7217 NoHandleAllocation ha;
7218 ASSERT(args.length() == 3);
7220 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7221 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7222 if (isnan(x) || isnan(y)) return args[2];
7223 if (x == y) return Smi::FromInt(EQUAL);
7224 if (isless(x, y)) return Smi::FromInt(LESS);
7225 return Smi::FromInt(GREATER);
7229 // Compare two Smis as if they were converted to strings and then
7230 // compared lexicographically.
7231 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
7232 NoHandleAllocation ha;
7233 ASSERT(args.length() == 2);
7234 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7235 CONVERT_SMI_ARG_CHECKED(y_value, 1);
7237 // If the integers are equal so are the string representations.
7238 if (x_value == y_value) return Smi::FromInt(EQUAL);
7240 // If one of the integers is zero the normal integer order is the
7241 // same as the lexicographic order of the string representations.
7242 if (x_value == 0 || y_value == 0)
7243 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
7245 // If only one of the integers is negative the negative number is
7246 // smallest because the char code of '-' is less than the char code
7247 // of any digit. Otherwise, we make both values positive.
7249 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7250 // architectures using 32-bit Smis.
7251 uint32_t x_scaled = x_value;
7252 uint32_t y_scaled = y_value;
7253 if (x_value < 0 || y_value < 0) {
7254 if (y_value >= 0) return Smi::FromInt(LESS);
7255 if (x_value >= 0) return Smi::FromInt(GREATER);
7256 x_scaled = -x_value;
7257 y_scaled = -y_value;
7260 static const uint32_t kPowersOf10[] = {
7261 1, 10, 100, 1000, 10*1000, 100*1000,
7262 1000*1000, 10*1000*1000, 100*1000*1000,
7266 // If the integers have the same number of decimal digits they can be
7267 // compared directly as the numeric order is the same as the
7268 // lexicographic order. If one integer has fewer digits, it is scaled
7269 // by some power of 10 to have the same number of digits as the longer
7270 // integer. If the scaled integers are equal it means the shorter
7271 // integer comes first in the lexicographic order.
7273 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7274 int x_log2 = IntegerLog2(x_scaled);
7275 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7276 x_log10 -= x_scaled < kPowersOf10[x_log10];
7278 int y_log2 = IntegerLog2(y_scaled);
7279 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7280 y_log10 -= y_scaled < kPowersOf10[y_log10];
7284 if (x_log10 < y_log10) {
7285 // X has fewer digits. We would like to simply scale up X but that
7286 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7287 // be scaled up to 9_000_000_000. So we scale up by the next
7288 // smallest power and scale down Y to drop one digit. It is OK to
7289 // drop one digit from the longer integer since the final digit is
7290 // past the length of the shorter integer.
7291 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7294 } else if (y_log10 < x_log10) {
7295 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7300 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7301 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7302 return Smi::FromInt(tie);
7306 static Object* StringInputBufferCompare(RuntimeState* state,
7309 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7310 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
7313 while (bufx.has_more() && bufy.has_more()) {
7314 int d = bufx.GetNext() - bufy.GetNext();
7315 if (d < 0) return Smi::FromInt(LESS);
7316 else if (d > 0) return Smi::FromInt(GREATER);
7319 // x is (non-trivial) prefix of y:
7320 if (bufy.has_more()) return Smi::FromInt(LESS);
7321 // y is prefix of x:
7322 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7326 static Object* FlatStringCompare(String* x, String* y) {
7327 ASSERT(x->IsFlat());
7328 ASSERT(y->IsFlat());
7329 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7330 int prefix_length = x->length();
7331 if (y->length() < prefix_length) {
7332 prefix_length = y->length();
7333 equal_prefix_result = Smi::FromInt(GREATER);
7334 } else if (y->length() > prefix_length) {
7335 equal_prefix_result = Smi::FromInt(LESS);
7338 String::FlatContent x_content = x->GetFlatContent();
7339 String::FlatContent y_content = y->GetFlatContent();
7340 if (x_content.IsAscii()) {
7341 Vector<const char> x_chars = x_content.ToAsciiVector();
7342 if (y_content.IsAscii()) {
7343 Vector<const char> y_chars = y_content.ToAsciiVector();
7344 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7346 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7347 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7350 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7351 if (y_content.IsAscii()) {
7352 Vector<const char> y_chars = y_content.ToAsciiVector();
7353 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7355 Vector<const uc16> y_chars = y_content.ToUC16Vector();
7356 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7361 result = equal_prefix_result;
7363 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7366 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
7371 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
7372 NoHandleAllocation ha;
7373 ASSERT(args.length() == 2);
7375 CONVERT_ARG_CHECKED(String, x, 0);
7376 CONVERT_ARG_CHECKED(String, y, 1);
7378 isolate->counters()->string_compare_runtime()->Increment();
7380 // A few fast case tests before we flatten.
7381 if (x == y) return Smi::FromInt(EQUAL);
7382 if (y->length() == 0) {
7383 if (x->length() == 0) return Smi::FromInt(EQUAL);
7384 return Smi::FromInt(GREATER);
7385 } else if (x->length() == 0) {
7386 return Smi::FromInt(LESS);
7389 int d = x->Get(0) - y->Get(0);
7390 if (d < 0) return Smi::FromInt(LESS);
7391 else if (d > 0) return Smi::FromInt(GREATER);
7394 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
7395 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7397 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
7398 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7401 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
7402 : StringInputBufferCompare(isolate->runtime_state(), x, y);
7406 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
7407 NoHandleAllocation ha;
7408 ASSERT(args.length() == 1);
7409 isolate->counters()->math_acos()->Increment();
7411 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7412 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
7416 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
7417 NoHandleAllocation ha;
7418 ASSERT(args.length() == 1);
7419 isolate->counters()->math_asin()->Increment();
7421 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7422 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
7426 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
7427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
7429 isolate->counters()->math_atan()->Increment();
7431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7432 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
7436 static const double kPiDividedBy4 = 0.78539816339744830962;
7439 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
7440 NoHandleAllocation ha;
7441 ASSERT(args.length() == 2);
7442 isolate->counters()->math_atan2()->Increment();
7444 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7445 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7447 if (isinf(x) && isinf(y)) {
7448 // Make sure that the result in case of two infinite arguments
7449 // is a multiple of Pi / 4. The sign of the result is determined
7450 // by the first argument (x) and the sign of the second argument
7451 // determines the multiplier: one or three.
7452 int multiplier = (x < 0) ? -1 : 1;
7453 if (y < 0) multiplier *= 3;
7454 result = multiplier * kPiDividedBy4;
7456 result = atan2(x, y);
7458 return isolate->heap()->AllocateHeapNumber(result);
7462 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
7463 NoHandleAllocation ha;
7464 ASSERT(args.length() == 1);
7465 isolate->counters()->math_ceil()->Increment();
7467 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7468 return isolate->heap()->NumberFromDouble(ceiling(x));
7472 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
7473 NoHandleAllocation ha;
7474 ASSERT(args.length() == 1);
7475 isolate->counters()->math_cos()->Increment();
7477 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7478 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
7482 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
7483 NoHandleAllocation ha;
7484 ASSERT(args.length() == 1);
7485 isolate->counters()->math_exp()->Increment();
7487 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7488 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
7492 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
7493 NoHandleAllocation ha;
7494 ASSERT(args.length() == 1);
7495 isolate->counters()->math_floor()->Increment();
7497 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7498 return isolate->heap()->NumberFromDouble(floor(x));
7502 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
7503 NoHandleAllocation ha;
7504 ASSERT(args.length() == 1);
7505 isolate->counters()->math_log()->Increment();
7507 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7508 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
7511 // Slow version of Math.pow. We check for fast paths for special cases.
7512 // Used if SSE2/VFP3 is not available.
7513 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
7514 NoHandleAllocation ha;
7515 ASSERT(args.length() == 2);
7516 isolate->counters()->math_pow()->Increment();
7518 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7520 // If the second argument is a smi, it is much faster to call the
7521 // custom powi() function than the generic pow().
7522 if (args[1]->IsSmi()) {
7523 int y = args.smi_at(1);
7524 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
7527 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7528 int y_int = static_cast<int>(y);
7531 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7532 } else if (y == 0.5) {
7533 result = (isinf(x)) ? V8_INFINITY
7534 : fast_sqrt(x + 0.0); // Convert -0 to +0.
7535 } else if (y == -0.5) {
7536 result = (isinf(x)) ? 0
7537 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
7539 result = power_double_double(x, y);
7541 if (isnan(result)) return isolate->heap()->nan_value();
7542 return isolate->heap()->AllocateHeapNumber(result);
7545 // Fast version of Math.pow if we know that y is not an integer and y is not
7546 // -0.5 or 0.5. Used as slow case from full codegen.
7547 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
7548 NoHandleAllocation ha;
7549 ASSERT(args.length() == 2);
7550 isolate->counters()->math_pow()->Increment();
7552 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7553 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
7555 return Smi::FromInt(1);
7557 double result = power_double_double(x, y);
7558 if (isnan(result)) return isolate->heap()->nan_value();
7559 return isolate->heap()->AllocateHeapNumber(result);
7564 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
7565 NoHandleAllocation ha;
7566 ASSERT(args.length() == 1);
7567 isolate->counters()->math_round()->Increment();
7569 if (!args[0]->IsHeapNumber()) {
7570 // Must be smi. Return the argument unchanged for all the other types
7571 // to make fuzz-natives test happy.
7575 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7577 double value = number->value();
7578 int exponent = number->get_exponent();
7579 int sign = number->get_sign();
7581 if (exponent < -1) {
7582 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7583 if (sign) return isolate->heap()->minus_zero_value();
7584 return Smi::FromInt(0);
7587 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7588 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7589 // argument holds for 32-bit smis).
7590 if (!sign && exponent < kSmiValueSize - 2) {
7591 return Smi::FromInt(static_cast<int>(value + 0.5));
7594 // If the magnitude is big enough, there's no place for fraction part. If we
7595 // try to add 0.5 to this number, 1.0 will be added instead.
7596 if (exponent >= 52) {
7600 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
7602 // Do not call NumberFromDouble() to avoid extra checks.
7603 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
7607 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
7608 NoHandleAllocation ha;
7609 ASSERT(args.length() == 1);
7610 isolate->counters()->math_sin()->Increment();
7612 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7613 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
7617 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
7618 NoHandleAllocation ha;
7619 ASSERT(args.length() == 1);
7620 isolate->counters()->math_sqrt()->Increment();
7622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7623 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
7627 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
7628 NoHandleAllocation ha;
7629 ASSERT(args.length() == 1);
7630 isolate->counters()->math_tan()->Increment();
7632 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7633 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
7637 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
7638 NoHandleAllocation ha;
7639 ASSERT(args.length() == 2);
7641 CONVERT_SMI_ARG_CHECKED(year, 0);
7642 CONVERT_SMI_ARG_CHECKED(month, 1);
7644 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
7648 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7649 HandleScope scope(isolate);
7650 ASSERT(args.length() == 3);
7652 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7653 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7654 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
7656 DateCache* date_cache = isolate->date_cache();
7658 Object* value = NULL;
7659 bool is_value_nan = false;
7661 value = isolate->heap()->nan_value();
7662 is_value_nan = true;
7663 } else if (!is_utc &&
7664 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7665 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7666 value = isolate->heap()->nan_value();
7667 is_value_nan = true;
7669 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7670 if (time < -DateCache::kMaxTimeInMs ||
7671 time > DateCache::kMaxTimeInMs) {
7672 value = isolate->heap()->nan_value();
7673 is_value_nan = true;
7675 MaybeObject* maybe_result =
7676 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7677 if (!maybe_result->ToObject(&value)) return maybe_result;
7680 date->SetValue(value, is_value_nan);
7685 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
7686 HandleScope scope(isolate);
7687 ASSERT(args.length() == 3);
7689 Handle<JSFunction> callee = args.at<JSFunction>(0);
7690 Object** parameters = reinterpret_cast<Object**>(args[1]);
7691 const int argument_count = Smi::cast(args[2])->value();
7693 Handle<JSObject> result =
7694 isolate->factory()->NewArgumentsObject(callee, argument_count);
7695 // Allocate the elements if needed.
7696 int parameter_count = callee->shared()->formal_parameter_count();
7697 if (argument_count > 0) {
7698 if (parameter_count > 0) {
7699 int mapped_count = Min(argument_count, parameter_count);
7700 Handle<FixedArray> parameter_map =
7701 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7702 parameter_map->set_map(
7703 isolate->heap()->non_strict_arguments_elements_map());
7705 Handle<Map> old_map(result->map());
7706 Handle<Map> new_map =
7707 isolate->factory()->CopyMapDropTransitions(old_map);
7708 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
7710 result->set_map(*new_map);
7711 result->set_elements(*parameter_map);
7713 // Store the context and the arguments array at the beginning of the
7715 Handle<Context> context(isolate->context());
7716 Handle<FixedArray> arguments =
7717 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7718 parameter_map->set(0, *context);
7719 parameter_map->set(1, *arguments);
7721 // Loop over the actual parameters backwards.
7722 int index = argument_count - 1;
7723 while (index >= mapped_count) {
7724 // These go directly in the arguments array and have no
7725 // corresponding slot in the parameter map.
7726 arguments->set(index, *(parameters - index - 1));
7730 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
7731 while (index >= 0) {
7732 // Detect duplicate names to the right in the parameter list.
7733 Handle<String> name(scope_info->ParameterName(index));
7734 int context_local_count = scope_info->ContextLocalCount();
7735 bool duplicate = false;
7736 for (int j = index + 1; j < parameter_count; ++j) {
7737 if (scope_info->ParameterName(j) == *name) {
7744 // This goes directly in the arguments array with a hole in the
7746 arguments->set(index, *(parameters - index - 1));
7747 parameter_map->set_the_hole(index + 2);
7749 // The context index goes in the parameter map with a hole in the
7751 int context_index = -1;
7752 for (int j = 0; j < context_local_count; ++j) {
7753 if (scope_info->ContextLocalName(j) == *name) {
7758 ASSERT(context_index >= 0);
7759 arguments->set_the_hole(index);
7760 parameter_map->set(index + 2, Smi::FromInt(
7761 Context::MIN_CONTEXT_SLOTS + context_index));
7767 // If there is no aliasing, the arguments object elements are not
7768 // special in any way.
7769 Handle<FixedArray> elements =
7770 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7771 result->set_elements(*elements);
7772 for (int i = 0; i < argument_count; ++i) {
7773 elements->set(i, *(parameters - i - 1));
7781 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
7782 NoHandleAllocation ha;
7783 ASSERT(args.length() == 3);
7785 JSFunction* callee = JSFunction::cast(args[0]);
7786 Object** parameters = reinterpret_cast<Object**>(args[1]);
7787 const int length = args.smi_at(2);
7790 { MaybeObject* maybe_result =
7791 isolate->heap()->AllocateArgumentsObject(callee, length);
7792 if (!maybe_result->ToObject(&result)) return maybe_result;
7794 // Allocate the elements if needed.
7796 // Allocate the fixed array.
7798 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
7799 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7802 AssertNoAllocation no_gc;
7803 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
7804 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
7805 array->set_length(length);
7807 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
7808 for (int i = 0; i < length; i++) {
7809 array->set(i, *--parameters, mode);
7811 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
7817 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
7818 HandleScope scope(isolate);
7819 ASSERT(args.length() == 3);
7820 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7821 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7822 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
7824 // The caller ensures that we pretenure closures that are assigned
7825 // directly to properties.
7826 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
7827 Handle<JSFunction> result =
7828 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7835 // Find the arguments of the JavaScript function invocation that called
7836 // into C++ code. Collect these in a newly allocated array of handles (possibly
7837 // prefixed by a number of empty handles).
7838 static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7841 // Find frame containing arguments passed to the caller.
7842 JavaScriptFrameIterator it;
7843 JavaScriptFrame* frame = it.frame();
7844 List<JSFunction*> functions(2);
7845 frame->GetFunctions(&functions);
7846 if (functions.length() > 1) {
7847 int inlined_jsframe_index = functions.length() - 1;
7848 JSFunction* inlined_function = functions[inlined_jsframe_index];
7849 Vector<SlotRef> args_slots =
7850 SlotRef::ComputeSlotMappingForArguments(
7852 inlined_jsframe_index,
7853 inlined_function->shared()->formal_parameter_count());
7855 int args_count = args_slots.length();
7857 *total_argc = prefix_argc + args_count;
7858 SmartArrayPointer<Handle<Object> > param_data(
7859 NewArray<Handle<Object> >(*total_argc));
7860 for (int i = 0; i < args_count; i++) {
7861 Handle<Object> val = args_slots[i].GetValue();
7862 param_data[prefix_argc + i] = val;
7865 args_slots.Dispose();
7869 it.AdvanceToArgumentsFrame();
7871 int args_count = frame->ComputeParametersCount();
7873 *total_argc = prefix_argc + args_count;
7874 SmartArrayPointer<Handle<Object> > param_data(
7875 NewArray<Handle<Object> >(*total_argc));
7876 for (int i = 0; i < args_count; i++) {
7877 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7878 param_data[prefix_argc + i] = val;
7885 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7886 HandleScope scope(isolate);
7887 ASSERT(args.length() == 4);
7888 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
7889 RUNTIME_ASSERT(args[3]->IsNumber());
7890 Handle<Object> bindee = args.at<Object>(1);
7892 // TODO(lrn): Create bound function in C++ code from premade shared info.
7893 bound_function->shared()->set_bound(true);
7894 // Get all arguments of calling function (Function.prototype.bind).
7896 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7897 // Don't count the this-arg.
7899 ASSERT(*arguments[0] == args[2]);
7902 ASSERT(args[2]->IsUndefined());
7904 // Initialize array of bindings (function, this, and any existing arguments
7905 // if the function was already bound).
7906 Handle<FixedArray> new_bindings;
7908 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7909 Handle<FixedArray> old_bindings(
7910 JSFunction::cast(*bindee)->function_bindings());
7912 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7913 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7915 for (int n = old_bindings->length(); i < n; i++) {
7916 new_bindings->set(i, old_bindings->get(i));
7919 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7920 new_bindings = isolate->factory()->NewFixedArray(array_size);
7921 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7922 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7925 // Copy arguments, skipping the first which is "this_arg".
7926 for (int j = 0; j < argc; j++, i++) {
7927 new_bindings->set(i, *arguments[j + 1]);
7929 new_bindings->set_map_no_write_barrier(
7930 isolate->heap()->fixed_cow_array_map());
7931 bound_function->set_function_bindings(*new_bindings);
7934 Handle<String> length_symbol = isolate->factory()->length_symbol();
7935 Handle<Object> new_length(args.at<Object>(3));
7936 PropertyAttributes attr =
7937 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7938 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7939 return *bound_function;
7943 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7944 HandleScope handles(isolate);
7945 ASSERT(args.length() == 1);
7946 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
7947 if (callable->IsJSFunction()) {
7948 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7949 if (function->shared()->bound()) {
7950 Handle<FixedArray> bindings(function->function_bindings());
7951 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7952 return *isolate->factory()->NewJSArrayWithElements(bindings);
7955 return isolate->heap()->undefined_value();
7959 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
7960 HandleScope scope(isolate);
7961 ASSERT(args.length() == 1);
7962 // First argument is a function to use as a constructor.
7963 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
7964 RUNTIME_ASSERT(function->shared()->bound());
7966 // The argument is a bound function. Extract its bound arguments
7968 Handle<FixedArray> bound_args =
7969 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7970 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7971 Handle<Object> bound_function(
7972 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7973 ASSERT(!bound_function->IsJSFunction() ||
7974 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
7977 SmartArrayPointer<Handle<Object> > param_data =
7978 GetCallerArguments(bound_argc, &total_argc);
7979 for (int i = 0; i < bound_argc; i++) {
7980 param_data[i] = Handle<Object>(bound_args->get(
7981 JSFunction::kBoundArgumentsStartIndex + i));
7984 if (!bound_function->IsJSFunction()) {
7985 bool exception_thrown;
7986 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7988 if (exception_thrown) return Failure::Exception();
7990 ASSERT(bound_function->IsJSFunction());
7992 bool exception = false;
7993 Handle<Object> result =
7994 Execution::New(Handle<JSFunction>::cast(bound_function),
7995 total_argc, *param_data, &exception);
7997 return Failure::Exception();
7999 ASSERT(!result.is_null());
8004 static void TrySettingInlineConstructStub(Isolate* isolate,
8005 Handle<JSFunction> function) {
8006 Handle<Object> prototype = isolate->factory()->null_value();
8007 if (function->has_instance_prototype()) {
8008 prototype = Handle<Object>(function->instance_prototype(), isolate);
8010 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
8011 ConstructStubCompiler compiler(isolate);
8012 Handle<Code> code = compiler.CompileConstructStub(function);
8013 function->shared()->set_construct_stub(*code);
8018 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
8019 HandleScope scope(isolate);
8020 ASSERT(args.length() == 1);
8022 Handle<Object> constructor = args.at<Object>(0);
8024 // If the constructor isn't a proper function we throw a type error.
8025 if (!constructor->IsJSFunction()) {
8026 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8027 Handle<Object> type_error =
8028 isolate->factory()->NewTypeError("not_constructor", arguments);
8029 return isolate->Throw(*type_error);
8032 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
8034 // If function should not have prototype, construction is not allowed. In this
8035 // case generated code bailouts here, since function has no initial_map.
8036 if (!function->should_have_prototype() && !function->shared()->bound()) {
8037 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8038 Handle<Object> type_error =
8039 isolate->factory()->NewTypeError("not_constructor", arguments);
8040 return isolate->Throw(*type_error);
8043 #ifdef ENABLE_DEBUGGER_SUPPORT
8044 Debug* debug = isolate->debug();
8045 // Handle stepping into constructors if step into is active.
8046 if (debug->StepInActive()) {
8047 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
8051 if (function->has_initial_map()) {
8052 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
8053 // The 'Function' function ignores the receiver object when
8054 // called using 'new' and creates a new JSFunction object that
8055 // is returned. The receiver object is only used for error
8056 // reporting if an error occurs when constructing the new
8057 // JSFunction. FACTORY->NewJSObject() should not be used to
8058 // allocate JSFunctions since it does not properly initialize
8059 // the shared part of the function. Since the receiver is
8060 // ignored anyway, we use the global object as the receiver
8061 // instead of a new JSFunction object. This way, errors are
8062 // reported the same way whether or not 'Function' is called
8064 return isolate->context()->global();
8068 // The function should be compiled for the optimization hints to be
8069 // available. We cannot use EnsureCompiled because that forces a
8070 // compilation through the shared function info which makes it
8071 // impossible for us to optimize.
8072 if (!function->is_compiled()) {
8073 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8076 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
8077 if (!function->has_initial_map() &&
8078 shared->IsInobjectSlackTrackingInProgress()) {
8079 // The tracking is already in progress for another function. We can only
8080 // track one initial_map at a time, so we force the completion before the
8081 // function is called as a constructor for the first time.
8082 shared->CompleteInobjectSlackTracking();
8085 bool first_allocation = !shared->live_objects_may_exist();
8086 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8087 RETURN_IF_EMPTY_HANDLE(isolate, result);
8088 // Delay setting the stub if inobject slack tracking is in progress.
8089 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
8090 TrySettingInlineConstructStub(isolate, function);
8093 isolate->counters()->constructed_objects()->Increment();
8094 isolate->counters()->constructed_objects_runtime()->Increment();
8100 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
8101 HandleScope scope(isolate);
8102 ASSERT(args.length() == 1);
8104 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8105 function->shared()->CompleteInobjectSlackTracking();
8106 TrySettingInlineConstructStub(isolate, function);
8108 return isolate->heap()->undefined_value();
8112 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
8113 HandleScope scope(isolate);
8114 ASSERT(args.length() == 1);
8116 Handle<JSFunction> function = args.at<JSFunction>(0);
8118 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
8120 function->PrintName();
8125 // Compile the target function.
8126 ASSERT(!function->is_compiled());
8127 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
8128 return Failure::Exception();
8131 // All done. Return the compiled code.
8132 ASSERT(function->is_compiled());
8133 return function->code();
8137 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
8138 HandleScope scope(isolate);
8139 ASSERT(args.length() == 1);
8140 Handle<JSFunction> function = args.at<JSFunction>(0);
8142 // If the function is not compiled ignore the lazy
8143 // recompilation. This can happen if the debugger is activated and
8144 // the function is returned to the not compiled state.
8145 if (!function->shared()->is_compiled()) {
8146 function->ReplaceCode(function->shared()->code());
8147 return function->code();
8150 // If the function is not optimizable or debugger is active continue using the
8151 // code from the full compiler.
8152 if (!function->shared()->code()->optimizable() ||
8153 isolate->DebuggerHasBreakPoints()) {
8154 if (FLAG_trace_opt) {
8155 PrintF("[failed to optimize ");
8156 function->PrintName();
8157 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8158 function->shared()->code()->optimizable() ? "T" : "F",
8159 isolate->DebuggerHasBreakPoints() ? "T" : "F");
8161 function->ReplaceCode(function->shared()->code());
8162 return function->code();
8164 function->shared()->code()->set_profiler_ticks(0);
8165 if (JSFunction::CompileOptimized(function,
8168 return function->code();
8170 if (FLAG_trace_opt) {
8171 PrintF("[failed to optimize ");
8172 function->PrintName();
8173 PrintF(": optimized compilation failed]\n");
8175 function->ReplaceCode(function->shared()->code());
8176 return function->code();
8180 class ActivationsFinder : public ThreadVisitor {
8182 explicit ActivationsFinder(JSFunction* function)
8183 : function_(function), has_activations_(false) {}
8185 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8186 if (has_activations_) return;
8188 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8189 JavaScriptFrame* frame = it.frame();
8190 if (frame->is_optimized() && frame->function() == function_) {
8191 has_activations_ = true;
8197 bool has_activations() { return has_activations_; }
8200 JSFunction* function_;
8201 bool has_activations_;
8205 static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8206 JavaScriptFrame* frame) {
8207 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8208 Handle<Object> arguments;
8209 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
8210 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
8211 if (arguments.is_null()) {
8212 // FunctionGetArguments can't throw an exception, so cast away the
8213 // doubt with an assert.
8214 arguments = Handle<Object>(
8215 Accessors::FunctionGetArguments(*function,
8216 NULL)->ToObjectUnchecked());
8217 ASSERT(*arguments != isolate->heap()->null_value());
8218 ASSERT(*arguments != isolate->heap()->undefined_value());
8220 frame->SetExpression(i, *arguments);
8221 if (FLAG_trace_deopt) {
8222 PrintF("Materializing arguments object for frame %p - %p: %p ",
8223 reinterpret_cast<void*>(frame->sp()),
8224 reinterpret_cast<void*>(frame->fp()),
8225 reinterpret_cast<void*>(*arguments));
8226 arguments->ShortPrint();
8234 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8235 HandleScope scope(isolate);
8236 ASSERT(args.length() == 1);
8237 RUNTIME_ASSERT(args[0]->IsSmi());
8238 Deoptimizer::BailoutType type =
8239 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8240 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8241 ASSERT(isolate->heap()->IsAllocationAllowed());
8242 int jsframes = deoptimizer->jsframe_count();
8244 deoptimizer->MaterializeHeapNumbers();
8247 JavaScriptFrameIterator it(isolate);
8248 for (int i = 0; i < jsframes - 1; i++) {
8249 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8253 JavaScriptFrame* frame = it.frame();
8254 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8255 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8256 MaterializeArgumentsObjectInFrame(isolate, frame);
8258 if (type == Deoptimizer::EAGER) {
8259 RUNTIME_ASSERT(function->IsOptimized());
8262 // Avoid doing too much work when running with --always-opt and keep
8263 // the optimized code around.
8264 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
8265 return isolate->heap()->undefined_value();
8268 // Find other optimized activations of the function.
8269 bool has_other_activations = false;
8270 while (!it.done()) {
8271 JavaScriptFrame* frame = it.frame();
8272 if (frame->is_optimized() && frame->function() == *function) {
8273 has_other_activations = true;
8279 if (!has_other_activations) {
8280 ActivationsFinder activations_finder(*function);
8281 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8282 has_other_activations = activations_finder.has_activations();
8285 if (!has_other_activations) {
8286 if (FLAG_trace_deopt) {
8287 PrintF("[removing optimized code for: ");
8288 function->PrintName();
8291 function->ReplaceCode(function->shared()->code());
8293 Deoptimizer::DeoptimizeFunction(*function);
8295 return isolate->heap()->undefined_value();
8299 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
8300 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8302 return isolate->heap()->undefined_value();
8306 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
8307 HandleScope scope(isolate);
8308 ASSERT(args.length() == 1);
8309 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8310 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
8312 Deoptimizer::DeoptimizeFunction(*function);
8314 return isolate->heap()->undefined_value();
8318 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) {
8319 HandleScope scope(isolate);
8320 ASSERT(args.length() == 1);
8321 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8322 Code* unoptimized = function->shared()->code();
8323 if (unoptimized->kind() == Code::FUNCTION) {
8324 unoptimized->ClearInlineCaches();
8325 unoptimized->ClearTypeFeedbackCells(isolate->heap());
8327 return isolate->heap()->undefined_value();
8331 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8332 #if defined(USE_SIMULATOR)
8333 return isolate->heap()->true_value();
8335 return isolate->heap()->false_value();
8340 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8341 HandleScope scope(isolate);
8342 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
8343 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8345 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8346 function->MarkForLazyRecompilation();
8348 Code* unoptimized = function->shared()->code();
8349 if (args.length() == 2 &&
8350 unoptimized->kind() == Code::FUNCTION) {
8351 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8352 CHECK(type->IsEqualTo(CStrVector("osr")));
8353 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8354 unoptimized->set_allow_osr_at_loop_nesting_level(
8355 Code::kMaxLoopNestingMarker);
8358 return isolate->heap()->undefined_value();
8362 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8363 HandleScope scope(isolate);
8364 ASSERT(args.length() == 1);
8365 // The least significant bit (after untagging) indicates whether the
8366 // function is currently optimized, regardless of reason.
8367 if (!V8::UseCrankshaft()) {
8368 return Smi::FromInt(4); // 4 == "never".
8370 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8371 if (FLAG_always_opt) {
8372 // We may have always opt, but that is more best-effort than a real
8373 // promise, so we still say "no" if it is not optimized.
8374 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always".
8375 : Smi::FromInt(2); // 2 == "no".
8377 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8378 : Smi::FromInt(2); // 2 == "no".
8382 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8383 HandleScope scope(isolate);
8384 ASSERT(args.length() == 1);
8385 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8386 return Smi::FromInt(function->shared()->opt_count());
8390 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
8391 HandleScope scope(isolate);
8392 ASSERT(args.length() == 1);
8393 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
8395 // We're not prepared to handle a function with arguments object.
8396 ASSERT(!function->shared()->uses_arguments());
8398 // We have hit a back edge in an unoptimized frame for a function that was
8399 // selected for on-stack replacement. Find the unoptimized code object.
8400 Handle<Code> unoptimized(function->shared()->code(), isolate);
8401 // Keep track of whether we've succeeded in optimizing.
8402 bool succeeded = unoptimized->optimizable();
8404 // If we are trying to do OSR when there are already optimized
8405 // activations of the function, it means (a) the function is directly or
8406 // indirectly recursive and (b) an optimized invocation has been
8407 // deoptimized so that we are currently in an unoptimized activation.
8408 // Check for optimized activations of this function.
8409 JavaScriptFrameIterator it(isolate);
8410 while (succeeded && !it.done()) {
8411 JavaScriptFrame* frame = it.frame();
8412 succeeded = !frame->is_optimized() || frame->function() != *function;
8417 int ast_id = AstNode::kNoNumber;
8419 // The top JS function is this one, the PC is somewhere in the
8420 // unoptimized code.
8421 JavaScriptFrameIterator it(isolate);
8422 JavaScriptFrame* frame = it.frame();
8423 ASSERT(frame->function() == *function);
8424 ASSERT(frame->LookupCode() == *unoptimized);
8425 ASSERT(unoptimized->contains(frame->pc()));
8427 // Use linear search of the unoptimized code's stack check table to find
8428 // the AST id matching the PC.
8429 Address start = unoptimized->instruction_start();
8430 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
8431 Address table_cursor = start + unoptimized->stack_check_table_offset();
8432 uint32_t table_length = Memory::uint32_at(table_cursor);
8433 table_cursor += kIntSize;
8434 for (unsigned i = 0; i < table_length; ++i) {
8435 // Table entries are (AST id, pc offset) pairs.
8436 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8437 if (pc_offset == target_pc_offset) {
8438 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8441 table_cursor += 2 * kIntSize;
8443 ASSERT(ast_id != AstNode::kNoNumber);
8444 if (FLAG_trace_osr) {
8445 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8446 function->PrintName();
8450 // Try to compile the optimized code. A true return value from
8451 // CompileOptimized means that compilation succeeded, not necessarily
8452 // that optimization succeeded.
8453 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8454 function->IsOptimized()) {
8455 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8456 function->code()->deoptimization_data());
8457 if (data->OsrPcOffset()->value() >= 0) {
8458 if (FLAG_trace_osr) {
8459 PrintF("[on-stack replacement offset %d in optimized code]\n",
8460 data->OsrPcOffset()->value());
8462 ASSERT(data->OsrAstId()->value() == ast_id);
8464 // We may never generate the desired OSR entry if we emit an
8465 // early deoptimize.
8473 // Revert to the original stack checks in the original unoptimized code.
8474 if (FLAG_trace_osr) {
8475 PrintF("[restoring original stack checks in ");
8476 function->PrintName();
8479 Handle<Code> check_code;
8480 if (FLAG_count_based_interrupts) {
8481 InterruptStub interrupt_stub;
8482 check_code = interrupt_stub.GetCode();
8485 StackCheckStub check_stub;
8486 check_code = check_stub.GetCode();
8488 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
8489 Deoptimizer::RevertStackCheckCode(*unoptimized,
8493 // Allow OSR only at nesting level zero again.
8494 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8496 // If the optimization attempt succeeded, return the AST id tagged as a
8497 // smi. This tells the builtin that we need to translate the unoptimized
8498 // frame to an optimized one.
8500 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8501 return Smi::FromInt(ast_id);
8503 if (function->IsMarkedForLazyRecompilation()) {
8504 function->ReplaceCode(function->shared()->code());
8506 return Smi::FromInt(-1);
8511 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8512 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8513 return isolate->heap()->undefined_value();
8517 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8518 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8519 return isolate->heap()->nan_value();
8523 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8524 HandleScope scope(isolate);
8525 ASSERT(args.length() >= 2);
8526 int argc = args.length() - 2;
8527 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8528 Object* receiver = args[0];
8530 // If there are too many arguments, allocate argv via malloc.
8531 const int argv_small_size = 10;
8532 Handle<Object> argv_small_buffer[argv_small_size];
8533 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8534 Handle<Object>* argv = argv_small_buffer;
8535 if (argc > argv_small_size) {
8536 argv = new Handle<Object>[argc];
8537 if (argv == NULL) return isolate->StackOverflow();
8538 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8541 for (int i = 0; i < argc; ++i) {
8542 MaybeObject* maybe = args[1 + i];
8544 if (!maybe->To<Object>(&object)) return maybe;
8545 argv[i] = Handle<Object>(object);
8549 Handle<JSReceiver> hfun(fun);
8550 Handle<Object> hreceiver(receiver);
8551 Handle<Object> result =
8552 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8554 if (threw) return Failure::Exception();
8559 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8560 HandleScope scope(isolate);
8561 ASSERT(args.length() == 5);
8562 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
8563 Handle<Object> receiver = args.at<Object>(1);
8564 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
8565 CONVERT_SMI_ARG_CHECKED(offset, 3);
8566 CONVERT_SMI_ARG_CHECKED(argc, 4);
8567 ASSERT(offset >= 0);
8570 // If there are too many arguments, allocate argv via malloc.
8571 const int argv_small_size = 10;
8572 Handle<Object> argv_small_buffer[argv_small_size];
8573 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8574 Handle<Object>* argv = argv_small_buffer;
8575 if (argc > argv_small_size) {
8576 argv = new Handle<Object>[argc];
8577 if (argv == NULL) return isolate->StackOverflow();
8578 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8581 for (int i = 0; i < argc; ++i) {
8582 argv[i] = Object::GetElement(arguments, offset + i);
8586 Handle<Object> result =
8587 Execution::Call(fun, receiver, argc, argv, &threw, true);
8589 if (threw) return Failure::Exception();
8594 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
8595 HandleScope scope(isolate);
8596 ASSERT(args.length() == 1);
8597 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8598 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8602 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
8603 HandleScope scope(isolate);
8604 ASSERT(args.length() == 1);
8605 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8606 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8610 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
8611 NoHandleAllocation ha;
8612 ASSERT(args.length() == 1);
8614 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8615 SharedFunctionInfo* shared = function->shared();
8616 // TODO: The QML mode should be checked in the ContextLength function.
8617 int length = shared->scope_info()->ContextLength(shared->qml_mode());
8620 { MaybeObject* maybe_result =
8621 isolate->heap()->AllocateFunctionContext(length, function);
8622 if (!maybe_result->ToObject(&result)) return maybe_result;
8625 isolate->set_context(Context::cast(result));
8627 return result; // non-failure
8631 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8632 NoHandleAllocation ha;
8633 ASSERT(args.length() == 2);
8634 JSObject* extension_object;
8635 if (args[0]->IsJSObject()) {
8636 extension_object = JSObject::cast(args[0]);
8638 // Convert the object to a proper JavaScript object.
8639 MaybeObject* maybe_js_object = args[0]->ToObject();
8640 if (!maybe_js_object->To(&extension_object)) {
8641 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8642 HandleScope scope(isolate);
8643 Handle<Object> handle = args.at<Object>(0);
8644 Handle<Object> result =
8645 isolate->factory()->NewTypeError("with_expression",
8646 HandleVector(&handle, 1));
8647 return isolate->Throw(*result);
8649 return maybe_js_object;
8654 JSFunction* function;
8655 if (args[1]->IsSmi()) {
8656 // A smi sentinel indicates a context nested inside global code rather
8657 // than some function. There is a canonical empty function that can be
8658 // gotten from the global context.
8659 function = isolate->context()->global_context()->closure();
8661 function = JSFunction::cast(args[1]);
8665 MaybeObject* maybe_context =
8666 isolate->heap()->AllocateWithContext(function,
8669 if (!maybe_context->To(&context)) return maybe_context;
8670 isolate->set_context(context);
8675 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
8676 NoHandleAllocation ha;
8677 ASSERT(args.length() == 3);
8678 String* name = String::cast(args[0]);
8679 Object* thrown_object = args[1];
8680 JSFunction* function;
8681 if (args[2]->IsSmi()) {
8682 // A smi sentinel indicates a context nested inside global code rather
8683 // than some function. There is a canonical empty function that can be
8684 // gotten from the global context.
8685 function = isolate->context()->global_context()->closure();
8687 function = JSFunction::cast(args[2]);
8690 MaybeObject* maybe_context =
8691 isolate->heap()->AllocateCatchContext(function,
8695 if (!maybe_context->To(&context)) return maybe_context;
8696 isolate->set_context(context);
8701 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8702 NoHandleAllocation ha;
8703 ASSERT(args.length() == 2);
8704 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
8705 JSFunction* function;
8706 if (args[1]->IsSmi()) {
8707 // A smi sentinel indicates a context nested inside global code rather
8708 // than some function. There is a canonical empty function that can be
8709 // gotten from the global context.
8710 function = isolate->context()->global_context()->closure();
8712 function = JSFunction::cast(args[1]);
8715 MaybeObject* maybe_context =
8716 isolate->heap()->AllocateBlockContext(function,
8719 if (!maybe_context->To(&context)) return maybe_context;
8720 isolate->set_context(context);
8725 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
8726 NoHandleAllocation ha;
8727 ASSERT(args.length() == 2);
8728 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0);
8729 CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1);
8732 MaybeObject* maybe_context =
8733 isolate->heap()->AllocateModuleContext(isolate->context(),
8735 if (!maybe_context->To(&context)) return maybe_context;
8736 // Also initialize the context slot of the instance object.
8737 instance->set_context(context);
8738 isolate->set_context(context);
8744 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
8745 HandleScope scope(isolate);
8746 ASSERT(args.length() == 2);
8748 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8749 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
8752 PropertyAttributes attributes;
8753 ContextLookupFlags flags = FOLLOW_CHAINS;
8754 BindingFlags binding_flags;
8755 Handle<Object> holder = context->Lookup(name,
8761 // If the slot was not found the result is true.
8762 if (holder.is_null()) {
8763 return isolate->heap()->true_value();
8766 // If the slot was found in a context, it should be DONT_DELETE.
8767 if (holder->IsContext()) {
8768 return isolate->heap()->false_value();
8771 // The slot was found in a JSObject, either a context extension object,
8772 // the global object, or the subject of a with. Try to delete it
8773 // (respecting DONT_DELETE).
8774 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8775 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
8779 // A mechanism to return a pair of Object pointers in registers (if possible).
8780 // How this is achieved is calling convention-dependent.
8781 // All currently supported x86 compiles uses calling conventions that are cdecl
8782 // variants where a 64-bit value is returned in two 32-bit registers
8783 // (edx:eax on ia32, r1:r0 on ARM).
8784 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8785 // In Win64 calling convention, a struct of two pointers is returned in memory,
8786 // allocated by the caller, and passed as a pointer in a hidden first parameter.
8787 #ifdef V8_HOST_ARCH_64_BIT
8793 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
8794 ObjectPair result = {x, y};
8795 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8796 // In Win64 they are assigned to a hidden first argument.
8800 typedef uint64_t ObjectPair;
8801 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
8802 return reinterpret_cast<uint32_t>(x) |
8803 (reinterpret_cast<ObjectPair>(y) << 32);
8808 static inline MaybeObject* Unhole(Heap* heap,
8810 PropertyAttributes attributes) {
8811 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8813 return x->IsTheHole() ? heap->undefined_value() : x;
8817 static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8819 ASSERT(!holder->IsGlobalObject());
8820 Context* top = isolate->context();
8821 // Get the context extension function.
8822 JSFunction* context_extension_function =
8823 top->global_context()->context_extension_function();
8824 // If the holder isn't a context extension object, we just return it
8825 // as the receiver. This allows arguments objects to be used as
8826 // receivers, but only if they are put in the context scope chain
8827 // explicitly via a with-statement.
8828 Object* constructor = holder->map()->constructor();
8829 if (constructor != context_extension_function) return holder;
8830 // Fall back to using the global object as the implicit receiver if
8831 // the property turns out to be a local variable allocated in a
8832 // context extension object - introduced via eval. Implicit global
8833 // receivers are indicated with the hole value.
8834 return isolate->heap()->the_hole_value();
8838 static ObjectPair LoadContextSlotHelper(Arguments args,
8841 HandleScope scope(isolate);
8842 ASSERT_EQ(2, args.length());
8844 if (!args[0]->IsContext() || !args[1]->IsString()) {
8845 return MakePair(isolate->ThrowIllegalOperation(), NULL);
8847 Handle<Context> context = args.at<Context>(0);
8848 Handle<String> name = args.at<String>(1);
8851 PropertyAttributes attributes;
8852 ContextLookupFlags flags = FOLLOW_CHAINS;
8853 BindingFlags binding_flags;
8854 Handle<Object> holder = context->Lookup(name,
8860 // If the index is non-negative, the slot has been found in a context.
8862 ASSERT(holder->IsContext());
8863 // If the "property" we were looking for is a local variable, the
8864 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
8866 // Use the hole as the receiver to signal that the receiver is implicit
8867 // and that the global receiver should be used (as distinguished from an
8868 // explicit receiver that happens to be a global object).
8869 Handle<Object> receiver = isolate->factory()->the_hole_value();
8870 Object* value = Context::cast(*holder)->get(index);
8871 // Check for uninitialized bindings.
8872 switch (binding_flags) {
8873 case MUTABLE_CHECK_INITIALIZED:
8874 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8875 if (value->IsTheHole()) {
8876 Handle<Object> reference_error =
8877 isolate->factory()->NewReferenceError("not_defined",
8878 HandleVector(&name, 1));
8879 return MakePair(isolate->Throw(*reference_error), NULL);
8882 case MUTABLE_IS_INITIALIZED:
8883 case IMMUTABLE_IS_INITIALIZED:
8884 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8885 ASSERT(!value->IsTheHole());
8886 return MakePair(value, *receiver);
8887 case IMMUTABLE_CHECK_INITIALIZED:
8888 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8889 case MISSING_BINDING:
8891 return MakePair(NULL, NULL);
8895 // Otherwise, if the slot was found the holder is a context extension
8896 // object, subject of a with, or a global object. We read the named
8897 // property from it.
8898 if (!holder.is_null()) {
8899 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8900 ASSERT(object->HasProperty(*name));
8901 // GetProperty below can cause GC.
8902 Handle<Object> receiver_handle(object->IsGlobalObject()
8903 ? GlobalObject::cast(*object)->global_receiver()
8904 : ComputeReceiverForNonGlobal(isolate, *object));
8906 // No need to unhole the value here. This is taken care of by the
8907 // GetProperty function.
8908 MaybeObject* value = object->GetProperty(*name);
8909 return MakePair(value, *receiver_handle);
8913 // The property doesn't exist - throw exception.
8914 Handle<Object> reference_error =
8915 isolate->factory()->NewReferenceError("not_defined",
8916 HandleVector(&name, 1));
8917 return MakePair(isolate->Throw(*reference_error), NULL);
8919 // The property doesn't exist - return undefined.
8920 return MakePair(isolate->heap()->undefined_value(),
8921 isolate->heap()->undefined_value());
8926 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
8927 return LoadContextSlotHelper(args, isolate, true);
8931 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
8932 return LoadContextSlotHelper(args, isolate, false);
8936 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
8937 HandleScope scope(isolate);
8938 ASSERT(args.length() == 4);
8940 Handle<Object> value(args[0], isolate);
8941 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8942 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
8943 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8944 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8945 ? kNonStrictMode : kStrictMode;
8948 PropertyAttributes attributes;
8949 ContextLookupFlags flags = FOLLOW_CHAINS;
8950 BindingFlags binding_flags;
8951 Handle<Object> holder = context->Lookup(name,
8958 // The property was found in a context slot.
8959 Handle<Context> context = Handle<Context>::cast(holder);
8960 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8961 context->get(index)->IsTheHole()) {
8962 Handle<Object> error =
8963 isolate->factory()->NewReferenceError("not_defined",
8964 HandleVector(&name, 1));
8965 return isolate->Throw(*error);
8967 // Ignore if read_only variable.
8968 if ((attributes & READ_ONLY) == 0) {
8969 // Context is a fixed array and set cannot fail.
8970 context->set(index, *value);
8971 } else if (strict_mode == kStrictMode) {
8972 // Setting read only property in strict mode.
8973 Handle<Object> error =
8974 isolate->factory()->NewTypeError("strict_cannot_assign",
8975 HandleVector(&name, 1));
8976 return isolate->Throw(*error);
8981 // Slow case: The property is not in a context slot. It is either in a
8982 // context extension object, a property of the subject of a with, or a
8983 // property of the global object.
8984 Handle<JSObject> object;
8986 if (!holder.is_null()) {
8987 // The property exists on the holder.
8988 object = Handle<JSObject>::cast(holder);
8990 // The property was not found.
8991 ASSERT(attributes == ABSENT);
8993 if (strict_mode == kStrictMode) {
8994 // Throw in strict mode (assignment to undefined variable).
8995 Handle<Object> error =
8996 isolate->factory()->NewReferenceError(
8997 "not_defined", HandleVector(&name, 1));
8998 return isolate->Throw(*error);
9000 // In non-strict mode, the property is added to the global object.
9002 object = Handle<JSObject>(isolate->context()->global());
9005 // Set the property if it's not read only or doesn't yet exist.
9006 if ((attributes & READ_ONLY) == 0 ||
9007 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
9008 RETURN_IF_EMPTY_HANDLE(
9010 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
9011 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
9012 // Setting read only property in strict mode.
9013 Handle<Object> error =
9014 isolate->factory()->NewTypeError(
9015 "strict_cannot_assign", HandleVector(&name, 1));
9016 return isolate->Throw(*error);
9022 RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
9023 HandleScope scope(isolate);
9024 ASSERT(args.length() == 1);
9026 return isolate->Throw(args[0]);
9030 RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
9031 HandleScope scope(isolate);
9032 ASSERT(args.length() == 1);
9034 return isolate->ReThrow(args[0]);
9038 RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
9039 ASSERT_EQ(0, args.length());
9040 return isolate->PromoteScheduledException();
9044 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
9045 HandleScope scope(isolate);
9046 ASSERT(args.length() == 1);
9048 Handle<Object> name(args[0], isolate);
9049 Handle<Object> reference_error =
9050 isolate->factory()->NewReferenceError("not_defined",
9051 HandleVector(&name, 1));
9052 return isolate->Throw(*reference_error);
9056 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
9057 ASSERT(args.length() == 0);
9059 // First check if this is a real stack overflow.
9060 if (isolate->stack_guard()->IsStackOverflow()) {
9061 NoHandleAllocation na;
9062 return isolate->StackOverflow();
9065 return Execution::HandleStackGuardInterrupt(isolate);
9069 RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9070 ASSERT(args.length() == 0);
9071 return Execution::HandleStackGuardInterrupt(isolate);
9075 static int StackSize() {
9077 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9082 static void PrintTransition(Object* result) {
9084 { const int nmax = 80;
9085 int n = StackSize();
9087 PrintF("%4d:%*s", n, n, "");
9089 PrintF("%4d:%*s", n, nmax, "...");
9092 if (result == NULL) {
9093 JavaScriptFrame::PrintTop(stdout, true, false);
9098 result->ShortPrint();
9104 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
9105 ASSERT(args.length() == 0);
9106 NoHandleAllocation ha;
9107 PrintTransition(NULL);
9108 return isolate->heap()->undefined_value();
9112 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
9113 NoHandleAllocation ha;
9114 PrintTransition(args[0]);
9115 return args[0]; // return TOS
9119 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
9120 NoHandleAllocation ha;
9121 ASSERT(args.length() == 1);
9124 if (args[0]->IsString()) {
9125 // If we have a string, assume it's a code "marker"
9126 // and print some interesting cpu debugging info.
9127 JavaScriptFrameIterator it(isolate);
9128 JavaScriptFrame* frame = it.frame();
9129 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9130 frame->fp(), frame->sp(), frame->caller_sp());
9132 PrintF("DebugPrint: ");
9135 if (args[0]->IsHeapObject()) {
9137 HeapObject::cast(args[0])->map()->Print();
9140 // ShortPrint is available in release mode. Print is not.
9141 args[0]->ShortPrint();
9146 return args[0]; // return TOS
9150 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
9151 ASSERT(args.length() == 0);
9152 NoHandleAllocation ha;
9153 isolate->PrintStack();
9154 return isolate->heap()->undefined_value();
9158 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
9159 NoHandleAllocation ha;
9160 ASSERT(args.length() == 0);
9162 // According to ECMA-262, section 15.9.1, page 117, the precision of
9163 // the number in a Date object representing a particular instant in
9164 // time is milliseconds. Therefore, we floor the result of getting
9166 double millis = floor(OS::TimeCurrentMillis());
9167 return isolate->heap()->NumberFromDouble(millis);
9171 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
9172 HandleScope scope(isolate);
9173 ASSERT(args.length() == 2);
9175 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
9178 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
9180 MaybeObject* maybe_result_array =
9181 output->EnsureCanContainHeapObjectElements();
9182 if (maybe_result_array->IsFailure()) return maybe_result_array;
9183 RUNTIME_ASSERT(output->HasFastElements());
9185 AssertNoAllocation no_allocation;
9187 FixedArray* output_array = FixedArray::cast(output->elements());
9188 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9190 String::FlatContent str_content = str->GetFlatContent();
9191 if (str_content.IsAscii()) {
9192 result = DateParser::Parse(str_content.ToAsciiVector(),
9194 isolate->unicode_cache());
9196 ASSERT(str_content.IsTwoByte());
9197 result = DateParser::Parse(str_content.ToUC16Vector(),
9199 isolate->unicode_cache());
9205 return isolate->heap()->null_value();
9210 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
9211 NoHandleAllocation ha;
9212 ASSERT(args.length() == 1);
9214 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9215 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9216 const char* zone = OS::LocalTimezone(static_cast<double>(time));
9217 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
9221 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
9222 NoHandleAllocation ha;
9223 ASSERT(args.length() == 1);
9225 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
9226 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9228 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
9232 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
9233 ASSERT(args.length() == 1);
9234 Object* global = args[0];
9235 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
9236 return JSGlobalObject::cast(global)->global_receiver();
9240 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
9241 HandleScope scope(isolate);
9242 ASSERT_EQ(1, args.length());
9243 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9245 source = Handle<String>(source->TryFlattenGetString());
9246 // Optimized fast case where we only have ASCII characters.
9247 Handle<Object> result;
9248 if (source->IsSeqAsciiString()) {
9249 result = JsonParser<true>::Parse(source);
9251 result = JsonParser<false>::Parse(source);
9253 if (result.is_null()) {
9254 // Syntax error or stack overflow in scanner.
9255 ASSERT(isolate->has_pending_exception());
9256 return Failure::Exception();
9262 bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9263 Handle<Context> context) {
9264 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9265 // Check with callback if set.
9266 AllowCodeGenerationFromStringsCallback callback =
9267 isolate->allow_code_gen_callback();
9268 if (callback == NULL) {
9269 // No callback set and code generation disallowed.
9272 // Callback set. Let it decide if code generation is allowed.
9273 VMState state(isolate, EXTERNAL);
9274 return callback(v8::Utils::ToLocal(context));
9279 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
9280 HandleScope scope(isolate);
9281 ASSERT_EQ(1, args.length());
9282 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
9284 // Extract global context.
9285 Handle<Context> context(isolate->context()->global_context());
9287 // Check if global context allows code generation from
9288 // strings. Throw an exception if it doesn't.
9289 if (context->allow_code_gen_from_strings()->IsFalse() &&
9290 !CodeGenerationFromStringsAllowed(isolate, context)) {
9291 return isolate->Throw(*isolate->factory()->NewError(
9292 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9295 // Compile source string in the global context.
9296 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9297 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition, false);
9298 if (shared.is_null()) return Failure::Exception();
9299 Handle<JSFunction> fun =
9300 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9307 static ObjectPair CompileGlobalEval(Isolate* isolate,
9308 Handle<String> source,
9309 Handle<Object> receiver,
9310 LanguageMode language_mode,
9313 Handle<Context> context = Handle<Context>(isolate->context());
9314 Handle<Context> global_context = Handle<Context>(context->global_context());
9316 // Check if global context allows code generation from
9317 // strings. Throw an exception if it doesn't.
9318 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9319 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
9320 isolate->Throw(*isolate->factory()->NewError(
9321 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9322 return MakePair(Failure::Exception(), NULL);
9325 // Deal with a normal eval call with a string argument. Compile it
9326 // and return the compiled function bound in the local context.
9327 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9329 Handle<Context>(isolate->context()),
9330 context->IsGlobalContext(),
9334 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
9335 Handle<JSFunction> compiled =
9336 isolate->factory()->NewFunctionFromSharedFunctionInfo(
9337 shared, context, NOT_TENURED);
9338 return MakePair(*compiled, *receiver);
9342 RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
9343 ASSERT(args.length() == 6);
9345 HandleScope scope(isolate);
9346 Handle<Object> callee = args.at<Object>(0);
9348 // If "eval" didn't refer to the original GlobalEval, it's not a
9349 // direct call to eval.
9350 // (And even if it is, but the first argument isn't a string, just let
9351 // execution default to an indirect call to eval, which will also return
9352 // the first argument without doing anything).
9353 if (*callee != isolate->global_context()->global_eval_fun() ||
9354 !args[1]->IsString()) {
9355 return MakePair(*callee, isolate->heap()->the_hole_value());
9358 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9359 ASSERT(args[4]->IsSmi());
9360 return CompileGlobalEval(isolate,
9365 Smi::cast(args[5])->value());
9369 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
9370 // This utility adjusts the property attributes for newly created Function
9371 // object ("new Function(...)") by changing the map.
9372 // All it does is changing the prototype property to enumerable
9373 // as specified in ECMA262, 15.3.5.2.
9374 HandleScope scope(isolate);
9375 ASSERT(args.length() == 1);
9376 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
9378 Handle<Map> map = func->shared()->is_classic_mode()
9379 ? isolate->function_instance_map()
9380 : isolate->strict_mode_function_instance_map();
9382 ASSERT(func->map()->instance_type() == map->instance_type());
9383 ASSERT(func->map()->instance_size() == map->instance_size());
9384 func->set_map(*map);
9389 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
9390 // Allocate a block of memory in NewSpace (filled with a filler).
9391 // Use as fallback for allocation in generated code when NewSpace
9393 ASSERT(args.length() == 1);
9394 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
9395 int size = size_smi->value();
9396 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9397 RUNTIME_ASSERT(size > 0);
9398 Heap* heap = isolate->heap();
9399 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
9400 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
9402 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
9403 if (maybe_allocation->ToObject(&allocation)) {
9404 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
9406 return maybe_allocation;
9411 // Push an object unto an array of objects if it is not already in the
9412 // array. Returns true if the element was pushed on the stack and
9414 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
9415 ASSERT(args.length() == 2);
9416 CONVERT_ARG_CHECKED(JSArray, array, 0);
9417 CONVERT_ARG_CHECKED(JSObject, element, 1);
9418 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
9419 int length = Smi::cast(array->length())->value();
9420 FixedArray* elements = FixedArray::cast(array->elements());
9421 for (int i = 0; i < length; i++) {
9422 if (elements->get(i) == element) return isolate->heap()->false_value();
9425 // Strict not needed. Used for cycle detection in Array join implementation.
9426 { MaybeObject* maybe_obj =
9427 array->SetFastElement(length, element, kNonStrictMode, true);
9428 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9430 return isolate->heap()->true_value();
9435 * A simple visitor visits every element of Array's.
9436 * The backend storage can be a fixed array for fast elements case,
9437 * or a dictionary for sparse array. Since Dictionary is a subtype
9438 * of FixedArray, the class can be used by both fast and slow cases.
9439 * The second parameter of the constructor, fast_elements, specifies
9440 * whether the storage is a FixedArray or Dictionary.
9442 * An index limit is used to deal with the situation that a result array
9443 * length overflows 32-bit non-negative integer.
9445 class ArrayConcatVisitor {
9447 ArrayConcatVisitor(Isolate* isolate,
9448 Handle<FixedArray> storage,
9449 bool fast_elements) :
9451 storage_(Handle<FixedArray>::cast(
9452 isolate->global_handles()->Create(*storage))),
9454 fast_elements_(fast_elements) { }
9456 ~ArrayConcatVisitor() {
9460 void visit(uint32_t i, Handle<Object> elm) {
9461 if (i >= JSObject::kMaxElementCount - index_offset_) return;
9462 uint32_t index = index_offset_ + i;
9464 if (fast_elements_) {
9465 if (index < static_cast<uint32_t>(storage_->length())) {
9466 storage_->set(index, *elm);
9469 // Our initial estimate of length was foiled, possibly by
9470 // getters on the arrays increasing the length of later arrays
9471 // during iteration.
9472 // This shouldn't happen in anything but pathological cases.
9473 SetDictionaryMode(index);
9474 // Fall-through to dictionary mode.
9476 ASSERT(!fast_elements_);
9477 Handle<SeededNumberDictionary> dict(
9478 SeededNumberDictionary::cast(*storage_));
9479 Handle<SeededNumberDictionary> result =
9480 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
9481 if (!result.is_identical_to(dict)) {
9482 // Dictionary needed to grow.
9484 set_storage(*result);
9488 void increase_index_offset(uint32_t delta) {
9489 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9490 index_offset_ = JSObject::kMaxElementCount;
9492 index_offset_ += delta;
9496 Handle<JSArray> ToArray() {
9497 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
9498 Handle<Object> length =
9499 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
9501 if (fast_elements_) {
9502 map = isolate_->factory()->GetElementsTransitionMap(array,
9505 map = isolate_->factory()->GetElementsTransitionMap(array,
9506 DICTIONARY_ELEMENTS);
9508 array->set_map(*map);
9509 array->set_length(*length);
9510 array->set_elements(*storage_);
9515 // Convert storage to dictionary mode.
9516 void SetDictionaryMode(uint32_t index) {
9517 ASSERT(fast_elements_);
9518 Handle<FixedArray> current_storage(*storage_);
9519 Handle<SeededNumberDictionary> slow_storage(
9520 isolate_->factory()->NewSeededNumberDictionary(
9521 current_storage->length()));
9522 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9523 for (uint32_t i = 0; i < current_length; i++) {
9524 HandleScope loop_scope;
9525 Handle<Object> element(current_storage->get(i));
9526 if (!element->IsTheHole()) {
9527 Handle<SeededNumberDictionary> new_storage =
9528 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
9529 if (!new_storage.is_identical_to(slow_storage)) {
9530 slow_storage = loop_scope.CloseAndEscape(new_storage);
9535 set_storage(*slow_storage);
9536 fast_elements_ = false;
9539 inline void clear_storage() {
9540 isolate_->global_handles()->Destroy(
9541 Handle<Object>::cast(storage_).location());
9544 inline void set_storage(FixedArray* storage) {
9545 storage_ = Handle<FixedArray>::cast(
9546 isolate_->global_handles()->Create(storage));
9550 Handle<FixedArray> storage_; // Always a global handle.
9551 // Index after last seen index. Always less than or equal to
9552 // JSObject::kMaxElementCount.
9553 uint32_t index_offset_;
9554 bool fast_elements_;
9558 static uint32_t EstimateElementCount(Handle<JSArray> array) {
9559 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9560 int element_count = 0;
9561 switch (array->GetElementsKind()) {
9562 case FAST_SMI_ONLY_ELEMENTS:
9563 case FAST_ELEMENTS: {
9564 // Fast elements can't have lengths that are not representable by
9565 // a 32-bit signed integer.
9566 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9567 int fast_length = static_cast<int>(length);
9568 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9569 for (int i = 0; i < fast_length; i++) {
9570 if (!elements->get(i)->IsTheHole()) element_count++;
9574 case FAST_DOUBLE_ELEMENTS:
9575 // TODO(1810): Decide if it's worthwhile to implement this.
9578 case DICTIONARY_ELEMENTS: {
9579 Handle<SeededNumberDictionary> dictionary(
9580 SeededNumberDictionary::cast(array->elements()));
9581 int capacity = dictionary->Capacity();
9582 for (int i = 0; i < capacity; i++) {
9583 Handle<Object> key(dictionary->KeyAt(i));
9584 if (dictionary->IsKey(*key)) {
9590 case NON_STRICT_ARGUMENTS_ELEMENTS:
9591 case EXTERNAL_BYTE_ELEMENTS:
9592 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9593 case EXTERNAL_SHORT_ELEMENTS:
9594 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9595 case EXTERNAL_INT_ELEMENTS:
9596 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9597 case EXTERNAL_FLOAT_ELEMENTS:
9598 case EXTERNAL_DOUBLE_ELEMENTS:
9599 case EXTERNAL_PIXEL_ELEMENTS:
9600 // External arrays are always dense.
9603 // As an estimate, we assume that the prototype doesn't contain any
9604 // inherited elements.
9605 return element_count;
9610 template<class ExternalArrayClass, class ElementType>
9611 static void IterateExternalArrayElements(Isolate* isolate,
9612 Handle<JSObject> receiver,
9613 bool elements_are_ints,
9614 bool elements_are_guaranteed_smis,
9615 ArrayConcatVisitor* visitor) {
9616 Handle<ExternalArrayClass> array(
9617 ExternalArrayClass::cast(receiver->elements()));
9618 uint32_t len = static_cast<uint32_t>(array->length());
9620 ASSERT(visitor != NULL);
9621 if (elements_are_ints) {
9622 if (elements_are_guaranteed_smis) {
9623 for (uint32_t j = 0; j < len; j++) {
9624 HandleScope loop_scope;
9625 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
9626 visitor->visit(j, e);
9629 for (uint32_t j = 0; j < len; j++) {
9630 HandleScope loop_scope;
9631 int64_t val = static_cast<int64_t>(array->get_scalar(j));
9632 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9633 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9634 visitor->visit(j, e);
9637 isolate->factory()->NewNumber(static_cast<ElementType>(val));
9638 visitor->visit(j, e);
9643 for (uint32_t j = 0; j < len; j++) {
9644 HandleScope loop_scope(isolate);
9645 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
9646 visitor->visit(j, e);
9652 // Used for sorting indices in a List<uint32_t>.
9653 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9656 return (a == b) ? 0 : (a < b) ? -1 : 1;
9660 static void CollectElementIndices(Handle<JSObject> object,
9662 List<uint32_t>* indices) {
9663 ElementsKind kind = object->GetElementsKind();
9665 case FAST_SMI_ONLY_ELEMENTS:
9666 case FAST_ELEMENTS: {
9667 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9668 uint32_t length = static_cast<uint32_t>(elements->length());
9669 if (range < length) length = range;
9670 for (uint32_t i = 0; i < length; i++) {
9671 if (!elements->get(i)->IsTheHole()) {
9677 case FAST_DOUBLE_ELEMENTS: {
9678 // TODO(1810): Decide if it's worthwhile to implement this.
9682 case DICTIONARY_ELEMENTS: {
9683 Handle<SeededNumberDictionary> dict(
9684 SeededNumberDictionary::cast(object->elements()));
9685 uint32_t capacity = dict->Capacity();
9686 for (uint32_t j = 0; j < capacity; j++) {
9687 HandleScope loop_scope;
9688 Handle<Object> k(dict->KeyAt(j));
9689 if (dict->IsKey(*k)) {
9690 ASSERT(k->IsNumber());
9691 uint32_t index = static_cast<uint32_t>(k->Number());
9692 if (index < range) {
9693 indices->Add(index);
9700 int dense_elements_length;
9702 case EXTERNAL_PIXEL_ELEMENTS: {
9703 dense_elements_length =
9704 ExternalPixelArray::cast(object->elements())->length();
9707 case EXTERNAL_BYTE_ELEMENTS: {
9708 dense_elements_length =
9709 ExternalByteArray::cast(object->elements())->length();
9712 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9713 dense_elements_length =
9714 ExternalUnsignedByteArray::cast(object->elements())->length();
9717 case EXTERNAL_SHORT_ELEMENTS: {
9718 dense_elements_length =
9719 ExternalShortArray::cast(object->elements())->length();
9722 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9723 dense_elements_length =
9724 ExternalUnsignedShortArray::cast(object->elements())->length();
9727 case EXTERNAL_INT_ELEMENTS: {
9728 dense_elements_length =
9729 ExternalIntArray::cast(object->elements())->length();
9732 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9733 dense_elements_length =
9734 ExternalUnsignedIntArray::cast(object->elements())->length();
9737 case EXTERNAL_FLOAT_ELEMENTS: {
9738 dense_elements_length =
9739 ExternalFloatArray::cast(object->elements())->length();
9742 case EXTERNAL_DOUBLE_ELEMENTS: {
9743 dense_elements_length =
9744 ExternalDoubleArray::cast(object->elements())->length();
9749 dense_elements_length = 0;
9752 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9753 if (range <= length) {
9755 // We will add all indices, so we might as well clear it first
9756 // and avoid duplicates.
9759 for (uint32_t i = 0; i < length; i++) {
9762 if (length == range) return; // All indices accounted for already.
9767 Handle<Object> prototype(object->GetPrototype());
9768 if (prototype->IsJSObject()) {
9769 // The prototype will usually have no inherited element indices,
9770 // but we have to check.
9771 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9777 * A helper function that visits elements of a JSArray in numerical
9780 * The visitor argument called for each existing element in the array
9781 * with the element index and the element's value.
9782 * Afterwards it increments the base-index of the visitor by the array
9784 * Returns false if any access threw an exception, otherwise true.
9786 static bool IterateElements(Isolate* isolate,
9787 Handle<JSArray> receiver,
9788 ArrayConcatVisitor* visitor) {
9789 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9790 switch (receiver->GetElementsKind()) {
9791 case FAST_SMI_ONLY_ELEMENTS:
9792 case FAST_ELEMENTS: {
9793 // Run through the elements FixedArray and use HasElement and GetElement
9794 // to check the prototype for missing elements.
9795 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9796 int fast_length = static_cast<int>(length);
9797 ASSERT(fast_length <= elements->length());
9798 for (int j = 0; j < fast_length; j++) {
9799 HandleScope loop_scope(isolate);
9800 Handle<Object> element_value(elements->get(j), isolate);
9801 if (!element_value->IsTheHole()) {
9802 visitor->visit(j, element_value);
9803 } else if (receiver->HasElement(j)) {
9804 // Call GetElement on receiver, not its prototype, or getters won't
9805 // have the correct receiver.
9806 element_value = Object::GetElement(receiver, j);
9807 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
9808 visitor->visit(j, element_value);
9813 case FAST_DOUBLE_ELEMENTS: {
9814 // TODO(1810): Decide if it's worthwhile to implement this.
9818 case DICTIONARY_ELEMENTS: {
9819 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
9820 List<uint32_t> indices(dict->Capacity() / 2);
9821 // Collect all indices in the object and the prototypes less
9822 // than length. This might introduce duplicates in the indices list.
9823 CollectElementIndices(receiver, length, &indices);
9824 indices.Sort(&compareUInt32);
9826 int n = indices.length();
9828 HandleScope loop_scope;
9829 uint32_t index = indices[j];
9830 Handle<Object> element = Object::GetElement(receiver, index);
9831 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
9832 visitor->visit(index, element);
9833 // Skip to next different index (i.e., omit duplicates).
9836 } while (j < n && indices[j] == index);
9840 case EXTERNAL_PIXEL_ELEMENTS: {
9841 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9842 receiver->elements()));
9843 for (uint32_t j = 0; j < length; j++) {
9844 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
9845 visitor->visit(j, e);
9849 case EXTERNAL_BYTE_ELEMENTS: {
9850 IterateExternalArrayElements<ExternalByteArray, int8_t>(
9851 isolate, receiver, true, true, visitor);
9854 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9855 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
9856 isolate, receiver, true, true, visitor);
9859 case EXTERNAL_SHORT_ELEMENTS: {
9860 IterateExternalArrayElements<ExternalShortArray, int16_t>(
9861 isolate, receiver, true, true, visitor);
9864 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9865 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
9866 isolate, receiver, true, true, visitor);
9869 case EXTERNAL_INT_ELEMENTS: {
9870 IterateExternalArrayElements<ExternalIntArray, int32_t>(
9871 isolate, receiver, true, false, visitor);
9874 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9875 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
9876 isolate, receiver, true, false, visitor);
9879 case EXTERNAL_FLOAT_ELEMENTS: {
9880 IterateExternalArrayElements<ExternalFloatArray, float>(
9881 isolate, receiver, false, false, visitor);
9884 case EXTERNAL_DOUBLE_ELEMENTS: {
9885 IterateExternalArrayElements<ExternalDoubleArray, double>(
9886 isolate, receiver, false, false, visitor);
9893 visitor->increase_index_offset(length);
9899 * Array::concat implementation.
9900 * See ECMAScript 262, 15.4.4.4.
9901 * TODO(581): Fix non-compliance for very large concatenations and update to
9902 * following the ECMAScript 5 specification.
9904 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
9905 ASSERT(args.length() == 1);
9906 HandleScope handle_scope(isolate);
9908 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
9909 int argument_count = static_cast<int>(arguments->length()->Number());
9910 RUNTIME_ASSERT(arguments->HasFastElements());
9911 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
9913 // Pass 1: estimate the length and number of elements of the result.
9914 // The actual length can be larger if any of the arguments have getters
9915 // that mutate other arguments (but will otherwise be precise).
9916 // The number of elements is precise if there are no inherited elements.
9918 uint32_t estimate_result_length = 0;
9919 uint32_t estimate_nof_elements = 0;
9921 for (int i = 0; i < argument_count; i++) {
9922 HandleScope loop_scope;
9923 Handle<Object> obj(elements->get(i));
9924 uint32_t length_estimate;
9925 uint32_t element_estimate;
9926 if (obj->IsJSArray()) {
9927 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9928 // TODO(1810): Find out if it's worthwhile to properly support
9929 // arbitrary ElementsKinds. For now, pessimistically transition to
9931 if (array->HasFastDoubleElements()) {
9932 array = Handle<JSArray>::cast(
9933 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
9936 static_cast<uint32_t>(array->length()->Number());
9938 EstimateElementCount(array);
9940 length_estimate = 1;
9941 element_estimate = 1;
9943 // Avoid overflows by capping at kMaxElementCount.
9944 if (JSObject::kMaxElementCount - estimate_result_length <
9946 estimate_result_length = JSObject::kMaxElementCount;
9948 estimate_result_length += length_estimate;
9950 if (JSObject::kMaxElementCount - estimate_nof_elements <
9952 estimate_nof_elements = JSObject::kMaxElementCount;
9954 estimate_nof_elements += element_estimate;
9959 // If estimated number of elements is more than half of length, a
9960 // fixed array (fast case) is more time and space-efficient than a
9962 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
9964 Handle<FixedArray> storage;
9966 // The backing storage array must have non-existing elements to
9967 // preserve holes across concat operations.
9968 storage = isolate->factory()->NewFixedArrayWithHoles(
9969 estimate_result_length);
9971 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9972 uint32_t at_least_space_for = estimate_nof_elements +
9973 (estimate_nof_elements >> 2);
9974 storage = Handle<FixedArray>::cast(
9975 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
9978 ArrayConcatVisitor visitor(isolate, storage, fast_case);
9980 for (int i = 0; i < argument_count; i++) {
9981 Handle<Object> obj(elements->get(i));
9982 if (obj->IsJSArray()) {
9983 Handle<JSArray> array = Handle<JSArray>::cast(obj);
9984 if (!IterateElements(isolate, array, &visitor)) {
9985 return Failure::Exception();
9988 visitor.visit(0, obj);
9989 visitor.increase_index_offset(1);
9993 return *visitor.ToArray();
9997 // This will not allocate (flatten the string), but it may run
9998 // very slowly for very deeply nested ConsStrings. For debugging use only.
9999 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
10000 NoHandleAllocation ha;
10001 ASSERT(args.length() == 1);
10003 CONVERT_ARG_CHECKED(String, string, 0);
10004 StringInputBuffer buffer(string);
10005 while (buffer.has_more()) {
10006 uint16_t character = buffer.GetNext();
10007 PrintF("%c", character);
10012 // Moves all own elements of an object, that are below a limit, to positions
10013 // starting at zero. All undefined values are placed after non-undefined values,
10014 // and are followed by non-existing element. Does not change the length
10016 // Returns the number of non-undefined elements collected.
10017 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
10018 ASSERT(args.length() == 2);
10019 CONVERT_ARG_CHECKED(JSObject, object, 0);
10020 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10021 return object->PrepareElementsForSort(limit);
10025 // Move contents of argument 0 (an array) to argument 1 (an array)
10026 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
10027 ASSERT(args.length() == 2);
10028 CONVERT_ARG_CHECKED(JSArray, from, 0);
10029 CONVERT_ARG_CHECKED(JSArray, to, 1);
10030 FixedArrayBase* new_elements = from->elements();
10031 MaybeObject* maybe_new_map;
10032 ElementsKind elements_kind;
10033 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10034 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
10035 elements_kind = FAST_ELEMENTS;
10036 } else if (new_elements->map() ==
10037 isolate->heap()->fixed_double_array_map()) {
10038 elements_kind = FAST_DOUBLE_ELEMENTS;
10040 elements_kind = DICTIONARY_ELEMENTS;
10042 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
10044 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10045 to->set_map(Map::cast(new_map));
10046 to->set_elements(new_elements);
10047 to->set_length(from->length());
10049 { MaybeObject* maybe_obj = from->ResetElements();
10050 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10052 from->set_length(Smi::FromInt(0));
10057 // How many elements does this object/array have?
10058 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
10059 ASSERT(args.length() == 1);
10060 CONVERT_ARG_CHECKED(JSObject, object, 0);
10061 HeapObject* elements = object->elements();
10062 if (elements->IsDictionary()) {
10063 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10064 return Smi::FromInt(result);
10065 } else if (object->IsJSArray()) {
10066 return JSArray::cast(object)->length();
10068 return Smi::FromInt(FixedArray::cast(elements)->length());
10073 // Returns an array that tells you where in the [0, length) interval an array
10074 // might have elements. Can either return keys (positive integers) or
10075 // intervals (pair of a negative integer (-start-1) followed by a
10076 // positive (length)) or undefined values.
10077 // Intervals can span over some keys that are not in the object.
10078 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
10079 ASSERT(args.length() == 2);
10080 HandleScope scope(isolate);
10081 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
10082 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
10083 if (array->elements()->IsDictionary()) {
10084 // Create an array and get all the keys into it, then remove all the
10085 // keys that are not integers in the range 0 to length-1.
10086 bool threw = false;
10087 Handle<FixedArray> keys =
10088 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10089 if (threw) return Failure::Exception();
10091 int keys_length = keys->length();
10092 for (int i = 0; i < keys_length; i++) {
10093 Object* key = keys->get(i);
10094 uint32_t index = 0;
10095 if (!key->ToArrayIndex(&index) || index >= length) {
10096 // Zap invalid keys.
10097 keys->set_undefined(i);
10100 return *isolate->factory()->NewJSArrayWithElements(keys);
10102 ASSERT(array->HasFastElements() ||
10103 array->HasFastSmiOnlyElements() ||
10104 array->HasFastDoubleElements());
10105 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
10106 // -1 means start of array.
10107 single_interval->set(0, Smi::FromInt(-1));
10108 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
10109 uint32_t actual_length =
10110 static_cast<uint32_t>(elements->length());
10111 uint32_t min_length = actual_length < length ? actual_length : length;
10112 Handle<Object> length_object =
10113 isolate->factory()->NewNumber(static_cast<double>(min_length));
10114 single_interval->set(1, *length_object);
10115 return *isolate->factory()->NewJSArrayWithElements(single_interval);
10120 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
10121 ASSERT(args.length() == 3);
10122 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10123 CONVERT_ARG_CHECKED(String, name, 1);
10124 CONVERT_SMI_ARG_CHECKED(flag, 2);
10125 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10126 return obj->LookupAccessor(name, component);
10130 #ifdef ENABLE_DEBUGGER_SUPPORT
10131 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
10132 ASSERT(args.length() == 0);
10133 return Execution::DebugBreakHelper();
10137 // Helper functions for wrapping and unwrapping stack frame ids.
10138 static Smi* WrapFrameId(StackFrame::Id id) {
10139 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
10140 return Smi::FromInt(id >> 2);
10144 static StackFrame::Id UnwrapFrameId(int wrapped) {
10145 return static_cast<StackFrame::Id>(wrapped << 2);
10149 // Adds a JavaScript function as a debug event listener.
10150 // args[0]: debug event listener function to set or null or undefined for
10151 // clearing the event listener function
10152 // args[1]: object supplied during callback
10153 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
10154 ASSERT(args.length() == 2);
10155 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10156 args[0]->IsUndefined() ||
10157 args[0]->IsNull());
10158 Handle<Object> callback = args.at<Object>(0);
10159 Handle<Object> data = args.at<Object>(1);
10160 isolate->debugger()->SetEventListener(callback, data);
10162 return isolate->heap()->undefined_value();
10166 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
10167 ASSERT(args.length() == 0);
10168 isolate->stack_guard()->DebugBreak();
10169 return isolate->heap()->undefined_value();
10173 static MaybeObject* DebugLookupResultValue(Heap* heap,
10176 LookupResult* result,
10177 bool* caught_exception) {
10179 switch (result->type()) {
10181 value = result->holder()->GetNormalizedProperty(result);
10182 if (value->IsTheHole()) {
10183 return heap->undefined_value();
10189 result->holder())->FastPropertyAt(result->GetFieldIndex());
10190 if (value->IsTheHole()) {
10191 return heap->undefined_value();
10194 case CONSTANT_FUNCTION:
10195 return result->GetConstantFunction();
10197 Object* structure = result->GetCallbackObject();
10198 if (structure->IsForeign() || structure->IsAccessorInfo()) {
10199 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10200 receiver, structure, name);
10201 if (!maybe_value->ToObject(&value)) {
10202 if (maybe_value->IsRetryAfterGC()) return maybe_value;
10203 ASSERT(maybe_value->IsException());
10204 maybe_value = heap->isolate()->pending_exception();
10205 heap->isolate()->clear_pending_exception();
10206 if (caught_exception != NULL) {
10207 *caught_exception = true;
10209 return maybe_value;
10213 return heap->undefined_value();
10217 case MAP_TRANSITION:
10218 case ELEMENTS_TRANSITION:
10219 case CONSTANT_TRANSITION:
10220 case NULL_DESCRIPTOR:
10221 return heap->undefined_value();
10224 return heap->undefined_value();
10226 UNREACHABLE(); // keep the compiler happy
10227 return heap->undefined_value();
10231 // Get debugger related details for an object property.
10232 // args[0]: object holding property
10233 // args[1]: name of the property
10235 // The array returned contains the following information:
10236 // 0: Property value
10237 // 1: Property details
10238 // 2: Property value is exception
10239 // 3: Getter function if defined
10240 // 4: Setter function if defined
10241 // Items 2-4 are only filled if the property has either a getter or a setter
10242 // defined through __defineGetter__ and/or __defineSetter__.
10243 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
10244 HandleScope scope(isolate);
10246 ASSERT(args.length() == 2);
10248 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10249 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
10251 // Make sure to set the current context to the context before the debugger was
10252 // entered (if the debugger is entered). The reason for switching context here
10253 // is that for some property lookups (accessors and interceptors) callbacks
10254 // into the embedding application can occour, and the embedding application
10255 // could have the assumption that its own global context is the current
10256 // context and not some internal debugger context.
10257 SaveContext save(isolate);
10258 if (isolate->debug()->InDebugger()) {
10259 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
10262 // Skip the global proxy as it has no properties and always delegates to the
10263 // real global object.
10264 if (obj->IsJSGlobalProxy()) {
10265 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10269 // Check if the name is trivially convertible to an index and get the element
10272 if (name->AsArrayIndex(&index)) {
10273 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
10274 Object* element_or_char;
10275 { MaybeObject* maybe_element_or_char =
10276 Runtime::GetElementOrCharAt(isolate, obj, index);
10277 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10278 return maybe_element_or_char;
10281 details->set(0, element_or_char);
10282 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
10283 return *isolate->factory()->NewJSArrayWithElements(details);
10286 // Find the number of objects making up this.
10287 int length = LocalPrototypeChainLength(*obj);
10289 // Try local lookup on each of the objects.
10290 Handle<JSObject> jsproto = obj;
10291 for (int i = 0; i < length; i++) {
10292 LookupResult result(isolate);
10293 jsproto->LocalLookup(*name, &result);
10294 if (result.IsProperty()) {
10295 // LookupResult is not GC safe as it holds raw object pointers.
10296 // GC can happen later in this code so put the required fields into
10297 // local variables using handles when required for later use.
10298 PropertyType result_type = result.type();
10299 Handle<Object> result_callback_obj;
10300 if (result_type == CALLBACKS) {
10301 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10304 Smi* property_details = result.GetPropertyDetails().AsSmi();
10305 // DebugLookupResultValue can cause GC so details from LookupResult needs
10306 // to be copied to handles before this.
10307 bool caught_exception = false;
10309 { MaybeObject* maybe_raw_value =
10310 DebugLookupResultValue(isolate->heap(), *obj, *name,
10311 &result, &caught_exception);
10312 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10314 Handle<Object> value(raw_value, isolate);
10316 // If the callback object is a fixed array then it contains JavaScript
10317 // getter and/or setter.
10318 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10319 result_callback_obj->IsAccessorPair();
10320 Handle<FixedArray> details =
10321 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
10322 details->set(0, *value);
10323 details->set(1, property_details);
10324 if (hasJavaScriptAccessors) {
10325 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
10326 details->set(2, isolate->heap()->ToBoolean(caught_exception));
10327 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10328 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
10331 return *isolate->factory()->NewJSArrayWithElements(details);
10333 if (i < length - 1) {
10334 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10338 return isolate->heap()->undefined_value();
10342 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
10343 HandleScope scope(isolate);
10345 ASSERT(args.length() == 2);
10347 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10348 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
10350 LookupResult result(isolate);
10351 obj->Lookup(*name, &result);
10352 if (result.IsProperty()) {
10353 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
10355 return isolate->heap()->undefined_value();
10359 // Return the property type calculated from the property details.
10360 // args[0]: smi with property details.
10361 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
10362 ASSERT(args.length() == 1);
10363 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10364 return Smi::FromInt(static_cast<int>(details.type()));
10368 // Return the property attribute calculated from the property details.
10369 // args[0]: smi with property details.
10370 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
10371 ASSERT(args.length() == 1);
10372 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10373 return Smi::FromInt(static_cast<int>(details.attributes()));
10377 // Return the property insertion index calculated from the property details.
10378 // args[0]: smi with property details.
10379 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
10380 ASSERT(args.length() == 1);
10381 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10382 return Smi::FromInt(details.index());
10386 // Return property value from named interceptor.
10388 // args[1]: property name
10389 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
10390 HandleScope scope(isolate);
10391 ASSERT(args.length() == 2);
10392 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10393 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10394 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
10396 PropertyAttributes attributes;
10397 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
10401 // Return element value from indexed interceptor.
10404 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
10405 HandleScope scope(isolate);
10406 ASSERT(args.length() == 2);
10407 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10408 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10409 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10411 return obj->GetElementWithInterceptor(*obj, index);
10415 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
10416 ASSERT(args.length() >= 1);
10417 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
10418 // Check that the break id is valid.
10419 if (isolate->debug()->break_id() == 0 ||
10420 break_id != isolate->debug()->break_id()) {
10421 return isolate->Throw(
10422 isolate->heap()->illegal_execution_state_symbol());
10425 return isolate->heap()->true_value();
10429 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
10430 HandleScope scope(isolate);
10431 ASSERT(args.length() == 1);
10433 // Check arguments.
10435 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10436 RUNTIME_ARGUMENTS(isolate, args));
10437 if (!maybe_result->ToObject(&result)) return maybe_result;
10440 // Count all frames which are relevant to debugging stack trace.
10442 StackFrame::Id id = isolate->debug()->break_frame_id();
10443 if (id == StackFrame::NO_ID) {
10444 // If there is no JavaScript stack frame count is 0.
10445 return Smi::FromInt(0);
10448 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10449 n += it.frame()->GetInlineCount();
10451 return Smi::FromInt(n);
10455 class FrameInspector {
10457 FrameInspector(JavaScriptFrame* frame,
10458 int inlined_jsframe_index,
10460 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10461 // Calculate the deoptimized frame.
10462 if (frame->is_optimized()) {
10463 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10464 frame, inlined_jsframe_index, isolate);
10466 has_adapted_arguments_ = frame_->has_adapted_arguments();
10467 is_bottommost_ = inlined_jsframe_index == 0;
10468 is_optimized_ = frame_->is_optimized();
10471 ~FrameInspector() {
10472 // Get rid of the calculated deoptimized frame if any.
10473 if (deoptimized_frame_ != NULL) {
10474 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10479 int GetParametersCount() {
10480 return is_optimized_
10481 ? deoptimized_frame_->parameters_count()
10482 : frame_->ComputeParametersCount();
10484 int expression_count() { return deoptimized_frame_->expression_count(); }
10485 Object* GetFunction() {
10486 return is_optimized_
10487 ? deoptimized_frame_->GetFunction()
10488 : frame_->function();
10490 Object* GetParameter(int index) {
10491 return is_optimized_
10492 ? deoptimized_frame_->GetParameter(index)
10493 : frame_->GetParameter(index);
10495 Object* GetExpression(int index) {
10496 return is_optimized_
10497 ? deoptimized_frame_->GetExpression(index)
10498 : frame_->GetExpression(index);
10500 int GetSourcePosition() {
10501 return is_optimized_
10502 ? deoptimized_frame_->GetSourcePosition()
10503 : frame_->LookupCode()->SourcePosition(frame_->pc());
10505 bool IsConstructor() {
10506 return is_optimized_ && !is_bottommost_
10507 ? deoptimized_frame_->HasConstructStub()
10508 : frame_->IsConstructor();
10511 // To inspect all the provided arguments the frame might need to be
10512 // replaced with the arguments frame.
10513 void SetArgumentsFrame(JavaScriptFrame* frame) {
10514 ASSERT(has_adapted_arguments_);
10516 is_optimized_ = frame_->is_optimized();
10517 ASSERT(!is_optimized_);
10521 JavaScriptFrame* frame_;
10522 DeoptimizedFrameInfo* deoptimized_frame_;
10524 bool is_optimized_;
10525 bool is_bottommost_;
10526 bool has_adapted_arguments_;
10528 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10532 static const int kFrameDetailsFrameIdIndex = 0;
10533 static const int kFrameDetailsReceiverIndex = 1;
10534 static const int kFrameDetailsFunctionIndex = 2;
10535 static const int kFrameDetailsArgumentCountIndex = 3;
10536 static const int kFrameDetailsLocalCountIndex = 4;
10537 static const int kFrameDetailsSourcePositionIndex = 5;
10538 static const int kFrameDetailsConstructCallIndex = 6;
10539 static const int kFrameDetailsAtReturnIndex = 7;
10540 static const int kFrameDetailsFlagsIndex = 8;
10541 static const int kFrameDetailsFirstDynamicIndex = 9;
10544 static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10545 JavaScriptFrame* frame) {
10546 SaveContext* save = isolate->save_context();
10547 while (save != NULL && !save->IsBelowFrame(frame)) {
10548 save = save->prev();
10550 ASSERT(save != NULL);
10555 // Return an array with frame details
10556 // args[0]: number: break id
10557 // args[1]: number: frame index
10559 // The array returned contains the following information:
10563 // 3: Argument count
10565 // 5: Source position
10566 // 6: Constructor call
10569 // Arguments name, value
10570 // Locals name, value
10571 // Return value if any
10572 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
10573 HandleScope scope(isolate);
10574 ASSERT(args.length() == 2);
10576 // Check arguments.
10578 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10579 RUNTIME_ARGUMENTS(isolate, args));
10580 if (!maybe_check->ToObject(&check)) return maybe_check;
10582 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10583 Heap* heap = isolate->heap();
10585 // Find the relevant frame with the requested index.
10586 StackFrame::Id id = isolate->debug()->break_frame_id();
10587 if (id == StackFrame::NO_ID) {
10588 // If there are no JavaScript stack frames return undefined.
10589 return heap->undefined_value();
10593 JavaScriptFrameIterator it(isolate, id);
10594 for (; !it.done(); it.Advance()) {
10595 if (index < count + it.frame()->GetInlineCount()) break;
10596 count += it.frame()->GetInlineCount();
10598 if (it.done()) return heap->undefined_value();
10600 bool is_optimized = it.frame()->is_optimized();
10602 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10603 if (is_optimized) {
10604 inlined_jsframe_index =
10605 it.frame()->GetInlineCount() - (index - count) - 1;
10607 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
10609 // Traverse the saved contexts chain to find the active context for the
10611 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
10613 // Get the frame id.
10614 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
10616 // Find source position in unoptimized code.
10617 int position = frame_inspector.GetSourcePosition();
10619 // Check for constructor frame.
10620 bool constructor = frame_inspector.IsConstructor();
10622 // Get scope info and read from it for local variable information.
10623 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
10624 Handle<SharedFunctionInfo> shared(function->shared());
10625 Handle<ScopeInfo> scope_info(shared->scope_info());
10626 ASSERT(*scope_info != ScopeInfo::Empty());
10628 // Get the locals names and values into a temporary array.
10630 // TODO(1240907): Hide compiler-introduced stack variables
10631 // (e.g. .result)? For users of the debugger, they will probably be
10633 Handle<FixedArray> locals =
10634 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
10636 // Fill in the values of the locals.
10638 for (; i < scope_info->StackLocalCount(); ++i) {
10639 // Use the value from the stack.
10640 locals->set(i * 2, scope_info->LocalName(i));
10641 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
10643 if (i < scope_info->LocalCount()) {
10644 // Get the context containing declarations.
10645 Handle<Context> context(
10646 Context::cast(it.frame()->context())->declaration_context());
10647 for (; i < scope_info->LocalCount(); ++i) {
10648 Handle<String> name(scope_info->LocalName(i));
10650 InitializationFlag init_flag;
10651 locals->set(i * 2, *name);
10652 locals->set(i * 2 + 1, context->get(
10653 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
10657 // Check whether this frame is positioned at return. If not top
10658 // frame or if the frame is optimized it cannot be at a return.
10659 bool at_return = false;
10660 if (!is_optimized && index == 0) {
10661 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
10664 // If positioned just before return find the value to be returned and add it
10665 // to the frame information.
10666 Handle<Object> return_value = isolate->factory()->undefined_value();
10668 StackFrameIterator it2(isolate);
10669 Address internal_frame_sp = NULL;
10670 while (!it2.done()) {
10671 if (it2.frame()->is_internal()) {
10672 internal_frame_sp = it2.frame()->sp();
10674 if (it2.frame()->is_java_script()) {
10675 if (it2.frame()->id() == it.frame()->id()) {
10676 // The internal frame just before the JavaScript frame contains the
10677 // value to return on top. A debug break at return will create an
10678 // internal frame to store the return value (eax/rax/r0) before
10679 // entering the debug break exit frame.
10680 if (internal_frame_sp != NULL) {
10682 Handle<Object>(Memory::Object_at(internal_frame_sp),
10689 // Indicate that the previous frame was not an internal frame.
10690 internal_frame_sp = NULL;
10696 // Now advance to the arguments adapter frame (if any). It contains all
10697 // the provided parameters whereas the function frame always have the number
10698 // of arguments matching the functions parameters. The rest of the
10699 // information (except for what is collected above) is the same.
10700 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
10701 it.AdvanceToArgumentsFrame();
10702 frame_inspector.SetArgumentsFrame(it.frame());
10705 // Find the number of arguments to fill. At least fill the number of
10706 // parameters for the function and fill more if more parameters are provided.
10707 int argument_count = scope_info->ParameterCount();
10708 if (argument_count < frame_inspector.GetParametersCount()) {
10709 argument_count = frame_inspector.GetParametersCount();
10712 // Calculate the size of the result.
10713 int details_size = kFrameDetailsFirstDynamicIndex +
10714 2 * (argument_count + scope_info->LocalCount()) +
10715 (at_return ? 1 : 0);
10716 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
10718 // Add the frame id.
10719 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10721 // Add the function (same as in function frame).
10722 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
10724 // Add the arguments count.
10725 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10727 // Add the locals count
10728 details->set(kFrameDetailsLocalCountIndex,
10729 Smi::FromInt(scope_info->LocalCount()));
10731 // Add the source position.
10732 if (position != RelocInfo::kNoPosition) {
10733 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10735 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
10738 // Add the constructor information.
10739 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
10741 // Add the at return information.
10742 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
10744 // Add flags to indicate information on whether this frame is
10745 // bit 0: invoked in the debugger context.
10746 // bit 1: optimized frame.
10747 // bit 2: inlined in optimized frame
10749 if (*save->context() == *isolate->debug()->debug_context()) {
10752 if (is_optimized) {
10754 flags |= inlined_jsframe_index << 2;
10756 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
10758 // Fill the dynamic part.
10759 int details_index = kFrameDetailsFirstDynamicIndex;
10761 // Add arguments name and value.
10762 for (int i = 0; i < argument_count; i++) {
10763 // Name of the argument.
10764 if (i < scope_info->ParameterCount()) {
10765 details->set(details_index++, scope_info->ParameterName(i));
10767 details->set(details_index++, heap->undefined_value());
10770 // Parameter value.
10771 if (i < frame_inspector.GetParametersCount()) {
10772 // Get the value from the stack.
10773 details->set(details_index++, frame_inspector.GetParameter(i));
10775 details->set(details_index++, heap->undefined_value());
10779 // Add locals name and value from the temporary copy from the function frame.
10780 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
10781 details->set(details_index++, locals->get(i));
10784 // Add the value being returned.
10786 details->set(details_index++, *return_value);
10789 // Add the receiver (same as in function frame).
10790 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10791 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
10792 Handle<Object> receiver(it.frame()->receiver(), isolate);
10793 if (!receiver->IsJSObject() &&
10794 shared->is_classic_mode() &&
10795 !shared->native()) {
10796 // If the receiver is not a JSObject and the function is not a
10797 // builtin or strict-mode we have hit an optimization where a
10798 // value object is not converted into a wrapped JS objects. To
10799 // hide this optimization from the debugger, we wrap the receiver
10800 // by creating correct wrapper object based on the calling frame's
10803 Handle<Context> calling_frames_global_context(
10804 Context::cast(Context::cast(it.frame()->context())->global_context()));
10806 isolate->factory()->ToObject(receiver, calling_frames_global_context);
10808 details->set(kFrameDetailsReceiverIndex, *receiver);
10810 ASSERT_EQ(details_size, details_index);
10811 return *isolate->factory()->NewJSArrayWithElements(details);
10815 // Copy all the context locals into an object used to materialize a scope.
10816 static bool CopyContextLocalsToScopeObject(
10818 Handle<ScopeInfo> scope_info,
10819 Handle<Context> context,
10820 Handle<JSObject> scope_object) {
10821 // Fill all context locals to the context extension.
10822 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10824 InitializationFlag init_flag;
10825 int context_index = scope_info->ContextSlotIndex(
10826 scope_info->ContextLocalName(i), &mode, &init_flag);
10828 RETURN_IF_EMPTY_HANDLE_VALUE(
10830 SetProperty(scope_object,
10831 Handle<String>(scope_info->ContextLocalName(i)),
10832 Handle<Object>(context->get(context_index), isolate),
10842 // Create a plain JSObject which materializes the local scope for the specified
10844 static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
10846 JavaScriptFrame* frame,
10847 FrameInspector* frame_inspector) {
10848 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
10849 Handle<SharedFunctionInfo> shared(function->shared());
10850 Handle<ScopeInfo> scope_info(shared->scope_info());
10852 // Allocate and initialize a JSObject with all the arguments, stack locals
10853 // heap locals and extension properties of the debugged function.
10854 Handle<JSObject> local_scope =
10855 isolate->factory()->NewJSObject(isolate->object_function());
10857 // First fill all parameters.
10858 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
10859 Handle<Object> value(
10860 i < frame_inspector->GetParametersCount() ?
10861 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10863 RETURN_IF_EMPTY_HANDLE_VALUE(
10865 SetProperty(local_scope,
10866 Handle<String>(scope_info->ParameterName(i)),
10870 Handle<JSObject>());
10873 // Second fill all stack locals.
10874 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
10875 RETURN_IF_EMPTY_HANDLE_VALUE(
10877 SetProperty(local_scope,
10878 Handle<String>(scope_info->StackLocalName(i)),
10879 Handle<Object>(frame_inspector->GetExpression(i)),
10882 Handle<JSObject>());
10885 if (scope_info->HasContext()) {
10886 // Third fill all context locals.
10887 Handle<Context> frame_context(Context::cast(frame->context()));
10888 Handle<Context> function_context(frame_context->declaration_context());
10889 if (!CopyContextLocalsToScopeObject(
10890 isolate, scope_info, function_context, local_scope)) {
10891 return Handle<JSObject>();
10894 // Finally copy any properties from the function context extension.
10895 // These will be variables introduced by eval.
10896 if (function_context->closure() == *function) {
10897 if (function_context->has_extension() &&
10898 !function_context->IsGlobalContext()) {
10899 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10900 bool threw = false;
10901 Handle<FixedArray> keys =
10902 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10903 if (threw) return Handle<JSObject>();
10905 for (int i = 0; i < keys->length(); i++) {
10906 // Names of variables introduced by eval are strings.
10907 ASSERT(keys->get(i)->IsString());
10908 Handle<String> key(String::cast(keys->get(i)));
10909 RETURN_IF_EMPTY_HANDLE_VALUE(
10911 SetProperty(local_scope,
10913 GetProperty(ext, key),
10916 Handle<JSObject>());
10922 return local_scope;
10926 static Handle<JSObject> MaterializeLocalScope(
10928 JavaScriptFrame* frame,
10929 int inlined_jsframe_index) {
10930 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10931 return MaterializeLocalScopeWithFrameInspector(isolate,
10937 // Create a plain JSObject which materializes the closure content for the
10939 static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10940 Handle<Context> context) {
10941 ASSERT(context->IsFunctionContext());
10943 Handle<SharedFunctionInfo> shared(context->closure()->shared());
10944 Handle<ScopeInfo> scope_info(shared->scope_info());
10946 // Allocate and initialize a JSObject with all the content of this function
10948 Handle<JSObject> closure_scope =
10949 isolate->factory()->NewJSObject(isolate->object_function());
10951 // Fill all context locals to the context extension.
10952 if (!CopyContextLocalsToScopeObject(
10953 isolate, scope_info, context, closure_scope)) {
10954 return Handle<JSObject>();
10957 // Finally copy any properties from the function context extension. This will
10958 // be variables introduced by eval.
10959 if (context->has_extension()) {
10960 Handle<JSObject> ext(JSObject::cast(context->extension()));
10961 bool threw = false;
10962 Handle<FixedArray> keys =
10963 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10964 if (threw) return Handle<JSObject>();
10966 for (int i = 0; i < keys->length(); i++) {
10967 // Names of variables introduced by eval are strings.
10968 ASSERT(keys->get(i)->IsString());
10969 Handle<String> key(String::cast(keys->get(i)));
10970 RETURN_IF_EMPTY_HANDLE_VALUE(
10972 SetProperty(closure_scope,
10974 GetProperty(ext, key),
10977 Handle<JSObject>());
10981 return closure_scope;
10985 // Create a plain JSObject which materializes the scope for the specified
10987 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10988 Handle<Context> context) {
10989 ASSERT(context->IsCatchContext());
10990 Handle<String> name(String::cast(context->extension()));
10991 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10992 Handle<JSObject> catch_scope =
10993 isolate->factory()->NewJSObject(isolate->object_function());
10994 RETURN_IF_EMPTY_HANDLE_VALUE(
10996 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10997 Handle<JSObject>());
10998 return catch_scope;
11002 // Create a plain JSObject which materializes the block scope for the specified
11004 static Handle<JSObject> MaterializeBlockScope(
11006 Handle<Context> context) {
11007 ASSERT(context->IsBlockContext());
11008 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11010 // Allocate and initialize a JSObject with all the arguments, stack locals
11011 // heap locals and extension properties of the debugged function.
11012 Handle<JSObject> block_scope =
11013 isolate->factory()->NewJSObject(isolate->object_function());
11015 // Fill all context locals.
11016 if (!CopyContextLocalsToScopeObject(
11017 isolate, scope_info, context, block_scope)) {
11018 return Handle<JSObject>();
11021 return block_scope;
11025 // Create a plain JSObject which materializes the module scope for the specified
11027 static Handle<JSObject> MaterializeModuleScope(
11029 Handle<Context> context) {
11030 ASSERT(context->IsModuleContext());
11031 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11033 // Allocate and initialize a JSObject with all the members of the debugged
11035 Handle<JSObject> module_scope =
11036 isolate->factory()->NewJSObject(isolate->object_function());
11038 // Fill all context locals.
11039 if (!CopyContextLocalsToScopeObject(
11040 isolate, scope_info, context, module_scope)) {
11041 return Handle<JSObject>();
11044 return module_scope;
11048 // Iterate over the actual scopes visible from a stack frame or from a closure.
11049 // The iteration proceeds from the innermost visible nested scope outwards.
11050 // All scopes are backed by an actual context except the local scope,
11051 // which is inserted "artificially" in the context chain.
11052 class ScopeIterator {
11055 ScopeTypeGlobal = 0,
11064 ScopeIterator(Isolate* isolate,
11065 JavaScriptFrame* frame,
11066 int inlined_jsframe_index)
11067 : isolate_(isolate),
11069 inlined_jsframe_index_(inlined_jsframe_index),
11070 function_(JSFunction::cast(frame->function())),
11071 context_(Context::cast(frame->context())),
11072 nested_scope_chain_(4) {
11074 // Catch the case when the debugger stops in an internal function.
11075 Handle<SharedFunctionInfo> shared_info(function_->shared());
11076 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11077 if (shared_info->script() == isolate->heap()->undefined_value()) {
11078 while (context_->closure() == *function_) {
11079 context_ = Handle<Context>(context_->previous(), isolate_);
11084 // Get the debug info (create it if it does not exist).
11085 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11086 // Return if ensuring debug info failed.
11089 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11091 // Find the break point where execution has stopped.
11092 BreakLocationIterator break_location_iterator(debug_info,
11093 ALL_BREAK_LOCATIONS);
11094 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11095 if (break_location_iterator.IsExit()) {
11096 // We are within the return sequence. At the momemt it is not possible to
11097 // get a source position which is consistent with the current scope chain.
11098 // Thus all nested with, catch and block contexts are skipped and we only
11099 // provide the function scope.
11100 if (scope_info->HasContext()) {
11101 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11103 while (context_->closure() == *function_) {
11104 context_ = Handle<Context>(context_->previous(), isolate_);
11107 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11109 // Reparse the code and analyze the scopes.
11110 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11111 Handle<Script> script(Script::cast(shared_info->script()));
11112 Scope* scope = NULL;
11114 // Check whether we are in global, eval or function code.
11115 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11116 if (scope_info->Type() != FUNCTION_SCOPE) {
11117 // Global or eval code.
11118 CompilationInfo info(script);
11119 if (scope_info->Type() == GLOBAL_SCOPE) {
11120 info.MarkAsGlobal();
11122 ASSERT(scope_info->Type() == EVAL_SCOPE);
11124 info.SetCallingContext(Handle<Context>(function_->context()));
11126 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11127 scope = info.function()->scope();
11131 CompilationInfo info(shared_info);
11132 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11133 scope = info.function()->scope();
11137 // Retrieve the scope chain for the current position.
11138 if (scope != NULL) {
11139 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11140 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11142 // A failed reparse indicates that the preparser has diverged from the
11143 // parser or that the preparse data given to the initial parse has been
11144 // faulty. We fail in debug mode but in release mode we only provide the
11145 // information we get from the context chain but nothing about
11146 // completely stack allocated scopes or stack allocated locals.
11152 ScopeIterator(Isolate* isolate,
11153 Handle<JSFunction> function)
11154 : isolate_(isolate),
11156 inlined_jsframe_index_(0),
11157 function_(function),
11158 context_(function->context()) {
11159 if (function->IsBuiltin()) {
11160 context_ = Handle<Context>();
11165 bool Done() { return context_.is_null(); }
11167 // Move to the next scope.
11169 ScopeType scope_type = Type();
11170 if (scope_type == ScopeTypeGlobal) {
11171 // The global scope is always the last in the chain.
11172 ASSERT(context_->IsGlobalContext());
11173 context_ = Handle<Context>();
11176 if (nested_scope_chain_.is_empty()) {
11177 context_ = Handle<Context>(context_->previous(), isolate_);
11179 if (nested_scope_chain_.last()->HasContext()) {
11180 ASSERT(context_->previous() != NULL);
11181 context_ = Handle<Context>(context_->previous(), isolate_);
11183 nested_scope_chain_.RemoveLast();
11187 // Return the type of the current scope.
11189 if (!nested_scope_chain_.is_empty()) {
11190 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11191 switch (scope_info->Type()) {
11192 case FUNCTION_SCOPE:
11193 ASSERT(context_->IsFunctionContext() ||
11194 !scope_info->HasContext());
11195 return ScopeTypeLocal;
11197 ASSERT(context_->IsModuleContext());
11198 return ScopeTypeModule;
11200 ASSERT(context_->IsGlobalContext());
11201 return ScopeTypeGlobal;
11203 ASSERT(context_->IsWithContext());
11204 return ScopeTypeWith;
11206 ASSERT(context_->IsCatchContext());
11207 return ScopeTypeCatch;
11209 ASSERT(!scope_info->HasContext() ||
11210 context_->IsBlockContext());
11211 return ScopeTypeBlock;
11216 if (context_->IsGlobalContext()) {
11217 ASSERT(context_->global()->IsGlobalObject());
11218 return ScopeTypeGlobal;
11220 if (context_->IsFunctionContext()) {
11221 return ScopeTypeClosure;
11223 if (context_->IsCatchContext()) {
11224 return ScopeTypeCatch;
11226 if (context_->IsBlockContext()) {
11227 return ScopeTypeBlock;
11229 if (context_->IsModuleContext()) {
11230 return ScopeTypeModule;
11232 ASSERT(context_->IsWithContext());
11233 return ScopeTypeWith;
11236 // Return the JavaScript object with the content of the current scope.
11237 Handle<JSObject> ScopeObject() {
11239 case ScopeIterator::ScopeTypeGlobal:
11240 return Handle<JSObject>(CurrentContext()->global());
11241 case ScopeIterator::ScopeTypeLocal:
11242 // Materialize the content of the local scope into a JSObject.
11243 ASSERT(nested_scope_chain_.length() == 1);
11244 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
11245 case ScopeIterator::ScopeTypeWith:
11246 // Return the with object.
11247 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11248 case ScopeIterator::ScopeTypeCatch:
11249 return MaterializeCatchScope(isolate_, CurrentContext());
11250 case ScopeIterator::ScopeTypeClosure:
11251 // Materialize the content of the closure scope into a JSObject.
11252 return MaterializeClosure(isolate_, CurrentContext());
11253 case ScopeIterator::ScopeTypeBlock:
11254 return MaterializeBlockScope(isolate_, CurrentContext());
11255 case ScopeIterator::ScopeTypeModule:
11256 return MaterializeModuleScope(isolate_, CurrentContext());
11259 return Handle<JSObject>();
11262 Handle<ScopeInfo> CurrentScopeInfo() {
11263 if (!nested_scope_chain_.is_empty()) {
11264 return nested_scope_chain_.last();
11265 } else if (context_->IsBlockContext()) {
11266 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11267 } else if (context_->IsFunctionContext()) {
11268 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11270 return Handle<ScopeInfo>::null();
11273 // Return the context for this scope. For the local context there might not
11274 // be an actual context.
11275 Handle<Context> CurrentContext() {
11276 if (Type() == ScopeTypeGlobal ||
11277 nested_scope_chain_.is_empty()) {
11279 } else if (nested_scope_chain_.last()->HasContext()) {
11282 return Handle<Context>();
11287 // Debug print of the content of the current scope.
11288 void DebugPrint() {
11290 case ScopeIterator::ScopeTypeGlobal:
11291 PrintF("Global:\n");
11292 CurrentContext()->Print();
11295 case ScopeIterator::ScopeTypeLocal: {
11296 PrintF("Local:\n");
11297 function_->shared()->scope_info()->Print();
11298 if (!CurrentContext().is_null()) {
11299 CurrentContext()->Print();
11300 if (CurrentContext()->has_extension()) {
11301 Handle<Object> extension(CurrentContext()->extension());
11302 if (extension->IsJSContextExtensionObject()) {
11303 extension->Print();
11310 case ScopeIterator::ScopeTypeWith:
11312 CurrentContext()->extension()->Print();
11315 case ScopeIterator::ScopeTypeCatch:
11316 PrintF("Catch:\n");
11317 CurrentContext()->extension()->Print();
11318 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
11321 case ScopeIterator::ScopeTypeClosure:
11322 PrintF("Closure:\n");
11323 CurrentContext()->Print();
11324 if (CurrentContext()->has_extension()) {
11325 Handle<Object> extension(CurrentContext()->extension());
11326 if (extension->IsJSContextExtensionObject()) {
11327 extension->Print();
11341 JavaScriptFrame* frame_;
11342 int inlined_jsframe_index_;
11343 Handle<JSFunction> function_;
11344 Handle<Context> context_;
11345 List<Handle<ScopeInfo> > nested_scope_chain_;
11347 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11351 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
11352 HandleScope scope(isolate);
11353 ASSERT(args.length() == 2);
11355 // Check arguments.
11357 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11358 RUNTIME_ARGUMENTS(isolate, args));
11359 if (!maybe_check->ToObject(&check)) return maybe_check;
11361 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11363 // Get the frame where the debugging is performed.
11364 StackFrame::Id id = UnwrapFrameId(wrapped_id);
11365 JavaScriptFrameIterator it(isolate, id);
11366 JavaScriptFrame* frame = it.frame();
11368 // Count the visible scopes.
11370 for (ScopeIterator it(isolate, frame, 0);
11376 return Smi::FromInt(n);
11380 static const int kScopeDetailsTypeIndex = 0;
11381 static const int kScopeDetailsObjectIndex = 1;
11382 static const int kScopeDetailsSize = 2;
11385 static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
11386 ScopeIterator* it) {
11387 // Calculate the size of the result.
11388 int details_size = kScopeDetailsSize;
11389 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
11391 // Fill in scope details.
11392 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
11393 Handle<JSObject> scope_object = it->ScopeObject();
11394 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
11395 details->set(kScopeDetailsObjectIndex, *scope_object);
11397 return *isolate->factory()->NewJSArrayWithElements(details);
11400 // Return an array with scope details
11401 // args[0]: number: break id
11402 // args[1]: number: frame index
11403 // args[2]: number: inlined frame index
11404 // args[3]: number: scope index
11406 // The array returned contains the following information:
11409 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
11410 HandleScope scope(isolate);
11411 ASSERT(args.length() == 4);
11413 // Check arguments.
11415 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11416 RUNTIME_ARGUMENTS(isolate, args));
11417 if (!maybe_check->ToObject(&check)) return maybe_check;
11419 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11420 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
11421 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
11423 // Get the frame where the debugging is performed.
11424 StackFrame::Id id = UnwrapFrameId(wrapped_id);
11425 JavaScriptFrameIterator frame_it(isolate, id);
11426 JavaScriptFrame* frame = frame_it.frame();
11428 // Find the requested scope.
11430 ScopeIterator it(isolate, frame, inlined_jsframe_index);
11431 for (; !it.Done() && n < index; it.Next()) {
11435 return isolate->heap()->undefined_value();
11437 return MaterializeScopeDetails(isolate, &it);
11441 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
11442 HandleScope scope(isolate);
11443 ASSERT(args.length() == 1);
11445 // Check arguments.
11446 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11448 // Count the visible scopes.
11450 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
11454 return Smi::FromInt(n);
11458 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
11459 HandleScope scope(isolate);
11460 ASSERT(args.length() == 2);
11462 // Check arguments.
11463 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11464 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11466 // Find the requested scope.
11468 ScopeIterator it(isolate, fun);
11469 for (; !it.Done() && n < index; it.Next()) {
11473 return isolate->heap()->undefined_value();
11476 return MaterializeScopeDetails(isolate, &it);
11480 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
11481 HandleScope scope(isolate);
11482 ASSERT(args.length() == 0);
11485 // Print the scopes for the top frame.
11486 StackFrameLocator locator;
11487 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
11488 for (ScopeIterator it(isolate, frame, 0);
11494 return isolate->heap()->undefined_value();
11498 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
11499 HandleScope scope(isolate);
11500 ASSERT(args.length() == 1);
11502 // Check arguments.
11504 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11505 RUNTIME_ARGUMENTS(isolate, args));
11506 if (!maybe_result->ToObject(&result)) return maybe_result;
11509 // Count all archived V8 threads.
11511 for (ThreadState* thread =
11512 isolate->thread_manager()->FirstThreadStateInUse();
11514 thread = thread->Next()) {
11518 // Total number of threads is current thread and archived threads.
11519 return Smi::FromInt(n + 1);
11523 static const int kThreadDetailsCurrentThreadIndex = 0;
11524 static const int kThreadDetailsThreadIdIndex = 1;
11525 static const int kThreadDetailsSize = 2;
11527 // Return an array with thread details
11528 // args[0]: number: break id
11529 // args[1]: number: thread index
11531 // The array returned contains the following information:
11532 // 0: Is current thread?
11534 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
11535 HandleScope scope(isolate);
11536 ASSERT(args.length() == 2);
11538 // Check arguments.
11540 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11541 RUNTIME_ARGUMENTS(isolate, args));
11542 if (!maybe_check->ToObject(&check)) return maybe_check;
11544 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11546 // Allocate array for result.
11547 Handle<FixedArray> details =
11548 isolate->factory()->NewFixedArray(kThreadDetailsSize);
11550 // Thread index 0 is current thread.
11552 // Fill the details.
11553 details->set(kThreadDetailsCurrentThreadIndex,
11554 isolate->heap()->true_value());
11555 details->set(kThreadDetailsThreadIdIndex,
11556 Smi::FromInt(ThreadId::Current().ToInteger()));
11558 // Find the thread with the requested index.
11560 ThreadState* thread =
11561 isolate->thread_manager()->FirstThreadStateInUse();
11562 while (index != n && thread != NULL) {
11563 thread = thread->Next();
11566 if (thread == NULL) {
11567 return isolate->heap()->undefined_value();
11570 // Fill the details.
11571 details->set(kThreadDetailsCurrentThreadIndex,
11572 isolate->heap()->false_value());
11573 details->set(kThreadDetailsThreadIdIndex,
11574 Smi::FromInt(thread->id().ToInteger()));
11577 // Convert to JS array and return.
11578 return *isolate->factory()->NewJSArrayWithElements(details);
11582 // Sets the disable break state
11583 // args[0]: disable break state
11584 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
11585 HandleScope scope(isolate);
11586 ASSERT(args.length() == 1);
11587 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
11588 isolate->debug()->set_disable_break(disable_break);
11589 return isolate->heap()->undefined_value();
11593 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
11594 HandleScope scope(isolate);
11595 ASSERT(args.length() == 1);
11597 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11598 Handle<SharedFunctionInfo> shared(fun->shared());
11599 // Find the number of break points
11600 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
11601 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
11602 // Return array as JS array
11603 return *isolate->factory()->NewJSArrayWithElements(
11604 Handle<FixedArray>::cast(break_locations));
11608 // Return the value of breakpoint_relocation flag
11609 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllowBreakPointRelocation) {
11610 return Smi::FromInt(FLAG_breakpoint_relocation);
11614 // Set a break point in a function
11615 // args[0]: function
11616 // args[1]: number: break source position (within the function source)
11617 // args[2]: number: break point object
11618 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
11619 HandleScope scope(isolate);
11620 ASSERT(args.length() == 3);
11621 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
11622 Handle<SharedFunctionInfo> shared(fun->shared());
11623 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11624 RUNTIME_ASSERT(source_position >= 0);
11625 Handle<Object> break_point_object_arg = args.at<Object>(2);
11627 // Set break point.
11628 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11631 return Smi::FromInt(source_position);
11635 Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11636 Handle<Script> script,
11638 // Iterate the heap looking for SharedFunctionInfo generated from the
11639 // script. The inner most SharedFunctionInfo containing the source position
11640 // for the requested break point is found.
11641 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
11642 // which is found is not compiled it is compiled and the heap is iterated
11643 // again as the compilation might create inner functions from the newly
11644 // compiled function and the actual requested break point might be in one of
11645 // these functions.
11647 // The current candidate for the source position:
11648 int target_start_position = RelocInfo::kNoPosition;
11649 Handle<SharedFunctionInfo> target;
11651 { // Extra scope for iterator and no-allocation.
11652 isolate->heap()->EnsureHeapIsIterable();
11653 AssertNoAllocation no_alloc_during_heap_iteration;
11654 HeapIterator iterator;
11655 for (HeapObject* obj = iterator.next();
11656 obj != NULL; obj = iterator.next()) {
11657 if (obj->IsSharedFunctionInfo()) {
11658 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11659 if (shared->script() == *script) {
11660 // If the SharedFunctionInfo found has the requested script data and
11661 // contains the source position it is a candidate.
11662 int start_position = shared->function_token_position();
11663 if (start_position == RelocInfo::kNoPosition) {
11664 start_position = shared->start_position();
11666 if (start_position <= position &&
11667 position <= shared->end_position()) {
11668 // If there is no candidate or this function is within the current
11669 // candidate this is the new candidate.
11670 if (target.is_null()) {
11671 target_start_position = start_position;
11674 if (target_start_position == start_position &&
11675 shared->end_position() == target->end_position()) {
11676 // If a top-level function contain only one function
11677 // declartion the source for the top-level and the
11678 // function is the same. In that case prefer the non
11679 // top-level function.
11680 if (!shared->is_toplevel()) {
11681 target_start_position = start_position;
11684 } else if (target_start_position <= start_position &&
11685 shared->end_position() <= target->end_position()) {
11686 // This containment check includes equality as a function
11687 // inside a top-level function can share either start or end
11688 // position with the top-level function.
11689 target_start_position = start_position;
11697 } // End No allocation scope.
11699 if (target.is_null()) {
11700 return isolate->heap()->undefined_value();
11703 // If the candidate found is compiled we are done. NOTE: when lazy
11704 // compilation of inner functions is introduced some additional checking
11705 // needs to be done here to compile inner functions.
11706 done = target->is_compiled();
11708 // If the candidate is not compiled compile it to reveal any inner
11709 // functions which might contain the requested source position.
11710 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
11712 } // End while loop.
11718 // Changes the state of a break point in a script and returns source position
11719 // where break point was set. NOTE: Regarding performance see the NOTE for
11720 // GetScriptFromScriptData.
11721 // args[0]: script to set break point in
11722 // args[1]: number: break source position (within the script source)
11723 // args[2]: number: break point object
11724 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
11725 HandleScope scope(isolate);
11726 ASSERT(args.length() == 3);
11727 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
11728 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11729 RUNTIME_ASSERT(source_position >= 0);
11730 Handle<Object> break_point_object_arg = args.at<Object>(2);
11732 // Get the script from the script wrapper.
11733 RUNTIME_ASSERT(wrapper->value()->IsScript());
11734 Handle<Script> script(Script::cast(wrapper->value()));
11736 Object* result = Runtime::FindSharedFunctionInfoInScript(
11737 isolate, script, source_position);
11738 if (!result->IsUndefined()) {
11739 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11740 // Find position within function. The script position might be before the
11741 // source position of the first function.
11743 if (shared->start_position() > source_position) {
11746 position = source_position - shared->start_position();
11748 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
11749 position += shared->start_position();
11750 return Smi::FromInt(position);
11752 return isolate->heap()->undefined_value();
11756 // Clear a break point
11757 // args[0]: number: break point object
11758 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
11759 HandleScope scope(isolate);
11760 ASSERT(args.length() == 1);
11761 Handle<Object> break_point_object_arg = args.at<Object>(0);
11763 // Clear break point.
11764 isolate->debug()->ClearBreakPoint(break_point_object_arg);
11766 return isolate->heap()->undefined_value();
11770 // Change the state of break on exceptions.
11771 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11772 // args[1]: Boolean indicating on/off.
11773 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
11774 HandleScope scope(isolate);
11775 ASSERT(args.length() == 2);
11776 RUNTIME_ASSERT(args[0]->IsNumber());
11777 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
11779 // If the number doesn't match an enum value, the ChangeBreakOnException
11780 // function will default to affecting caught exceptions.
11781 ExceptionBreakType type =
11782 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
11783 // Update break point state.
11784 isolate->debug()->ChangeBreakOnException(type, enable);
11785 return isolate->heap()->undefined_value();
11789 // Returns the state of break on exceptions
11790 // args[0]: boolean indicating uncaught exceptions
11791 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
11792 HandleScope scope(isolate);
11793 ASSERT(args.length() == 1);
11794 RUNTIME_ASSERT(args[0]->IsNumber());
11796 ExceptionBreakType type =
11797 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
11798 bool result = isolate->debug()->IsBreakOnException(type);
11799 return Smi::FromInt(result);
11803 // Prepare for stepping
11804 // args[0]: break id for checking execution state
11805 // args[1]: step action from the enumeration StepAction
11806 // args[2]: number of times to perform the step, for step out it is the number
11807 // of frames to step down.
11808 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
11809 HandleScope scope(isolate);
11810 ASSERT(args.length() == 3);
11811 // Check arguments.
11813 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11814 RUNTIME_ARGUMENTS(isolate, args));
11815 if (!maybe_check->ToObject(&check)) return maybe_check;
11817 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
11818 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
11821 // Get the step action and check validity.
11822 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11823 if (step_action != StepIn &&
11824 step_action != StepNext &&
11825 step_action != StepOut &&
11826 step_action != StepInMin &&
11827 step_action != StepMin) {
11828 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
11831 // Get the number of steps.
11832 int step_count = NumberToInt32(args[2]);
11833 if (step_count < 1) {
11834 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
11837 // Clear all current stepping setup.
11838 isolate->debug()->ClearStepping();
11841 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11843 return isolate->heap()->undefined_value();
11847 // Clear all stepping set by PrepareStep.
11848 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
11849 HandleScope scope(isolate);
11850 ASSERT(args.length() == 0);
11851 isolate->debug()->ClearStepping();
11852 return isolate->heap()->undefined_value();
11856 // Creates a copy of the with context chain. The copy of the context chain is
11857 // is linked to the function context supplied.
11858 static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11859 Handle<JSFunction> function,
11860 Handle<Context> base,
11861 JavaScriptFrame* frame,
11862 int inlined_jsframe_index) {
11863 HandleScope scope(isolate);
11864 List<Handle<ScopeInfo> > scope_chain;
11865 List<Handle<Context> > context_chain;
11867 ScopeIterator it(isolate, frame, inlined_jsframe_index);
11868 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11869 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11870 ASSERT(!it.Done());
11871 scope_chain.Add(it.CurrentScopeInfo());
11872 context_chain.Add(it.CurrentContext());
11875 // At the end of the chain. Return the base context to link to.
11876 Handle<Context> context = base;
11878 // Iteratively copy and or materialize the nested contexts.
11879 while (!scope_chain.is_empty()) {
11880 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11881 Handle<Context> current = context_chain.RemoveLast();
11882 ASSERT(!(scope_info->HasContext() & current.is_null()));
11884 if (scope_info->Type() == CATCH_SCOPE) {
11885 Handle<String> name(String::cast(current->extension()));
11886 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11888 isolate->factory()->NewCatchContext(function,
11892 } else if (scope_info->Type() == BLOCK_SCOPE) {
11893 // Materialize the contents of the block scope into a JSObject.
11894 Handle<JSObject> block_scope_object =
11895 MaterializeBlockScope(isolate, current);
11896 if (block_scope_object.is_null()) {
11897 return Handle<Context>::null();
11899 // Allocate a new function context for the debug evaluation and set the
11900 // extension object.
11901 Handle<Context> new_context =
11902 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11904 new_context->set_extension(*block_scope_object);
11905 new_context->set_previous(*context);
11906 context = new_context;
11908 ASSERT(scope_info->Type() == WITH_SCOPE);
11909 ASSERT(current->IsWithContext());
11910 Handle<JSObject> extension(JSObject::cast(current->extension()));
11912 isolate->factory()->NewWithContext(function, context, extension);
11916 return scope.CloseAndEscape(context);
11920 // Helper function to find or create the arguments object for
11921 // Runtime_DebugEvaluate.
11922 static Handle<Object> GetArgumentsObject(Isolate* isolate,
11923 JavaScriptFrame* frame,
11924 FrameInspector* frame_inspector,
11925 Handle<ScopeInfo> scope_info,
11926 Handle<Context> function_context) {
11927 // Try to find the value of 'arguments' to pass as parameter. If it is not
11928 // found (that is the debugged function does not reference 'arguments' and
11929 // does not support eval) then create an 'arguments' object.
11931 if (scope_info->StackLocalCount() > 0) {
11932 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
11934 return Handle<Object>(frame->GetExpression(index), isolate);
11938 if (scope_info->HasHeapAllocatedLocals()) {
11940 InitializationFlag init_flag;
11941 index = scope_info->ContextSlotIndex(
11942 isolate->heap()->arguments_symbol(), &mode, &init_flag);
11944 return Handle<Object>(function_context->get(index), isolate);
11948 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11949 int length = frame_inspector->GetParametersCount();
11950 Handle<JSObject> arguments =
11951 isolate->factory()->NewArgumentsObject(function, length);
11952 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
11954 AssertNoAllocation no_gc;
11955 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
11956 for (int i = 0; i < length; i++) {
11957 array->set(i, frame_inspector->GetParameter(i), mode);
11959 arguments->set_elements(*array);
11964 static const char kSourceStr[] =
11965 "(function(arguments,__source__){return eval(__source__);})";
11968 // Evaluate a piece of JavaScript in the context of a stack frame for
11969 // debugging. This is accomplished by creating a new context which in its
11970 // extension part has all the parameters and locals of the function on the
11971 // stack frame. A function which calls eval with the code to evaluate is then
11972 // compiled in this context and called in this context. As this context
11973 // replaces the context of the function on the stack frame a new (empty)
11974 // function is created as well to be used as the closure for the context.
11975 // This function and the context acts as replacements for the function on the
11976 // stack frame presenting the same view of the values of parameters and
11977 // local variables as if the piece of JavaScript was evaluated at the point
11978 // where the function on the stack frame is currently stopped.
11979 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
11980 HandleScope scope(isolate);
11982 // Check the execution state and decode arguments frame and source to be
11984 ASSERT(args.length() == 6);
11985 Object* check_result;
11986 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11987 RUNTIME_ARGUMENTS(isolate, args));
11988 if (!maybe_check_result->ToObject(&check_result)) {
11989 return maybe_check_result;
11992 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
11993 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
11994 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11995 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
11996 Handle<Object> additional_context(args[5]);
11998 // Handle the processing of break.
11999 DisableBreak disable_break_save(disable_break);
12001 // Get the frame where the debugging is performed.
12002 StackFrame::Id id = UnwrapFrameId(wrapped_id);
12003 JavaScriptFrameIterator it(isolate, id);
12004 JavaScriptFrame* frame = it.frame();
12005 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12006 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
12007 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
12008 bool qml_mode = function->shared()->qml_mode();
12010 // Traverse the saved contexts chain to find the active context for the
12012 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12014 SaveContext savex(isolate);
12015 isolate->set_context(*(save->context()));
12017 // Create the (empty) function replacing the function on the stack frame for
12018 // the purpose of evaluating in the context created below. It is important
12019 // that this function does not describe any parameters and local variables
12020 // in the context. If it does then this will cause problems with the lookup
12021 // in Context::Lookup, where context slots for parameters and local variables
12022 // are looked at before the extension object.
12023 Handle<JSFunction> go_between =
12024 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12025 isolate->factory()->undefined_value());
12026 go_between->set_context(function->context());
12028 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12029 ASSERT(go_between_scope_info->ParameterCount() == 0);
12030 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
12033 // Materialize the content of the local scope into a JSObject.
12034 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12035 isolate, frame, &frame_inspector);
12036 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
12038 // Allocate a new context for the debug evaluation and set the extension
12040 Handle<Context> context =
12041 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12043 context->set_extension(*local_scope);
12044 // Copy any with contexts present and chain them in front of this context.
12045 Handle<Context> frame_context(Context::cast(frame->context()));
12046 Handle<Context> function_context;
12047 // Get the function's context if it has one.
12048 if (scope_info->HasContext()) {
12049 function_context = Handle<Context>(frame_context->declaration_context());
12051 context = CopyNestedScopeContextChain(isolate,
12055 inlined_jsframe_index);
12057 if (additional_context->IsJSObject()) {
12058 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
12060 isolate->factory()->NewWithContext(go_between, context, extension);
12063 // Wrap the evaluation statement in a new function compiled in the newly
12064 // created context. The function has one parameter which has to be called
12065 // 'arguments'. This it to have access to what would have been 'arguments' in
12066 // the function being debugged.
12067 // function(arguments,__source__) {return eval(__source__);}
12069 Handle<String> function_source =
12070 isolate->factory()->NewStringFromAscii(
12071 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
12073 // Currently, the eval code will be executed in non-strict mode,
12074 // even in the strict code context.
12075 Handle<SharedFunctionInfo> shared =
12076 Compiler::CompileEval(function_source,
12078 context->IsGlobalContext(),
12080 RelocInfo::kNoPosition,
12082 if (shared.is_null()) return Failure::Exception();
12083 Handle<JSFunction> compiled_function =
12084 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
12086 // Invoke the result of the compilation to get the evaluation function.
12087 bool has_pending_exception;
12088 Handle<Object> receiver(frame->receiver(), isolate);
12089 Handle<Object> evaluation_function =
12090 Execution::Call(compiled_function, receiver, 0, NULL,
12091 &has_pending_exception, false,
12092 Handle<Object>(function->context()->qml_global()));
12093 if (has_pending_exception) return Failure::Exception();
12095 Handle<Object> arguments = GetArgumentsObject(isolate,
12101 // Invoke the evaluation function and return the result.
12102 Handle<Object> argv[] = { arguments, source };
12103 Handle<Object> result =
12104 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12108 &has_pending_exception);
12109 if (has_pending_exception) return Failure::Exception();
12111 // Skip the global proxy as it has no properties and always delegates to the
12112 // real global object.
12113 if (result->IsJSGlobalProxy()) {
12114 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12121 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
12122 HandleScope scope(isolate);
12124 // Check the execution state and decode arguments frame and source to be
12126 ASSERT(args.length() == 4);
12127 Object* check_result;
12128 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12129 RUNTIME_ARGUMENTS(isolate, args));
12130 if (!maybe_check_result->ToObject(&check_result)) {
12131 return maybe_check_result;
12134 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12135 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
12136 Handle<Object> additional_context(args[3]);
12138 // Handle the processing of break.
12139 DisableBreak disable_break_save(disable_break);
12141 // Enter the top context from before the debugger was invoked.
12142 SaveContext save(isolate);
12143 SaveContext* top = &save;
12144 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
12148 isolate->set_context(*top->context());
12151 // Get the global context now set to the top context from before the
12152 // debugger was invoked.
12153 Handle<Context> context = isolate->global_context();
12155 bool is_global = true;
12157 if (additional_context->IsJSObject()) {
12158 // Create a new with context with the additional context information between
12159 // the context of the debugged function and the eval code to be executed.
12160 context = isolate->factory()->NewWithContext(
12161 Handle<JSFunction>(context->closure()),
12163 Handle<JSObject>::cast(additional_context));
12167 // Compile the source to be evaluated.
12168 // Currently, the eval code will be executed in non-strict mode,
12169 // even in the strict code context.
12170 Handle<SharedFunctionInfo> shared =
12171 Compiler::CompileEval(source,
12175 RelocInfo::kNoPosition,
12177 if (shared.is_null()) return Failure::Exception();
12178 Handle<JSFunction> compiled_function =
12179 Handle<JSFunction>(
12180 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12183 // Invoke the result of the compilation to get the evaluation function.
12184 bool has_pending_exception;
12185 Handle<Object> receiver = isolate->global();
12186 Handle<Object> result =
12187 Execution::Call(compiled_function, receiver, 0, NULL,
12188 &has_pending_exception);
12189 // Clear the oneshot breakpoints so that the debugger does not step further.
12190 isolate->debug()->ClearStepping();
12191 if (has_pending_exception) return Failure::Exception();
12196 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
12197 HandleScope scope(isolate);
12198 ASSERT(args.length() == 0);
12200 // Fill the script objects.
12201 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
12203 // Convert the script objects to proper JS objects.
12204 for (int i = 0; i < instances->length(); i++) {
12205 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12206 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12208 // instances->set(i, *GetScriptWrapper(script))
12209 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12210 // already have dereferenced the instances handle.
12211 Handle<JSValue> wrapper = GetScriptWrapper(script);
12212 instances->set(i, *wrapper);
12215 // Return result as a JS array.
12216 Handle<JSObject> result =
12217 isolate->factory()->NewJSObject(isolate->array_function());
12218 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
12223 // Helper function used by Runtime_DebugReferencedBy below.
12224 static int DebugReferencedBy(HeapIterator* iterator,
12226 Object* instance_filter, int max_references,
12227 FixedArray* instances, int instances_size,
12228 JSFunction* arguments_function) {
12229 NoHandleAllocation ha;
12230 AssertNoAllocation no_alloc;
12232 // Iterate the heap.
12234 JSObject* last = NULL;
12235 HeapObject* heap_obj = NULL;
12236 while (((heap_obj = iterator->next()) != NULL) &&
12237 (max_references == 0 || count < max_references)) {
12238 // Only look at all JSObjects.
12239 if (heap_obj->IsJSObject()) {
12240 // Skip context extension objects and argument arrays as these are
12241 // checked in the context of functions using them.
12242 JSObject* obj = JSObject::cast(heap_obj);
12243 if (obj->IsJSContextExtensionObject() ||
12244 obj->map()->constructor() == arguments_function) {
12248 // Check if the JS object has a reference to the object looked for.
12249 if (obj->ReferencesObject(target)) {
12250 // Check instance filter if supplied. This is normally used to avoid
12251 // references from mirror objects (see Runtime_IsInPrototypeChain).
12252 if (!instance_filter->IsUndefined()) {
12255 Object* prototype = V->GetPrototype();
12256 if (prototype->IsNull()) {
12259 if (instance_filter == prototype) {
12260 obj = NULL; // Don't add this object.
12268 // Valid reference found add to instance array if supplied an update
12270 if (instances != NULL && count < instances_size) {
12271 instances->set(count, obj);
12280 // Check for circular reference only. This can happen when the object is only
12281 // referenced from mirrors and has a circular reference in which case the
12282 // object is not really alive and would have been garbage collected if not
12283 // referenced from the mirror.
12284 if (count == 1 && last == target) {
12288 // Return the number of referencing objects found.
12293 // Scan the heap for objects with direct references to an object
12294 // args[0]: the object to find references to
12295 // args[1]: constructor function for instances to exclude (Mirror)
12296 // args[2]: the the maximum number of objects to return
12297 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
12298 ASSERT(args.length() == 3);
12300 // First perform a full GC in order to avoid references from dead objects.
12301 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12302 "%DebugReferencedBy");
12303 // The heap iterator reserves the right to do a GC to make the heap iterable.
12304 // Due to the GC above we know it won't need to do that, but it seems cleaner
12305 // to get the heap iterator constructed before we start having unprotected
12306 // Object* locals that are not protected by handles.
12308 // Check parameters.
12309 CONVERT_ARG_CHECKED(JSObject, target, 0);
12310 Object* instance_filter = args[1];
12311 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12312 instance_filter->IsJSObject());
12313 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12314 RUNTIME_ASSERT(max_references >= 0);
12317 // Get the constructor function for context extension and arguments array.
12318 JSObject* arguments_boilerplate =
12319 isolate->context()->global_context()->arguments_boilerplate();
12320 JSFunction* arguments_function =
12321 JSFunction::cast(arguments_boilerplate->map()->constructor());
12323 // Get the number of referencing objects.
12325 HeapIterator heap_iterator;
12326 count = DebugReferencedBy(&heap_iterator,
12327 target, instance_filter, max_references,
12328 NULL, 0, arguments_function);
12330 // Allocate an array to hold the result.
12332 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
12333 if (!maybe_object->ToObject(&object)) return maybe_object;
12335 FixedArray* instances = FixedArray::cast(object);
12337 // Fill the referencing objects.
12338 // AllocateFixedArray above does not make the heap non-iterable.
12339 ASSERT(HEAP->IsHeapIterable());
12340 HeapIterator heap_iterator2;
12341 count = DebugReferencedBy(&heap_iterator2,
12342 target, instance_filter, max_references,
12343 instances, count, arguments_function);
12345 // Return result as JS array.
12347 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12348 isolate->context()->global_context()->array_function());
12349 if (!maybe_result->ToObject(&result)) return maybe_result;
12350 return JSArray::cast(result)->SetContent(instances);
12354 // Helper function used by Runtime_DebugConstructedBy below.
12355 static int DebugConstructedBy(HeapIterator* iterator,
12356 JSFunction* constructor,
12357 int max_references,
12358 FixedArray* instances,
12359 int instances_size) {
12360 AssertNoAllocation no_alloc;
12362 // Iterate the heap.
12364 HeapObject* heap_obj = NULL;
12365 while (((heap_obj = iterator->next()) != NULL) &&
12366 (max_references == 0 || count < max_references)) {
12367 // Only look at all JSObjects.
12368 if (heap_obj->IsJSObject()) {
12369 JSObject* obj = JSObject::cast(heap_obj);
12370 if (obj->map()->constructor() == constructor) {
12371 // Valid reference found add to instance array if supplied an update
12373 if (instances != NULL && count < instances_size) {
12374 instances->set(count, obj);
12381 // Return the number of referencing objects found.
12386 // Scan the heap for objects constructed by a specific function.
12387 // args[0]: the constructor to find instances of
12388 // args[1]: the the maximum number of objects to return
12389 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
12390 ASSERT(args.length() == 2);
12392 // First perform a full GC in order to avoid dead objects.
12393 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12394 "%DebugConstructedBy");
12396 // Check parameters.
12397 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
12398 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12399 RUNTIME_ASSERT(max_references >= 0);
12401 // Get the number of referencing objects.
12403 HeapIterator heap_iterator;
12404 count = DebugConstructedBy(&heap_iterator,
12410 // Allocate an array to hold the result.
12412 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
12413 if (!maybe_object->ToObject(&object)) return maybe_object;
12415 FixedArray* instances = FixedArray::cast(object);
12417 ASSERT(HEAP->IsHeapIterable());
12418 // Fill the referencing objects.
12419 HeapIterator heap_iterator2;
12420 count = DebugConstructedBy(&heap_iterator2,
12426 // Return result as JS array.
12428 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12429 isolate->context()->global_context()->array_function());
12430 if (!maybe_result->ToObject(&result)) return maybe_result;
12432 return JSArray::cast(result)->SetContent(instances);
12436 // Find the effective prototype object as returned by __proto__.
12437 // args[0]: the object to find the prototype for.
12438 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
12439 ASSERT(args.length() == 1);
12441 CONVERT_ARG_CHECKED(JSObject, obj, 0);
12443 // Use the __proto__ accessor.
12444 return Accessors::ObjectPrototype.getter(obj, NULL);
12448 // Patches script source (should be called upon BeforeCompile event).
12449 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12450 HandleScope scope(isolate);
12451 ASSERT(args.length() == 2);
12453 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12454 Handle<String> source(String::cast(args[1]));
12456 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12457 Handle<Script> script(Script::cast(script_wrapper->value()));
12459 int compilation_state = Smi::cast(script->compilation_state())->value();
12460 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12461 script->set_source(*source);
12463 return isolate->heap()->undefined_value();
12467 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
12468 ASSERT(args.length() == 0);
12470 return isolate->heap()->undefined_value();
12474 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
12476 HandleScope scope(isolate);
12477 ASSERT(args.length() == 1);
12478 // Get the function and make sure it is compiled.
12479 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
12480 Handle<SharedFunctionInfo> shared(func->shared());
12481 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
12482 return Failure::Exception();
12484 func->code()->PrintLn();
12486 return isolate->heap()->undefined_value();
12490 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
12492 HandleScope scope(isolate);
12493 ASSERT(args.length() == 1);
12494 // Get the function and make sure it is compiled.
12495 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
12496 Handle<SharedFunctionInfo> shared(func->shared());
12497 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
12498 return Failure::Exception();
12500 shared->construct_stub()->PrintLn();
12502 return isolate->heap()->undefined_value();
12506 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
12507 NoHandleAllocation ha;
12508 ASSERT(args.length() == 1);
12510 CONVERT_ARG_CHECKED(JSFunction, f, 0);
12511 return f->shared()->inferred_name();
12515 static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12517 FixedArray* buffer) {
12518 AssertNoAllocation no_allocations;
12520 int buffer_size = buffer->length();
12521 for (HeapObject* obj = iterator->next();
12523 obj = iterator->next()) {
12524 ASSERT(obj != NULL);
12525 if (!obj->IsSharedFunctionInfo()) {
12528 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12529 if (shared->script() != script) {
12532 if (counter < buffer_size) {
12533 buffer->set(counter, shared);
12540 // For a script finds all SharedFunctionInfo's in the heap that points
12541 // to this script. Returns JSArray of SharedFunctionInfo wrapped
12542 // in OpaqueReferences.
12543 RUNTIME_FUNCTION(MaybeObject*,
12544 Runtime_LiveEditFindSharedFunctionInfosForScript) {
12545 ASSERT(args.length() == 1);
12546 HandleScope scope(isolate);
12547 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
12550 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12552 const int kBufferSize = 32;
12554 Handle<FixedArray> array;
12555 array = isolate->factory()->NewFixedArray(kBufferSize);
12558 isolate->heap()->EnsureHeapIsIterable();
12559 AssertNoAllocation no_allocations;
12560 HeapIterator heap_iterator;
12561 Script* scr = *script;
12562 FixedArray* arr = *array;
12563 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12565 if (number > kBufferSize) {
12566 array = isolate->factory()->NewFixedArray(number);
12567 isolate->heap()->EnsureHeapIsIterable();
12568 AssertNoAllocation no_allocations;
12569 HeapIterator heap_iterator;
12570 Script* scr = *script;
12571 FixedArray* arr = *array;
12572 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12575 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
12576 result->set_length(Smi::FromInt(number));
12578 LiveEdit::WrapSharedFunctionInfos(result);
12583 // For a script calculates compilation information about all its functions.
12584 // The script source is explicitly specified by the second argument.
12585 // The source of the actual script is not used, however it is important that
12586 // all generated code keeps references to this particular instance of script.
12587 // Returns a JSArray of compilation infos. The array is ordered so that
12588 // each function with all its descendant is always stored in a continues range
12589 // with the function itself going first. The root function is a script function.
12590 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
12591 ASSERT(args.length() == 2);
12592 HandleScope scope(isolate);
12593 CONVERT_ARG_CHECKED(JSValue, script, 0);
12594 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12595 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12597 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12599 if (isolate->has_pending_exception()) {
12600 return Failure::Exception();
12606 // Changes the source of the script to a new_source.
12607 // If old_script_name is provided (i.e. is a String), also creates a copy of
12608 // the script with its original source and sends notification to debugger.
12609 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
12610 ASSERT(args.length() == 3);
12611 HandleScope scope(isolate);
12612 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12613 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
12614 Handle<Object> old_script_name(args[2], isolate);
12616 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12617 Handle<Script> original_script(Script::cast(original_script_value->value()));
12619 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12623 if (old_script->IsScript()) {
12624 Handle<Script> script_handle(Script::cast(old_script));
12625 return *(GetScriptWrapper(script_handle));
12627 return isolate->heap()->null_value();
12632 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
12633 ASSERT(args.length() == 1);
12634 HandleScope scope(isolate);
12635 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
12636 return LiveEdit::FunctionSourceUpdated(shared_info);
12640 // Replaces code of SharedFunctionInfo with a new one.
12641 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
12642 ASSERT(args.length() == 2);
12643 HandleScope scope(isolate);
12644 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12645 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
12647 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
12650 // Connects SharedFunctionInfo to another script.
12651 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
12652 ASSERT(args.length() == 2);
12653 HandleScope scope(isolate);
12654 Handle<Object> function_object(args[0], isolate);
12655 Handle<Object> script_object(args[1], isolate);
12657 if (function_object->IsJSValue()) {
12658 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12659 if (script_object->IsJSValue()) {
12660 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12661 Script* script = Script::cast(JSValue::cast(*script_object)->value());
12662 script_object = Handle<Object>(script, isolate);
12665 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12667 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12668 // and we check it in this function.
12671 return isolate->heap()->undefined_value();
12675 // In a code of a parent function replaces original function as embedded object
12676 // with a substitution one.
12677 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
12678 ASSERT(args.length() == 3);
12679 HandleScope scope(isolate);
12681 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12682 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12683 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
12685 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12688 return isolate->heap()->undefined_value();
12692 // Updates positions of a shared function info (first parameter) according
12693 // to script source change. Text change is described in second parameter as
12694 // array of groups of 3 numbers:
12695 // (change_begin, change_end, change_end_new_position).
12696 // Each group describes a change in text; groups are sorted by change_begin.
12697 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
12698 ASSERT(args.length() == 2);
12699 HandleScope scope(isolate);
12700 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12701 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
12703 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
12707 // For array of SharedFunctionInfo's (each wrapped in JSValue)
12708 // checks that none of them have activations on stacks (of any thread).
12709 // Returns array of the same length with corresponding results of
12710 // LiveEdit::FunctionPatchabilityStatus type.
12711 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
12712 ASSERT(args.length() == 2);
12713 HandleScope scope(isolate);
12714 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12715 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
12717 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
12720 // Compares 2 strings line-by-line, then token-wise and returns diff in form
12721 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12723 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
12724 ASSERT(args.length() == 2);
12725 HandleScope scope(isolate);
12726 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12727 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
12729 return *LiveEdit::CompareStrings(s1, s2);
12733 // A testing entry. Returns statement position which is the closest to
12734 // source_position.
12735 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
12736 ASSERT(args.length() == 2);
12737 HandleScope scope(isolate);
12738 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12739 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12741 Handle<Code> code(function->code(), isolate);
12743 if (code->kind() != Code::FUNCTION &&
12744 code->kind() != Code::OPTIMIZED_FUNCTION) {
12745 return isolate->heap()->undefined_value();
12748 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
12749 int closest_pc = 0;
12750 int distance = kMaxInt;
12751 while (!it.done()) {
12752 int statement_position = static_cast<int>(it.rinfo()->data());
12753 // Check if this break point is closer that what was previously found.
12754 if (source_position <= statement_position &&
12755 statement_position - source_position < distance) {
12757 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
12758 distance = statement_position - source_position;
12759 // Check whether we can't get any closer.
12760 if (distance == 0) break;
12765 return Smi::FromInt(closest_pc);
12769 // Calls specified function with or without entering the debugger.
12770 // This is used in unit tests to run code as if debugger is entered or simply
12771 // to have a stack with C++ frame in the middle.
12772 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
12773 ASSERT(args.length() == 2);
12774 HandleScope scope(isolate);
12775 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12776 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
12778 Handle<Object> result;
12779 bool pending_exception;
12781 if (without_debugger) {
12782 result = Execution::Call(function, isolate->global(), 0, NULL,
12783 &pending_exception);
12785 EnterDebugger enter_debugger;
12786 result = Execution::Call(function, isolate->global(), 0, NULL,
12787 &pending_exception);
12790 if (!pending_exception) {
12793 return Failure::Exception();
12799 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
12800 CONVERT_ARG_CHECKED(String, arg, 0);
12801 SmartArrayPointer<char> flags =
12802 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12803 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
12804 return isolate->heap()->undefined_value();
12809 // Presently, it only does a full GC.
12810 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
12811 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
12812 return isolate->heap()->undefined_value();
12816 // Gets the current heap usage.
12817 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
12818 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
12819 if (!Smi::IsValid(usage)) {
12820 return *isolate->factory()->NewNumberFromInt(usage);
12822 return Smi::FromInt(usage);
12826 // Captures a live object list from the present heap.
12827 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
12828 #ifdef LIVE_OBJECT_LIST
12829 return isolate->heap()->true_value();
12831 return isolate->heap()->false_value();
12836 // Captures a live object list from the present heap.
12837 RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
12838 #ifdef LIVE_OBJECT_LIST
12839 return LiveObjectList::Capture();
12841 return isolate->heap()->undefined_value();
12846 // Deletes the specified live object list.
12847 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
12848 #ifdef LIVE_OBJECT_LIST
12849 CONVERT_SMI_ARG_CHECKED(id, 0);
12850 bool success = LiveObjectList::Delete(id);
12851 return isolate->heap()->ToBoolean(success);
12853 return isolate->heap()->undefined_value();
12858 // Generates the response to a debugger request for a dump of the objects
12859 // contained in the difference between the captured live object lists
12860 // specified by id1 and id2.
12861 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12863 RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
12864 #ifdef LIVE_OBJECT_LIST
12866 CONVERT_SMI_ARG_CHECKED(id1, 0);
12867 CONVERT_SMI_ARG_CHECKED(id2, 1);
12868 CONVERT_SMI_ARG_CHECKED(start, 2);
12869 CONVERT_SMI_ARG_CHECKED(count, 3);
12870 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
12871 EnterDebugger enter_debugger;
12872 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12874 return isolate->heap()->undefined_value();
12879 // Gets the specified object as requested by the debugger.
12880 // This is only used for obj ids shown in live object lists.
12881 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
12882 #ifdef LIVE_OBJECT_LIST
12883 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
12884 Object* result = LiveObjectList::GetObj(obj_id);
12887 return isolate->heap()->undefined_value();
12892 // Gets the obj id for the specified address if valid.
12893 // This is only used for obj ids shown in live object lists.
12894 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
12895 #ifdef LIVE_OBJECT_LIST
12897 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
12898 Object* result = LiveObjectList::GetObjId(address);
12901 return isolate->heap()->undefined_value();
12906 // Gets the retainers that references the specified object alive.
12907 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
12908 #ifdef LIVE_OBJECT_LIST
12910 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
12911 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12912 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12913 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12914 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12915 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
12917 Handle<JSObject> instance_filter;
12918 if (args[1]->IsJSObject()) {
12919 instance_filter = args.at<JSObject>(1);
12921 bool verbose = false;
12922 if (args[2]->IsBoolean()) {
12923 verbose = args[2]->IsTrue();
12926 if (args[3]->IsSmi()) {
12927 start = args.smi_at(3);
12929 int limit = Smi::kMaxValue;
12930 if (args[4]->IsSmi()) {
12931 limit = args.smi_at(4);
12934 return LiveObjectList::GetObjRetainers(obj_id,
12941 return isolate->heap()->undefined_value();
12946 // Gets the reference path between 2 objects.
12947 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
12948 #ifdef LIVE_OBJECT_LIST
12950 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12951 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
12952 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12954 Handle<JSObject> instance_filter;
12955 if (args[2]->IsJSObject()) {
12956 instance_filter = args.at<JSObject>(2);
12960 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12963 return isolate->heap()->undefined_value();
12968 // Generates the response to a debugger request for a list of all
12969 // previously captured live object lists.
12970 RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
12971 #ifdef LIVE_OBJECT_LIST
12972 CONVERT_SMI_ARG_CHECKED(start, 0);
12973 CONVERT_SMI_ARG_CHECKED(count, 1);
12974 return LiveObjectList::Info(start, count);
12976 return isolate->heap()->undefined_value();
12981 // Gets a dump of the specified object as requested by the debugger.
12982 // This is only used for obj ids shown in live object lists.
12983 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
12984 #ifdef LIVE_OBJECT_LIST
12986 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
12987 Object* result = LiveObjectList::PrintObj(obj_id);
12990 return isolate->heap()->undefined_value();
12995 // Resets and releases all previously captured live object lists.
12996 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
12997 #ifdef LIVE_OBJECT_LIST
12998 LiveObjectList::Reset();
12999 return isolate->heap()->undefined_value();
13001 return isolate->heap()->undefined_value();
13006 // Generates the response to a debugger request for a summary of the types
13007 // of objects in the difference between the captured live object lists
13008 // specified by id1 and id2.
13009 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13011 RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
13012 #ifdef LIVE_OBJECT_LIST
13014 CONVERT_SMI_ARG_CHECKED(id1, 0);
13015 CONVERT_SMI_ARG_CHECKED(id2, 1);
13016 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
13018 EnterDebugger enter_debugger;
13019 return LiveObjectList::Summarize(id1, id2, filter_obj);
13021 return isolate->heap()->undefined_value();
13025 #endif // ENABLE_DEBUGGER_SUPPORT
13028 RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
13029 NoHandleAllocation ha;
13030 v8::V8::ResumeProfiler();
13031 return isolate->heap()->undefined_value();
13035 RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
13036 NoHandleAllocation ha;
13037 v8::V8::PauseProfiler();
13038 return isolate->heap()->undefined_value();
13042 // Finds the script object from the script data. NOTE: This operation uses
13043 // heap traversal to find the function generated for the source position
13044 // for the requested break point. For lazily compiled functions several heap
13045 // traversals might be required rendering this operation as a rather slow
13046 // operation. However for setting break points which is normally done through
13047 // some kind of user interaction the performance is not crucial.
13048 static Handle<Object> Runtime_GetScriptFromScriptName(
13049 Handle<String> script_name) {
13050 // Scan the heap for Script objects to find the script with the requested
13052 Handle<Script> script;
13053 script_name->GetHeap()->EnsureHeapIsIterable();
13054 AssertNoAllocation no_allocation_during_heap_iteration;
13055 HeapIterator iterator;
13056 HeapObject* obj = NULL;
13057 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
13058 // If a script is found check if it has the script data requested.
13059 if (obj->IsScript()) {
13060 if (Script::cast(obj)->name()->IsString()) {
13061 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13062 script = Handle<Script>(Script::cast(obj));
13068 // If no script with the requested script data is found return undefined.
13069 if (script.is_null()) return FACTORY->undefined_value();
13071 // Return the script found.
13072 return GetScriptWrapper(script);
13076 // Get the script object from script data. NOTE: Regarding performance
13077 // see the NOTE for GetScriptFromScriptData.
13078 // args[0]: script data for the script to find the source for
13079 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
13080 HandleScope scope(isolate);
13082 ASSERT(args.length() == 1);
13084 CONVERT_ARG_CHECKED(String, script_name, 0);
13086 // Find the requested script.
13087 Handle<Object> result =
13088 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13093 // Determines whether the given stack frame should be displayed in
13094 // a stack trace. The caller is the error constructor that asked
13095 // for the stack trace to be collected. The first time a construct
13096 // call to this function is encountered it is skipped. The seen_caller
13097 // in/out parameter is used to remember if the caller has been seen
13099 static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13101 bool* seen_caller) {
13102 // Only display JS frames.
13103 if (!raw_frame->is_java_script()) {
13106 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13107 Object* raw_fun = frame->function();
13108 // Not sure when this can happen but skip it just in case.
13109 if (!raw_fun->IsJSFunction()) {
13112 if ((raw_fun == caller) && !(*seen_caller)) {
13113 *seen_caller = true;
13116 // Skip all frames until we've seen the caller.
13117 if (!(*seen_caller)) return false;
13118 // Also, skip non-visible built-in functions and any call with the builtins
13119 // object as receiver, so as to not reveal either the builtins object or
13120 // an internal function.
13121 // The --builtins-in-stack-traces command line flag allows including
13122 // internal call sites in the stack trace for debugging purposes.
13123 if (!FLAG_builtins_in_stack_traces) {
13124 JSFunction* fun = JSFunction::cast(raw_fun);
13125 if (frame->receiver()->IsJSBuiltinsObject() ||
13126 (fun->IsBuiltin() && !fun->shared()->native())) {
13134 // Collect the raw data for a stack trace. Returns an array of 4
13135 // element segments each containing a receiver, function, code and
13136 // native code offset.
13137 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
13138 ASSERT_EQ(args.length(), 3);
13139 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
13140 Handle<Object> caller = args.at<Object>(1);
13141 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
13143 HandleScope scope(isolate);
13144 Factory* factory = isolate->factory();
13146 limit = Max(limit, 0); // Ensure that limit is not negative.
13147 int initial_size = Min(limit, 10);
13148 Handle<FixedArray> elements =
13149 factory->NewFixedArrayWithHoles(initial_size * 4);
13151 StackFrameIterator iter(isolate);
13152 // If the caller parameter is a function we skip frames until we're
13153 // under it before starting to collect.
13154 bool seen_caller = !caller->IsJSFunction();
13156 int frames_seen = 0;
13157 while (!iter.done() && frames_seen < limit) {
13158 StackFrame* raw_frame = iter.frame();
13159 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
13161 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13162 // Set initial size to the maximum inlining level + 1 for the outermost
13164 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
13165 frame->Summarize(&frames);
13166 for (int i = frames.length() - 1; i >= 0; i--) {
13167 if (cursor + 4 > elements->length()) {
13168 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13169 Handle<FixedArray> new_elements =
13170 factory->NewFixedArrayWithHoles(new_capacity);
13171 for (int i = 0; i < cursor; i++) {
13172 new_elements->set(i, elements->get(i));
13174 elements = new_elements;
13176 ASSERT(cursor + 4 <= elements->length());
13178 Handle<Object> recv = frames[i].receiver();
13179 Handle<JSFunction> fun = frames[i].function();
13180 Handle<Code> code = frames[i].code();
13181 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
13182 elements->set(cursor++, *recv);
13183 elements->set(cursor++, *fun);
13184 elements->set(cursor++, *code);
13185 elements->set(cursor++, *offset);
13190 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
13191 // Capture and attach a more detailed stack trace if necessary.
13192 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
13193 result->set_length(Smi::FromInt(cursor));
13198 // Returns V8 version as a string.
13199 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
13200 ASSERT_EQ(args.length(), 0);
13202 NoHandleAllocation ha;
13204 const char* version_string = v8::V8::GetVersion();
13206 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13211 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
13212 ASSERT(args.length() == 2);
13213 OS::PrintError("abort: %s\n",
13214 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
13215 isolate->PrintStack();
13222 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
13223 // This is only called from codegen, so checks might be more lax.
13224 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
13225 Object* key = args[1];
13227 int finger_index = cache->finger_index();
13228 Object* o = cache->get(finger_index);
13230 // The fastest case: hit the same place again.
13231 return cache->get(finger_index + 1);
13234 for (int i = finger_index - 2;
13235 i >= JSFunctionResultCache::kEntriesIndex;
13239 cache->set_finger_index(i);
13240 return cache->get(i + 1);
13244 int size = cache->size();
13245 ASSERT(size <= cache->length());
13247 for (int i = size - 2; i > finger_index; i -= 2) {
13250 cache->set_finger_index(i);
13251 return cache->get(i + 1);
13255 // There is no value in the cache. Invoke the function and cache result.
13256 HandleScope scope(isolate);
13258 Handle<JSFunctionResultCache> cache_handle(cache);
13259 Handle<Object> key_handle(key);
13260 Handle<Object> value;
13262 Handle<JSFunction> factory(JSFunction::cast(
13263 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13264 // TODO(antonm): consider passing a receiver when constructing a cache.
13265 Handle<Object> receiver(isolate->global_context()->global());
13266 // This handle is nor shared, nor used later, so it's safe.
13267 Handle<Object> argv[] = { key_handle };
13268 bool pending_exception;
13269 value = Execution::Call(factory,
13273 &pending_exception);
13274 if (pending_exception) return Failure::Exception();
13278 if (FLAG_verify_heap) {
13279 cache_handle->JSFunctionResultCacheVerify();
13283 // Function invocation may have cleared the cache. Reread all the data.
13284 finger_index = cache_handle->finger_index();
13285 size = cache_handle->size();
13287 // If we have spare room, put new data into it, otherwise evict post finger
13288 // entry which is likely to be the least recently used.
13290 if (size < cache_handle->length()) {
13291 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13294 index = finger_index + JSFunctionResultCache::kEntrySize;
13295 if (index == cache_handle->length()) {
13296 index = JSFunctionResultCache::kEntriesIndex;
13300 ASSERT(index % 2 == 0);
13301 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13302 ASSERT(index < cache_handle->length());
13304 cache_handle->set(index, *key_handle);
13305 cache_handle->set(index + 1, *value);
13306 cache_handle->set_finger_index(index);
13309 if (FLAG_verify_heap) {
13310 cache_handle->JSFunctionResultCacheVerify();
13318 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
13319 HandleScope scope(isolate);
13320 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13321 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
13322 return *isolate->factory()->NewJSMessageObject(
13327 isolate->factory()->undefined_value(),
13328 isolate->factory()->undefined_value(),
13329 isolate->factory()->undefined_value());
13333 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
13334 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
13335 return message->type();
13339 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
13340 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
13341 return message->arguments();
13345 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
13346 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
13347 return Smi::FromInt(message->start_position());
13351 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
13352 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
13353 return message->script();
13358 // ListNatives is ONLY used by the fuzz-natives.js in debug mode
13359 // Exclude the code in release mode.
13360 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
13361 ASSERT(args.length() == 0);
13363 #define COUNT_ENTRY(Name, argc, ressize) + 1
13364 int entry_count = 0
13365 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13366 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13367 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13369 Factory* factory = isolate->factory();
13370 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
13372 bool inline_runtime_functions = false;
13373 #define ADD_ENTRY(Name, argc, ressize) \
13375 HandleScope inner; \
13376 Handle<String> name; \
13377 /* Inline runtime functions have an underscore in front of the name. */ \
13378 if (inline_runtime_functions) { \
13379 name = factory->NewStringFromAscii( \
13380 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13382 name = factory->NewStringFromAscii( \
13383 Vector<const char>(#Name, StrLength(#Name))); \
13385 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
13386 pair_elements->set(0, *name); \
13387 pair_elements->set(1, Smi::FromInt(argc)); \
13388 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
13389 elements->set(index++, *pair); \
13391 inline_runtime_functions = false;
13392 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
13393 inline_runtime_functions = true;
13394 INLINE_FUNCTION_LIST(ADD_ENTRY)
13395 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
13397 ASSERT_EQ(index, entry_count);
13398 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
13404 RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
13405 ASSERT(args.length() == 2);
13406 CONVERT_ARG_CHECKED(String, format, 0);
13407 CONVERT_ARG_CHECKED(JSArray, elms, 1);
13408 String::FlatContent format_content = format->GetFlatContent();
13409 RUNTIME_ASSERT(format_content.IsAscii());
13410 Vector<const char> chars = format_content.ToAsciiVector();
13411 LOGGER->LogRuntime(chars, elms);
13412 return isolate->heap()->undefined_value();
13416 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
13417 UNREACHABLE(); // implemented as macro in the parser
13422 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13423 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13424 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
13425 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13428 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
13429 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13430 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13431 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13432 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13433 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13434 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13435 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13436 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13437 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13438 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13439 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13440 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13441 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13443 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13446 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13447 ASSERT(args.length() == 2);
13448 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13449 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
13450 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13453 // ----------------------------------------------------------------------------
13454 // Implementation of Runtime
13456 #define F(name, number_of_args, result_size) \
13457 { Runtime::k##name, Runtime::RUNTIME, #name, \
13458 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
13461 #define I(name, number_of_args, result_size) \
13462 { Runtime::kInline##name, Runtime::INLINE, \
13463 "_" #name, NULL, number_of_args, result_size },
13465 static const Runtime::Function kIntrinsicFunctions[] = {
13466 RUNTIME_FUNCTION_LIST(F)
13467 INLINE_FUNCTION_LIST(I)
13468 INLINE_RUNTIME_FUNCTION_LIST(I)
13472 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13473 Object* dictionary) {
13474 ASSERT(Isolate::Current()->heap() == heap);
13475 ASSERT(dictionary != NULL);
13476 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13477 for (int i = 0; i < kNumFunctions; ++i) {
13478 Object* name_symbol;
13479 { MaybeObject* maybe_name_symbol =
13480 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
13481 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13483 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
13484 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13485 String::cast(name_symbol),
13487 PropertyDetails(NONE, NORMAL));
13488 if (!maybe_dictionary->ToObject(&dictionary)) {
13489 // Non-recoverable failure. Calling code must restart heap
13491 return maybe_dictionary;
13499 const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13500 Heap* heap = name->GetHeap();
13501 int entry = heap->intrinsic_function_names()->FindEntry(*name);
13502 if (entry != kNotFound) {
13503 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
13504 int function_index = Smi::cast(smi_index)->value();
13505 return &(kIntrinsicFunctions[function_index]);
13511 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
13512 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13516 void Runtime::PerformGC(Object* result) {
13517 Isolate* isolate = Isolate::Current();
13518 Failure* failure = Failure::cast(result);
13519 if (failure->IsRetryAfterGC()) {
13520 if (isolate->heap()->new_space()->AddFreshPage()) {
13524 // Try to do a garbage collection; ignore it if it fails. The C
13525 // entry stub will throw an out-of-memory exception in that case.
13526 isolate->heap()->CollectGarbage(failure->allocation_space(),
13527 "Runtime::PerformGC");
13529 // Handle last resort GC and make sure to allow future allocations
13530 // to grow the heap without causing GCs (if possible).
13531 isolate->counters()->gc_last_resort_from_js()->Increment();
13532 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13533 "Runtime::PerformGC");
13538 } } // namespace v8::internal