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 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdlib.h> 29 30 #include "v8.h" 31 32 #include "accessors.h" 33 #include "api.h" 34 #include "arguments.h" 35 #include "bootstrapper.h" 36 #include "codegen.h" 37 #include "compilation-cache.h" 38 #include "compiler.h" 39 #include "cpu.h" 40 #include "dateparser-inl.h" 41 #include "debug.h" 42 #include "deoptimizer.h" 43 #include "date.h" 44 #include "execution.h" 45 #include "global-handles.h" 46 #include "isolate-inl.h" 47 #include "jsregexp.h" 48 #include "json-parser.h" 49 #include "liveedit.h" 50 #include "liveobjectlist-inl.h" 51 #include "misc-intrinsics.h" 52 #include "parser.h" 53 #include "platform.h" 54 #include "runtime-profiler.h" 55 #include "runtime.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" 62 63 namespace v8 { 64 namespace internal { 65 66 67 #define RUNTIME_ASSERT(value) \ 68 if (!(value)) return isolate->ThrowIllegalOperation(); 69 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]); 76 77 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ 78 RUNTIME_ASSERT(args[index]->Is##Type()); \ 79 Handle<Type> name = args.at<Type>(index); 80 81 // Cast the given object to a boolean and store it in a variable with 82 // the given name. If the object is not a boolean call IllegalOperation 83 // and return. 84 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ 85 RUNTIME_ASSERT(args[index]->IsBoolean()); \ 86 bool name = args[index]->IsTrue(); 87 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 90 // and return. 91 #define CONVERT_SMI_ARG_CHECKED(name, index) \ 92 RUNTIME_ASSERT(args[index]->IsSmi()); \ 93 int name = args.smi_at(index); 94 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); 101 102 // Call the specified converter on the object *comand store the result in 103 // a variable of the specified type with the given name. If the 104 // object is not a Number call IllegalOperation and return. 105 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 106 RUNTIME_ASSERT(obj->IsNumber()); \ 107 type name = NumberTo##Type(obj); 108 109 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])); 116 117 118 // Assert that the given argument has a valid value for a StrictModeFlag 119 // and store it in a StrictModeFlag variable with the given name. 120 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ 121 RUNTIME_ASSERT(args[index]->IsSmi()); \ 122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \ 123 args.smi_at(index) == kNonStrictMode); \ 124 StrictModeFlag name = \ 125 static_cast<StrictModeFlag>(args.smi_at(index)); 126 127 128 // Assert that the given argument has a valid value for a LanguageMode 129 // and store it in a LanguageMode variable with the given name. 130 #define CONVERT_LANGUAGE_MODE_ARG(name, index) \ 131 ASSERT(args[index]->IsSmi()); \ 132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \ 133 args.smi_at(index) == STRICT_MODE || \ 134 args.smi_at(index) == EXTENDED_MODE); \ 135 LanguageMode name = \ 136 static_cast<LanguageMode>(args.smi_at(index)); 137 138 139 MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate, 140 JSObject* boilerplate) { 141 StackLimitCheck check(isolate); 142 if (check.HasOverflowed()) return isolate->StackOverflow(); 143 144 Heap* heap = isolate->heap(); 145 Object* result; 146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate); 147 if (!maybe_result->ToObject(&result)) return maybe_result; 148 } 149 JSObject* copy = JSObject::cast(result); 150 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; 160 } 161 properties->set(i, result); 162 } 163 } 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; 171 } 172 copy->InObjectPropertyAtPut(i, result); 173 } 174 } 175 } else { 176 { MaybeObject* maybe_result = 177 heap->AllocateFixedArray(copy->NumberOfLocalProperties()); 178 if (!maybe_result->ToObject(&result)) return maybe_result; 179 } 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 189 // an array. 190 if (attributes != NONE) continue; 191 Object* value = 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; 197 } 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; 202 } 203 } 204 } 205 } 206 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(); 216 #ifdef DEBUG 217 for (int i = 0; i < elements->length(); i++) { 218 ASSERT(!elements->get(i)->IsJSObject()); 219 } 220 #endif 221 } else { 222 for (int i = 0; i < elements->length(); i++) { 223 Object* value = elements->get(i); 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, 230 js_object); 231 if (!maybe_result->ToObject(&result)) return maybe_result; 232 } 233 elements->set(i, result); 234 } 235 } 236 } 237 break; 238 } 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, 249 js_object); 250 if (!maybe_result->ToObject(&result)) return maybe_result; 251 } 252 element_dictionary->ValueAtPut(i, result); 253 } 254 } 255 } 256 break; 257 } 258 case NON_STRICT_ARGUMENTS_ELEMENTS: 259 UNIMPLEMENTED(); 260 break; 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. 272 break; 273 } 274 return copy; 275 } 276 277 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--; 295 } else { 296 // Bail out as a non-symbol non-index key makes caching impossible. 297 // ASSERT to make sure that the if condition after the loop is false. 298 ASSERT(number_of_symbol_keys != number_of_properties); 299 break; 300 } 301 } 302 // If we only have symbols and array indices among keys then we can 303 // use the map cache in the global context. 304 const int kMaxKeys = 10; 305 if ((number_of_symbol_keys == number_of_properties) && 306 (number_of_symbol_keys < kMaxKeys)) { 307 // Create the fixed array with the key. 308 Handle<FixedArray> keys = 309 isolate->factory()->NewFixedArray(number_of_symbol_keys); 310 if (number_of_symbol_keys > 0) { 311 int index = 0; 312 for (int p = 0; p < properties_length; p += 2) { 313 Object* key = constant_properties->get(p); 314 if (key->IsSymbol()) { 315 keys->set(index++, key); 316 } 317 } 318 ASSERT(index == number_of_symbol_keys); 319 } 320 *is_result_from_cache = true; 321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys); 322 } 323 *is_result_from_cache = false; 324 return isolate->factory()->CopyMap( 325 Handle<Map>(context->object_function()->initial_map()), 326 number_of_properties); 327 } 328 329 330 static Handle<Object> CreateLiteralBoilerplate( 331 Isolate* isolate, 332 Handle<FixedArray> literals, 333 Handle<FixedArray> constant_properties); 334 335 336 static Handle<Object> CreateObjectLiteralBoilerplate( 337 Isolate* isolate, 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)); 350 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, 359 constant_properties, 360 &is_result_from_cache); 361 362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map); 363 364 // Normalize the elements of the boilerplate to save space if needed. 365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); 366 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); 377 } 378 379 for (int index = 0; index < length; index +=2) { 380 Handle<Object> key(constant_properties->get(index+0), isolate); 381 Handle<Object> value(constant_properties->get(index+1), isolate); 382 if (value->IsFixedArray()) { 383 // The value contains the constant_properties of a 384 // simple object or array literal. 385 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 386 value = CreateLiteralBoilerplate(isolate, literals, array); 387 if (value.is_null()) return value; 388 } 389 Handle<Object> result; 390 uint32_t element_index = 0; 391 if (key->IsSymbol()) { 392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { 393 // Array index as string (uint32). 394 result = JSObject::SetOwnElement( 395 boilerplate, element_index, value, kNonStrictMode); 396 } else { 397 Handle<String> name(String::cast(*key)); 398 ASSERT(!name->AsArrayIndex(&element_index)); 399 result = JSObject::SetLocalPropertyIgnoreAttributes( 400 boilerplate, name, value, NONE); 401 } 402 } else if (key->ToArrayIndex(&element_index)) { 403 // Array index (uint32). 404 result = JSObject::SetOwnElement( 405 boilerplate, element_index, value, kNonStrictMode); 406 } else { 407 // Non-uint32 number. 408 ASSERT(key->IsNumber()); 409 double num = key->Number(); 410 char arr[100]; 411 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 412 const char* str = DoubleToCString(num, buffer); 413 Handle<String> name = 414 isolate->factory()->NewStringFromAscii(CStrVector(str)); 415 result = JSObject::SetLocalPropertyIgnoreAttributes( 416 boilerplate, name, value, NONE); 417 } 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; 423 } 424 425 // Transform to fast properties if necessary. For object literals with 426 // containing function literals we defer this operation until after all 427 // computed properties have been assigned so that we can generate 428 // constant function properties. 429 if (should_transform && !has_function_literal) { 430 JSObject::TransformToFastProperties( 431 boilerplate, boilerplate->map()->unused_property_fields()); 432 } 433 434 return boilerplate; 435 } 436 437 438 MaybeObject* TransitionElements(Handle<Object> object, 439 ElementsKind to_kind, 440 Isolate* isolate) { 441 HandleScope scope(isolate); 442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); 443 ElementsKind from_kind = 444 Handle<JSObject>::cast(object)->map()->elements_kind(); 445 if (Map::IsValidElementsTransition(from_kind, to_kind)) { 446 Handle<Object> result = JSObject::TransitionElementsKind( 447 Handle<JSObject>::cast(object), to_kind); 448 if (result.is_null()) return isolate->ThrowIllegalOperation(); 449 return *result; 450 } 451 return isolate->ThrowIllegalOperation(); 452 } 453 454 455 static const int kSmiOnlyLiteralMinimumLength = 1024; 456 457 458 Handle<Object> Runtime::CreateArrayLiteralBoilerplate( 459 Isolate* isolate, 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)); 467 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))); 472 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())); 478 } else { 479 object->set_map(Map::cast(global_context->object_js_array_map())); 480 } 481 482 Handle<FixedArrayBase> copied_elements_values; 483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) { 484 ASSERT(FLAG_smi_only_arrays); 485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray( 486 Handle<FixedDoubleArray>::cast(constant_elements_values)); 487 } else { 488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS || 489 constant_elements_kind == FAST_ELEMENTS); 490 const bool is_cow = 491 (constant_elements_values->map() == 492 isolate->heap()->fixed_cow_array_map()); 493 if (is_cow) { 494 copied_elements_values = constant_elements_values; 495 #if DEBUG 496 Handle<FixedArray> fixed_array_values = 497 Handle<FixedArray>::cast(copied_elements_values); 498 for (int i = 0; i < fixed_array_values->length(); i++) { 499 ASSERT(!fixed_array_values->get(i)->IsFixedArray()); 500 } 501 #endif 502 } else { 503 Handle<FixedArray> fixed_array_values = 504 Handle<FixedArray>::cast(constant_elements_values); 505 Handle<FixedArray> fixed_array_values_copy = 506 isolate->factory()->CopyFixedArray(fixed_array_values); 507 copied_elements_values = fixed_array_values_copy; 508 for (int i = 0; i < fixed_array_values->length(); i++) { 509 Object* current = fixed_array_values->get(i); 510 if (current->IsFixedArray()) { 511 // The value contains the constant_properties of a 512 // simple object or array literal. 513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); 514 Handle<Object> result = 515 CreateLiteralBoilerplate(isolate, literals, fa); 516 if (result.is_null()) return result; 517 fixed_array_values_copy->set(i, *result); 518 } 519 } 520 } 521 } 522 object->set_elements(*copied_elements_values); 523 object->set_length(Smi::FromInt(copied_elements_values->length())); 524 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()); 531 } 532 } 533 534 return object; 535 } 536 537 538 static Handle<Object> CreateLiteralBoilerplate( 539 Isolate* isolate, 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, 547 literals, 548 elements, 549 true, 550 kHasNoFunctionLiteral); 551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 552 return CreateObjectLiteralBoilerplate(isolate, 553 literals, 554 elements, 555 false, 556 kHasNoFunctionLiteral); 557 case CompileTimeValue::ARRAY_LITERAL: 558 return Runtime::CreateArrayLiteralBoilerplate( 559 isolate, literals, elements); 560 default: 561 UNREACHABLE(); 562 return Handle<Object>::null(); 563 } 564 } 565 566 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; 576 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, 581 literals, 582 constant_properties, 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); 588 } 589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); 590 } 591 592 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; 602 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, 607 literals, 608 constant_properties, 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); 614 } 615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); 616 } 617 618 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); 625 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()) { 629 boilerplate = 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); 634 } 635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate)); 636 } 637 638 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); 645 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()); 650 boilerplate = 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); 655 } 656 if (JSObject::cast(*boilerplate)->elements()->map() == 657 isolate->heap()->fixed_cow_array_map()) { 658 isolate->counters()->cow_arrays_created_runtime()->Increment(); 659 } 660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); 661 } 662 663 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); 671 } 672 673 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); 684 } 685 686 687 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) { 688 ASSERT(args.length() == 1); 689 Object* obj = args[0]; 690 return isolate->heap()->ToBoolean(obj->IsJSProxy()); 691 } 692 693 694 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) { 695 ASSERT(args.length() == 1); 696 Object* obj = args[0]; 697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); 698 } 699 700 701 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { 702 ASSERT(args.length() == 1); 703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 704 return proxy->handler(); 705 } 706 707 708 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) { 709 ASSERT(args.length() == 1); 710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 711 return proxy->call_trap(); 712 } 713 714 715 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) { 716 ASSERT(args.length() == 1); 717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 718 return proxy->construct_trap(); 719 } 720 721 722 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { 723 ASSERT(args.length() == 1); 724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 725 proxy->Fix(); 726 return isolate->heap()->undefined_value(); 727 } 728 729 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); 736 return *holder; 737 } 738 739 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(); 749 } 750 751 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)); 759 } 760 761 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(); 771 } 772 773 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); 780 return *holder; 781 } 782 783 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); 790 } 791 792 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); 802 return *value; 803 } 804 805 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)); 814 return *weakmap; 815 } 816 817 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); 824 } 825 826 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); 836 return *value; 837 } 838 839 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(); 846 } 847 848 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()); 856 do { 857 if (obj->IsAccessCheckNeeded() && 858 !isolate->MayNamedAccess(JSObject::cast(obj), 859 isolate->heap()->Proto_symbol(), 860 v8::ACCESS_GET)) { 861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET); 862 return isolate->heap()->undefined_value(); 863 } 864 obj = obj->GetPrototype(); 865 } while (obj->IsJSObject() && 866 JSObject::cast(obj)->map()->is_hidden_prototype()); 867 return obj; 868 } 869 870 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). 875 Object* O = args[0]; 876 Object* V = args[1]; 877 while (true) { 878 Object* prototype = V->GetPrototype(); 879 if (prototype->IsNull()) return isolate->heap()->false_value(); 880 if (O == prototype) return isolate->heap()->true_value(); 881 V = prototype; 882 } 883 } 884 885 886 // Recursively traverses hidden prototypes if property is not found 887 static void GetOwnPropertyImplementation(JSObject* obj, 888 String* name, 889 LookupResult* result) { 890 obj->LocalLookupRealNamedProperty(name, result); 891 892 if (!result->IsProperty()) { 893 Object* proto = obj->GetPrototype(); 894 if (proto->IsJSObject() && 895 JSObject::cast(proto)->map()->is_hidden_prototype()) 896 GetOwnPropertyImplementation(JSObject::cast(proto), 897 name, result); 898 } 899 } 900 901 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); 908 bool can_access = 909 (access_type == v8::ACCESS_HAS && 910 (info->all_can_read() || info->all_can_write())) || 911 (access_type == v8::ACCESS_GET && info->all_can_read()) || 912 (access_type == v8::ACCESS_SET && info->all_can_write()); 913 return can_access; 914 } 915 } 916 917 return false; 918 } 919 920 921 static bool CheckAccess(JSObject* obj, 922 String* name, 923 LookupResult* result, 924 v8::AccessType access_type) { 925 ASSERT(result->IsProperty()); 926 927 JSObject* holder = result->holder(); 928 JSObject* current = obj; 929 Isolate* isolate = obj->GetIsolate(); 930 while (true) { 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). 936 break; 937 } 938 939 if (current == holder) { 940 return true; 941 } 942 943 current = JSObject::cast(current->GetPrototype()); 944 } 945 946 // API callbacks can have per callback access exceptions. 947 switch (result->type()) { 948 case CALLBACKS: { 949 if (CheckAccessException(result, access_type)) { 950 return true; 951 } 952 break; 953 } 954 case INTERCEPTOR: { 955 // If the object has an interceptor, try real named properties. 956 // Overwrite the result to fetch the correct property later. 957 holder->LookupRealNamedProperty(name, result); 958 if (result->IsProperty()) { 959 if (CheckAccessException(result, access_type)) { 960 return true; 961 } 962 } 963 break; 964 } 965 default: 966 break; 967 } 968 969 isolate->ReportFailedAccessCheck(current, access_type); 970 return false; 971 } 972 973 974 // TODO(1095): we should traverse hidden prototype hierachy as well. 975 static bool CheckElementAccess(JSObject* obj, 976 uint32_t index, 977 v8::AccessType access_type) { 978 if (obj->IsAccessCheckNeeded() && 979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) { 980 return false; 981 } 982 983 return true; 984 } 985 986 987 // Enumerator used as indices into the array returned from GetOwnProperty 988 enum PropertyDescriptorIndices { 989 IS_ACCESSOR_INDEX, 990 VALUE_INDEX, 991 GETTER_INDEX, 992 SETTER_INDEX, 993 WRITABLE_INDEX, 994 ENUMERABLE_INDEX, 995 CONFIGURABLE_INDEX, 996 DESCRIPTOR_SIZE 997 }; 998 999 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. 1008 uint32_t index; 1009 if (name->AsArrayIndex(&index)) { 1010 switch (obj->HasLocalElement(index)) { 1011 case JSObject::UNDEFINED_ELEMENT: 1012 return heap->undefined_value(); 1013 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); 1022 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()); 1028 return *desc; 1029 } 1030 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()); 1040 return *desc; 1041 } 1042 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)); 1050 } 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)); 1055 } else { 1056 dictionary = SeededNumberDictionary::cast(elements); 1057 } 1058 int entry = dictionary->FindEntry(index); 1059 ASSERT(entry != SeededNumberDictionary::kNotFound); 1060 PropertyDetails details = dictionary->DetailsAt(entry); 1061 switch (details.type()) { 1062 case CALLBACKS: { 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)); 1069 } 1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) { 1071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER)); 1072 } 1073 break; 1074 } 1075 case NORMAL: { 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())); 1082 break; 1083 } 1084 default: 1085 UNREACHABLE(); 1086 break; 1087 } 1088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum())); 1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete())); 1090 return *desc; 1091 } 1092 } 1093 } 1094 1095 // Use recursive implementation to also traverse hidden prototypes 1096 GetOwnPropertyImplementation(*obj, *name, &result); 1097 1098 if (!result.IsProperty()) { 1099 return heap->undefined_value(); 1100 } 1101 1102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) { 1103 return heap->false_value(); 1104 } 1105 1106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum())); 1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete())); 1108 1109 bool is_js_accessor = (result.type() == CALLBACKS) && 1110 (result.GetCallbackObject()->IsAccessorPair()); 1111 1112 if (is_js_accessor) { 1113 // __defineGetter__/__defineSetter__ callback. 1114 elms->set(IS_ACCESSOR_INDEX, heap->true_value()); 1115 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)); 1119 } 1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) { 1121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER)); 1122 } 1123 } else { 1124 elms->set(IS_ACCESSOR_INDEX, heap->false_value()); 1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly())); 1126 1127 PropertyAttributes attrs; 1128 Object* value; 1129 // GetProperty will check access and report any violations. 1130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs); 1131 if (!maybe_value->ToObject(&value)) return maybe_value; 1132 } 1133 elms->set(VALUE_INDEX, value); 1134 } 1135 1136 return *desc; 1137 } 1138 1139 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); 1153 } 1154 1155 1156 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) { 1157 ASSERT(args.length() == 1); 1158 CONVERT_ARG_CHECKED(JSObject, obj, 0); 1159 return obj->PreventExtensions(); 1160 } 1161 1162 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); 1171 } 1172 return isolate->heap()->ToBoolean(obj->map()->is_extensible()); 1173 } 1174 1175 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(); 1184 return *result; 1185 } 1186 1187 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); 1193 } 1194 1195 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); 1201 } 1202 1203 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); 1215 } else { 1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 1217 } 1218 return *HeapObject::RawField(templ, offset); 1219 } 1220 1221 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. 1229 Object* new_map; 1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions(); 1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 1232 } 1233 1234 Map::cast(new_map)->set_is_access_check_needed(false); 1235 object->set_map(Map::cast(new_map)); 1236 } 1237 return isolate->heap()->ToBoolean(needs_access_checks); 1238 } 1239 1240 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. 1247 Object* new_map; 1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions(); 1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 1250 } 1251 1252 Map::cast(new_map)->set_is_access_check_needed(true); 1253 object->set_map(Map::cast(new_map)); 1254 } 1255 return isolate->heap()->undefined_value(); 1256 } 1257 1258 1259 static Failure* ThrowRedeclarationError(Isolate* isolate, 1260 const char* type, 1261 Handle<String> name) { 1262 HandleScope scope(isolate); 1263 Handle<Object> type_handle = 1264 isolate->factory()->NewStringFromAscii(CStrVector(type)); 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); 1269 } 1270 1271 1272 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { 1273 ASSERT(args.length() == 3); 1274 HandleScope scope(isolate); 1275 Handle<GlobalObject> global = Handle<GlobalObject>( 1276 isolate->context()->global()); 1277 1278 Handle<Context> context = args.at<Context>(0); 1279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); 1280 CONVERT_SMI_ARG_CHECKED(flags, 2); 1281 1282 // Traverse the name/value pairs and set the properties. 1283 int length = pairs->length(); 1284 for (int i = 0; i < length; i += 2) { 1285 HandleScope scope(isolate); 1286 Handle<String> name(String::cast(pairs->get(i))); 1287 Handle<Object> value(pairs->get(i + 1), isolate); 1288 1289 // We have to declare a global const property. To capture we only 1290 // assign to it when evaluating the assignment for "const x = 1291 // <expr>" the initial value is the hole. 1292 bool is_const_property = value->IsTheHole(); 1293 bool is_function_declaration = false; 1294 if (value->IsUndefined() || is_const_property) { 1295 // Lookup the property in the global object, and don't set the 1296 // value of the variable if the property is already there. 1297 LookupResult lookup(isolate); 1298 global->Lookup(*name, &lookup); 1299 if (lookup.IsProperty()) { 1300 // We found an existing property. Unless it was an interceptor 1301 // that claims the property is absent, skip this declaration. 1302 if (lookup.type() != INTERCEPTOR) { 1303 continue; 1304 } 1305 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 1306 if (attributes != ABSENT) { 1307 continue; 1308 } 1309 // Fall-through and introduce the absent property by using 1310 // SetProperty. 1311 } 1312 } else { 1313 is_function_declaration = true; 1314 // Copy the function and update its context. Use it as value. 1315 Handle<SharedFunctionInfo> shared = 1316 Handle<SharedFunctionInfo>::cast(value); 1317 Handle<JSFunction> function = 1318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 1319 context, 1320 TENURED); 1321 value = function; 1322 } 1323 1324 LookupResult lookup(isolate); 1325 global->LocalLookup(*name, &lookup); 1326 1327 // Compute the property attributes. According to ECMA-262, section 1328 // 13, page 71, the property must be read-only and 1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the 1330 // property as read-only, so we don't either. 1331 int attr = NONE; 1332 if (!DeclareGlobalsEvalFlag::decode(flags)) { 1333 attr |= DONT_DELETE; 1334 } 1335 bool is_native = DeclareGlobalsNativeFlag::decode(flags); 1336 if (is_const_property || (is_native && is_function_declaration)) { 1337 attr |= READ_ONLY; 1338 } 1339 1340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); 1341 1342 // Safari does not allow the invocation of callback setters for 1343 // function declarations. To mimic this behavior, we do not allow 1344 // the invocation of setters for function values. This makes a 1345 // difference for global functions with the same names as event 1346 // handlers such as "function onload() {}". Firefox does call the 1347 // onload setter in those case and Safari does not. We follow 1348 // Safari for compatibility. 1349 if (is_function_declaration) { 1350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) { 1351 // Do not overwrite READ_ONLY properties. 1352 if (lookup.GetAttributes() & READ_ONLY) { 1353 if (language_mode != CLASSIC_MODE) { 1354 Handle<Object> args[] = { name }; 1355 return isolate->Throw(*isolate->factory()->NewTypeError( 1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args)))); 1357 } 1358 continue; 1359 } 1360 // Do not change DONT_DELETE to false from true. 1361 attr |= lookup.GetAttributes() & DONT_DELETE; 1362 } 1363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr); 1364 1365 RETURN_IF_EMPTY_HANDLE( 1366 isolate, 1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value, 1368 attributes)); 1369 } else { 1370 RETURN_IF_EMPTY_HANDLE( 1371 isolate, 1372 JSReceiver::SetProperty(global, name, value, 1373 static_cast<PropertyAttributes>(attr), 1374 language_mode == CLASSIC_MODE 1375 ? kNonStrictMode : kStrictMode)); 1376 } 1377 } 1378 1379 ASSERT(!isolate->has_pending_exception()); 1380 return isolate->heap()->undefined_value(); 1381 } 1382 1383 1384 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { 1385 HandleScope scope(isolate); 1386 ASSERT(args.length() == 4); 1387 1388 // Declarations are always made in a function or global context. In the 1389 // case of eval code, the context passed is the context of the caller, 1390 // which may be some nested context and not the declaration context. 1391 RUNTIME_ASSERT(args[0]->IsContext()); 1392 Handle<Context> context(Context::cast(args[0])->declaration_context()); 1393 1394 Handle<String> name(String::cast(args[1])); 1395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2)); 1396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); 1397 Handle<Object> initial_value(args[3], isolate); 1398 1399 int index; 1400 PropertyAttributes attributes; 1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 1402 BindingFlags binding_flags; 1403 Handle<Object> holder = 1404 context->Lookup(name, flags, &index, &attributes, &binding_flags); 1405 1406 if (attributes != ABSENT) { 1407 // The name was declared before; check for conflicting re-declarations. 1408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 1409 // Functions are not read-only. 1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 1412 return ThrowRedeclarationError(isolate, type, name); 1413 } 1414 1415 // Initialize it if necessary. 1416 if (*initial_value != NULL) { 1417 if (index >= 0) { 1418 ASSERT(holder.is_identical_to(context)); 1419 if (((attributes & READ_ONLY) == 0) || 1420 context->get(index)->IsTheHole()) { 1421 context->set(index, *initial_value); 1422 } 1423 } else { 1424 // Slow case: The property is in the context extension object of a 1425 // function context or the global object of a global context. 1426 Handle<JSObject> object = Handle<JSObject>::cast(holder); 1427 RETURN_IF_EMPTY_HANDLE( 1428 isolate, 1429 JSReceiver::SetProperty(object, name, initial_value, mode, 1430 kNonStrictMode)); 1431 } 1432 } 1433 1434 } else { 1435 // The property is not in the function context. It needs to be 1436 // "declared" in the function context's extension context or as a 1437 // property of the the global object. 1438 Handle<JSObject> object; 1439 if (context->has_extension()) { 1440 object = Handle<JSObject>(JSObject::cast(context->extension())); 1441 } else { 1442 // Context extension objects are allocated lazily. 1443 ASSERT(context->IsFunctionContext()); 1444 object = isolate->factory()->NewJSObject( 1445 isolate->context_extension_function()); 1446 context->set_extension(*object); 1447 } 1448 ASSERT(*object != NULL); 1449 1450 // Declare the property by setting it to the initial value if provided, 1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 1452 // constant declarations). 1453 ASSERT(!object->HasLocalProperty(*name)); 1454 Handle<Object> value(isolate->heap()->undefined_value(), isolate); 1455 if (*initial_value != NULL) value = initial_value; 1456 // Declaring a const context slot is a conflicting declaration if 1457 // there is a callback with that name in a prototype. It is 1458 // allowed to introduce const variables in 1459 // JSContextExtensionObjects. They are treated specially in 1460 // SetProperty and no setters are invoked for those since they are 1461 // not real JSObjects. 1462 if (initial_value->IsTheHole() && 1463 !object->IsJSContextExtensionObject()) { 1464 LookupResult lookup(isolate); 1465 object->Lookup(*name, &lookup); 1466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) { 1467 return ThrowRedeclarationError(isolate, "const", name); 1468 } 1469 } 1470 RETURN_IF_EMPTY_HANDLE( 1471 isolate, 1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); 1473 } 1474 1475 return isolate->heap()->undefined_value(); 1476 } 1477 1478 1479 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { 1480 NoHandleAllocation nha; 1481 // args[0] == name 1482 // args[1] == language_mode 1483 // args[2] == value (optional) 1484 1485 // Determine if we need to assign to the variable if it already 1486 // exists (based on the number of arguments). 1487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); 1488 bool assign = args.length() == 3; 1489 1490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 1491 GlobalObject* global = isolate->context()->global(); 1492 RUNTIME_ASSERT(args[1]->IsSmi()); 1493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); 1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) 1495 ? kNonStrictMode : kStrictMode; 1496 1497 // According to ECMA-262, section 12.2, page 62, the property must 1498 // not be deletable. 1499 PropertyAttributes attributes = DONT_DELETE; 1500 1501 // Lookup the property locally in the global object. If it isn't 1502 // there, there is a property with this name in the prototype chain. 1503 // We follow Safari and Firefox behavior and only set the property 1504 // locally if there is an explicit initialization value that we have 1505 // to assign to the property. 1506 // Note that objects can have hidden prototypes, so we need to traverse 1507 // the whole chain of hidden prototypes to do a 'local' lookup. 1508 Object* object = global; 1509 LookupResult lookup(isolate); 1510 while (object->IsJSObject() && 1511 JSObject::cast(object)->map()->is_hidden_prototype()) { 1512 JSObject* raw_holder = JSObject::cast(object); 1513 raw_holder->LocalLookup(*name, &lookup); 1514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) { 1515 HandleScope handle_scope(isolate); 1516 Handle<JSObject> holder(raw_holder); 1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); 1518 // Update the raw pointer in case it's changed due to GC. 1519 raw_holder = *holder; 1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 1521 // Found an interceptor that's not read only. 1522 if (assign) { 1523 return raw_holder->SetProperty( 1524 &lookup, *name, args[2], attributes, strict_mode_flag); 1525 } else { 1526 return isolate->heap()->undefined_value(); 1527 } 1528 } 1529 } 1530 object = raw_holder->GetPrototype(); 1531 } 1532 1533 // Reload global in case the loop above performed a GC. 1534 global = isolate->context()->global(); 1535 if (assign) { 1536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag); 1537 } 1538 return isolate->heap()->undefined_value(); 1539 } 1540 1541 1542 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { 1543 // All constants are declared with an initial value. The name 1544 // of the constant is the first argument and the initial value 1545 // is the second. 1546 RUNTIME_ASSERT(args.length() == 2); 1547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 1548 Handle<Object> value = args.at<Object>(1); 1549 1550 // Get the current global object from top. 1551 GlobalObject* global = isolate->context()->global(); 1552 1553 // According to ECMA-262, section 12.2, page 62, the property must 1554 // not be deletable. Since it's a const, it must be READ_ONLY too. 1555 PropertyAttributes attributes = 1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 1557 1558 // Lookup the property locally in the global object. If it isn't 1559 // there, we add the property and take special precautions to always 1560 // add it as a local property even in case of callbacks in the 1561 // prototype chain (this rules out using SetProperty). 1562 // We use SetLocalPropertyIgnoreAttributes instead 1563 LookupResult lookup(isolate); 1564 global->LocalLookup(*name, &lookup); 1565 if (!lookup.IsProperty()) { 1566 return global->SetLocalPropertyIgnoreAttributes(*name, 1567 *value, 1568 attributes); 1569 } 1570 1571 if (!lookup.IsReadOnly()) { 1572 // Restore global object from context (in case of GC) and continue 1573 // with setting the value. 1574 HandleScope handle_scope(isolate); 1575 Handle<GlobalObject> global(isolate->context()->global()); 1576 1577 // BUG 1213575: Handle the case where we have to set a read-only 1578 // property through an interceptor and only do it if it's 1579 // uninitialized, e.g. the hole. Nirk... 1580 // Passing non-strict mode because the property is writable. 1581 RETURN_IF_EMPTY_HANDLE( 1582 isolate, 1583 JSReceiver::SetProperty(global, name, value, attributes, 1584 kNonStrictMode)); 1585 return *value; 1586 } 1587 1588 // Set the value, but only if we're assigning the initial value to a 1589 // constant. For now, we determine this by checking if the 1590 // current value is the hole. 1591 // Strict mode handling not needed (const is disallowed in strict mode). 1592 PropertyType type = lookup.type(); 1593 if (type == FIELD) { 1594 FixedArray* properties = global->properties(); 1595 int index = lookup.GetFieldIndex(); 1596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { 1597 properties->set(index, *value); 1598 } 1599 } else if (type == NORMAL) { 1600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() || 1601 !lookup.IsReadOnly()) { 1602 global->SetNormalizedProperty(&lookup, *value); 1603 } 1604 } else { 1605 // Ignore re-initialization of constants that have already been 1606 // assigned a function value. 1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION); 1608 } 1609 1610 // Use the set value as the result of the operation. 1611 return *value; 1612 } 1613 1614 1615 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { 1616 HandleScope scope(isolate); 1617 ASSERT(args.length() == 3); 1618 1619 Handle<Object> value(args[0], isolate); 1620 ASSERT(!value->IsTheHole()); 1621 1622 // Initializations are always done in a function or global context. 1623 RUNTIME_ASSERT(args[1]->IsContext()); 1624 Handle<Context> context(Context::cast(args[1])->declaration_context()); 1625 1626 Handle<String> name(String::cast(args[2])); 1627 1628 int index; 1629 PropertyAttributes attributes; 1630 ContextLookupFlags flags = FOLLOW_CHAINS; 1631 BindingFlags binding_flags; 1632 Handle<Object> holder = 1633 context->Lookup(name, flags, &index, &attributes, &binding_flags); 1634 1635 if (index >= 0) { 1636 ASSERT(holder->IsContext()); 1637 // Property was found in a context. Perform the assignment if we 1638 // found some non-constant or an uninitialized constant. 1639 Handle<Context> context = Handle<Context>::cast(holder); 1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { 1641 context->set(index, *value); 1642 } 1643 return *value; 1644 } 1645 1646 // The property could not be found, we introduce it as a property of the 1647 // global object. 1648 if (attributes == ABSENT) { 1649 Handle<JSObject> global = Handle<JSObject>( 1650 isolate->context()->global()); 1651 // Strict mode not needed (const disallowed in strict mode). 1652 RETURN_IF_EMPTY_HANDLE( 1653 isolate, 1654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode)); 1655 return *value; 1656 } 1657 1658 // The property was present in some function's context extension object, 1659 // as a property on the subject of a with, or as a property of the global 1660 // object. 1661 // 1662 // In most situations, eval-introduced consts should still be present in 1663 // the context extension object. However, because declaration and 1664 // initialization are separate, the property might have been deleted 1665 // before we reach the initialization point. 1666 // 1667 // Example: 1668 // 1669 // function f() { eval("delete x; const x;"); } 1670 // 1671 // In that case, the initialization behaves like a normal assignment. 1672 Handle<JSObject> object = Handle<JSObject>::cast(holder); 1673 1674 if (*object == context->extension()) { 1675 // This is the property that was introduced by the const declaration. 1676 // Set it if it hasn't been set before. NOTE: We cannot use 1677 // GetProperty() to get the current value as it 'unholes' the value. 1678 LookupResult lookup(isolate); 1679 object->LocalLookupRealNamedProperty(*name, &lookup); 1680 ASSERT(lookup.IsFound()); // the property was declared 1681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 1682 1683 PropertyType type = lookup.type(); 1684 if (type == FIELD) { 1685 FixedArray* properties = object->properties(); 1686 int index = lookup.GetFieldIndex(); 1687 if (properties->get(index)->IsTheHole()) { 1688 properties->set(index, *value); 1689 } 1690 } else if (type == NORMAL) { 1691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { 1692 object->SetNormalizedProperty(&lookup, *value); 1693 } 1694 } else { 1695 // We should not reach here. Any real, named property should be 1696 // either a field or a dictionary slot. 1697 UNREACHABLE(); 1698 } 1699 } else { 1700 // The property was found on some other object. Set it if it is not a 1701 // read-only property. 1702 if ((attributes & READ_ONLY) == 0) { 1703 // Strict mode not needed (const disallowed in strict mode). 1704 RETURN_IF_EMPTY_HANDLE( 1705 isolate, 1706 JSReceiver::SetProperty(object, name, value, attributes, 1707 kNonStrictMode)); 1708 } 1709 } 1710 1711 return *value; 1712 } 1713 1714 1715 RUNTIME_FUNCTION(MaybeObject*, 1716 Runtime_OptimizeObjectForAddingMultipleProperties) { 1717 HandleScope scope(isolate); 1718 ASSERT(args.length() == 2); 1719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 1720 CONVERT_SMI_ARG_CHECKED(properties, 1); 1721 if (object->HasFastProperties()) { 1722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 1723 } 1724 return *object; 1725 } 1726 1727 1728 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { 1729 HandleScope scope(isolate); 1730 ASSERT(args.length() == 4); 1731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 1733 // Due to the way the JS calls are constructed this must be less than the 1734 // length of a string, i.e. it is always a Smi. We check anyway for security. 1735 CONVERT_SMI_ARG_CHECKED(index, 2); 1736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 1737 RUNTIME_ASSERT(last_match_info->HasFastElements()); 1738 RUNTIME_ASSERT(index >= 0); 1739 RUNTIME_ASSERT(index <= subject->length()); 1740 isolate->counters()->regexp_entry_runtime()->Increment(); 1741 Handle<Object> result = RegExpImpl::Exec(regexp, 1742 subject, 1743 index, 1744 last_match_info); 1745 if (result.is_null()) return Failure::Exception(); 1746 return *result; 1747 } 1748 1749 1750 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) { 1751 ASSERT(args.length() == 3); 1752 CONVERT_SMI_ARG_CHECKED(elements_count, 0); 1753 if (elements_count < 0 || 1754 elements_count > FixedArray::kMaxLength || 1755 !Smi::IsValid(elements_count)) { 1756 return isolate->ThrowIllegalOperation(); 1757 } 1758 Object* new_object; 1759 { MaybeObject* maybe_new_object = 1760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count); 1761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 1762 } 1763 FixedArray* elements = FixedArray::cast(new_object); 1764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw( 1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE); 1766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 1767 } 1768 { 1769 AssertNoAllocation no_gc; 1770 HandleScope scope(isolate); 1771 reinterpret_cast<HeapObject*>(new_object)-> 1772 set_map(isolate->global_context()->regexp_result_map()); 1773 } 1774 JSArray* array = JSArray::cast(new_object); 1775 array->set_properties(isolate->heap()->empty_fixed_array()); 1776 array->set_elements(elements); 1777 array->set_length(Smi::FromInt(elements_count)); 1778 // Write in-object properties after the length of the array. 1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); 1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); 1781 return array; 1782 } 1783 1784 1785 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { 1786 AssertNoAllocation no_alloc; 1787 ASSERT(args.length() == 5); 1788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); 1789 CONVERT_ARG_CHECKED(String, source, 1); 1790 1791 Object* global = args[2]; 1792 if (!global->IsTrue()) global = isolate->heap()->false_value(); 1793 1794 Object* ignoreCase = args[3]; 1795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value(); 1796 1797 Object* multiline = args[4]; 1798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value(); 1799 1800 Map* map = regexp->map(); 1801 Object* constructor = map->constructor(); 1802 if (constructor->IsJSFunction() && 1803 JSFunction::cast(constructor)->initial_map() == map) { 1804 // If we still have the original map, set in-object properties directly. 1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); 1806 // Both true and false are immovable immortal objects so no need for write 1807 // barrier. 1808 regexp->InObjectPropertyAtPut( 1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER); 1810 regexp->InObjectPropertyAtPut( 1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER); 1812 regexp->InObjectPropertyAtPut( 1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER); 1814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex, 1815 Smi::FromInt(0), 1816 SKIP_WRITE_BARRIER); // It's a Smi. 1817 return regexp; 1818 } 1819 1820 // Map has changed, so use generic, but slower, method. 1821 PropertyAttributes final = 1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 1823 PropertyAttributes writable = 1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 1825 Heap* heap = isolate->heap(); 1826 MaybeObject* result; 1827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(), 1828 source, 1829 final); 1830 ASSERT(!result->IsFailure()); 1831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(), 1832 global, 1833 final); 1834 ASSERT(!result->IsFailure()); 1835 result = 1836 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(), 1837 ignoreCase, 1838 final); 1839 ASSERT(!result->IsFailure()); 1840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(), 1841 multiline, 1842 final); 1843 ASSERT(!result->IsFailure()); 1844 result = 1845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(), 1846 Smi::FromInt(0), 1847 writable); 1848 ASSERT(!result->IsFailure()); 1849 USE(result); 1850 return regexp; 1851 } 1852 1853 1854 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { 1855 HandleScope scope(isolate); 1856 ASSERT(args.length() == 1); 1857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); 1858 // This is necessary to enable fast checks for absence of elements 1859 // on Array.prototype and below. 1860 prototype->set_elements(isolate->heap()->empty_fixed_array()); 1861 return Smi::FromInt(0); 1862 } 1863 1864 1865 static Handle<JSFunction> InstallBuiltin(Isolate* isolate, 1866 Handle<JSObject> holder, 1867 const char* name, 1868 Builtins::Name builtin_name) { 1869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name); 1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); 1871 Handle<JSFunction> optimized = 1872 isolate->factory()->NewFunction(key, 1873 JS_OBJECT_TYPE, 1874 JSObject::kHeaderSize, 1875 code, 1876 false); 1877 optimized->shared()->DontAdaptArguments(); 1878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode); 1879 return optimized; 1880 } 1881 1882 1883 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { 1884 HandleScope scope(isolate); 1885 ASSERT(args.length() == 1); 1886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0); 1887 1888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); 1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); 1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); 1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); 1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); 1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); 1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); 1895 1896 return *holder; 1897 } 1898 1899 1900 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { 1901 ASSERT(args.length() == 1); 1902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 1903 1904 if (!callable->IsJSFunction()) { 1905 HandleScope scope(isolate); 1906 bool threw = false; 1907 Handle<Object> delegate = 1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw); 1909 if (threw) return Failure::Exception(); 1910 callable = JSFunction::cast(*delegate); 1911 } 1912 JSFunction* function = JSFunction::cast(callable); 1913 1914 SharedFunctionInfo* shared = function->shared(); 1915 if (shared->native() || !shared->is_classic_mode()) { 1916 return isolate->heap()->undefined_value(); 1917 } 1918 // Returns undefined for strict or native functions, or 1919 // the associated global receiver for "normal" functions. 1920 1921 Context* global_context = 1922 function->context()->global()->global_context(); 1923 return global_context->global()->global_receiver(); 1924 } 1925 1926 1927 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { 1928 HandleScope scope(isolate); 1929 ASSERT(args.length() == 4); 1930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 1931 int index = args.smi_at(1); 1932 Handle<String> pattern = args.at<String>(2); 1933 Handle<String> flags = args.at<String>(3); 1934 1935 // Get the RegExp function from the context in the literals array. 1936 // This is the RegExp function from the context in which the 1937 // function was created. We do not use the RegExp function from the 1938 // current global context because this might be the RegExp function 1939 // from another context which we should not have access to. 1940 Handle<JSFunction> constructor = 1941 Handle<JSFunction>( 1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function()); 1943 // Compute the regular expression literal. 1944 bool has_pending_exception; 1945 Handle<Object> regexp = 1946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, 1947 &has_pending_exception); 1948 if (has_pending_exception) { 1949 ASSERT(isolate->has_pending_exception()); 1950 return Failure::Exception(); 1951 } 1952 literals->set(index, *regexp); 1953 return *regexp; 1954 } 1955 1956 1957 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { 1958 NoHandleAllocation ha; 1959 ASSERT(args.length() == 1); 1960 1961 CONVERT_ARG_CHECKED(JSFunction, f, 0); 1962 return f->shared()->name(); 1963 } 1964 1965 1966 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { 1967 NoHandleAllocation ha; 1968 ASSERT(args.length() == 2); 1969 1970 CONVERT_ARG_CHECKED(JSFunction, f, 0); 1971 CONVERT_ARG_CHECKED(String, name, 1); 1972 f->shared()->set_name(name); 1973 return isolate->heap()->undefined_value(); 1974 } 1975 1976 1977 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) { 1978 NoHandleAllocation ha; 1979 ASSERT(args.length() == 1); 1980 CONVERT_ARG_CHECKED(JSFunction, f, 0); 1981 return isolate->heap()->ToBoolean( 1982 f->shared()->name_should_print_as_anonymous()); 1983 } 1984 1985 1986 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 1987 NoHandleAllocation ha; 1988 ASSERT(args.length() == 1); 1989 CONVERT_ARG_CHECKED(JSFunction, f, 0); 1990 f->shared()->set_name_should_print_as_anonymous(true); 1991 return isolate->heap()->undefined_value(); 1992 } 1993 1994 1995 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { 1996 NoHandleAllocation ha; 1997 ASSERT(args.length() == 1); 1998 1999 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2000 Object* obj = f->RemovePrototype(); 2001 if (obj->IsFailure()) return obj; 2002 2003 return isolate->heap()->undefined_value(); 2004 } 2005 2006 2007 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { 2008 HandleScope scope(isolate); 2009 ASSERT(args.length() == 1); 2010 2011 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); 2013 if (!script->IsScript()) return isolate->heap()->undefined_value(); 2014 2015 return *GetScriptWrapper(Handle<Script>::cast(script)); 2016 } 2017 2018 2019 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { 2020 HandleScope scope(isolate); 2021 ASSERT(args.length() == 1); 2022 2023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); 2024 Handle<SharedFunctionInfo> shared(f->shared()); 2025 return *shared->GetSourceCode(); 2026 } 2027 2028 2029 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { 2030 NoHandleAllocation ha; 2031 ASSERT(args.length() == 1); 2032 2033 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2034 int pos = fun->shared()->start_position(); 2035 return Smi::FromInt(pos); 2036 } 2037 2038 2039 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { 2040 ASSERT(args.length() == 2); 2041 2042 CONVERT_ARG_CHECKED(Code, code, 0); 2043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 2044 2045 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 2046 2047 Address pc = code->address() + offset; 2048 return Smi::FromInt(code->SourcePosition(pc)); 2049 } 2050 2051 2052 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { 2053 NoHandleAllocation ha; 2054 ASSERT(args.length() == 2); 2055 2056 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2057 CONVERT_ARG_CHECKED(String, name, 1); 2058 fun->SetInstanceClassName(name); 2059 return isolate->heap()->undefined_value(); 2060 } 2061 2062 2063 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { 2064 NoHandleAllocation ha; 2065 ASSERT(args.length() == 2); 2066 2067 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2068 CONVERT_SMI_ARG_CHECKED(length, 1); 2069 fun->shared()->set_length(length); 2070 return isolate->heap()->undefined_value(); 2071 } 2072 2073 2074 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { 2075 NoHandleAllocation ha; 2076 ASSERT(args.length() == 2); 2077 2078 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2079 ASSERT(fun->should_have_prototype()); 2080 Object* obj; 2081 { MaybeObject* maybe_obj = 2082 Accessors::FunctionSetPrototype(fun, args[1], NULL); 2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2084 } 2085 return args[0]; // return TOS 2086 } 2087 2088 2089 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { 2090 NoHandleAllocation ha; 2091 RUNTIME_ASSERT(args.length() == 1); 2092 CONVERT_ARG_CHECKED(JSFunction, function, 0); 2093 2094 MaybeObject* maybe_name = 2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype")); 2096 String* name; 2097 if (!maybe_name->To(&name)) return maybe_name; 2098 2099 if (function->HasFastProperties()) { 2100 // Construct a new field descriptor with updated attributes. 2101 DescriptorArray* instance_desc = function->map()->instance_descriptors(); 2102 int index = instance_desc->Search(name); 2103 ASSERT(index != DescriptorArray::kNotFound); 2104 PropertyDetails details(instance_desc->GetDetails(index)); 2105 CallbacksDescriptor new_desc(name, 2106 instance_desc->GetValue(index), 2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), 2108 details.index()); 2109 // Construct a new field descriptors array containing the new descriptor. 2110 Object* descriptors_unchecked; 2111 { MaybeObject* maybe_descriptors_unchecked = 2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS); 2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) { 2114 return maybe_descriptors_unchecked; 2115 } 2116 } 2117 DescriptorArray* new_descriptors = 2118 DescriptorArray::cast(descriptors_unchecked); 2119 // Create a new map featuring the new field descriptors array. 2120 Object* map_unchecked; 2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors(); 2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) { 2123 return maybe_map_unchecked; 2124 } 2125 } 2126 Map* new_map = Map::cast(map_unchecked); 2127 new_map->set_instance_descriptors(new_descriptors); 2128 function->set_map(new_map); 2129 } else { // Dictionary properties. 2130 // Directly manipulate the property details. 2131 int entry = function->property_dictionary()->FindEntry(name); 2132 ASSERT(entry != StringDictionary::kNotFound); 2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry); 2134 PropertyDetails new_details( 2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), 2136 details.type(), 2137 details.index()); 2138 function->property_dictionary()->DetailsAtPut(entry, new_details); 2139 } 2140 return function; 2141 } 2142 2143 2144 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { 2145 NoHandleAllocation ha; 2146 ASSERT(args.length() == 1); 2147 2148 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2149 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); 2150 } 2151 2152 2153 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { 2154 NoHandleAllocation ha; 2155 ASSERT(args.length() == 1); 2156 2157 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2158 return isolate->heap()->ToBoolean(f->IsBuiltin()); 2159 } 2160 2161 2162 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { 2163 HandleScope scope(isolate); 2164 ASSERT(args.length() == 2); 2165 2166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 2167 Handle<Object> code = args.at<Object>(1); 2168 2169 Handle<Context> context(target->context()); 2170 2171 if (!code->IsNull()) { 2172 RUNTIME_ASSERT(code->IsJSFunction()); 2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code); 2174 Handle<SharedFunctionInfo> shared(fun->shared()); 2175 2176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) { 2177 return Failure::Exception(); 2178 } 2179 // Since we don't store the source for this we should never 2180 // optimize this. 2181 shared->code()->set_optimizable(false); 2182 // Set the code, scope info, formal parameter count, 2183 // and the length of the target function. 2184 target->shared()->set_code(shared->code()); 2185 target->ReplaceCode(shared->code()); 2186 target->shared()->set_scope_info(shared->scope_info()); 2187 target->shared()->set_length(shared->length()); 2188 target->shared()->set_formal_parameter_count( 2189 shared->formal_parameter_count()); 2190 // Set the source code of the target function to undefined. 2191 // SetCode is only used for built-in constructors like String, 2192 // Array, and Object, and some web code 2193 // doesn't like seeing source code for constructors. 2194 target->shared()->set_script(isolate->heap()->undefined_value()); 2195 target->shared()->code()->set_optimizable(false); 2196 // Clear the optimization hints related to the compiled code as these are no 2197 // longer valid when the code is overwritten. 2198 target->shared()->ClearThisPropertyAssignmentsInfo(); 2199 context = Handle<Context>(fun->context()); 2200 2201 // Make sure we get a fresh copy of the literal vector to avoid 2202 // cross context contamination. 2203 int number_of_literals = fun->NumberOfLiterals(); 2204 Handle<FixedArray> literals = 2205 isolate->factory()->NewFixedArray(number_of_literals, TENURED); 2206 if (number_of_literals > 0) { 2207 // Insert the object, regexp and array functions in the literals 2208 // array prefix. These are the functions that will be used when 2209 // creating object, regexp and array literals. 2210 literals->set(JSFunction::kLiteralGlobalContextIndex, 2211 context->global_context()); 2212 } 2213 target->set_literals(*literals); 2214 target->set_next_function_link(isolate->heap()->undefined_value()); 2215 2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) { 2217 isolate->logger()->LogExistingFunction( 2218 shared, Handle<Code>(shared->code())); 2219 } 2220 } 2221 2222 target->set_context(*context); 2223 return *target; 2224 } 2225 2226 2227 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) { 2228 HandleScope scope(isolate); 2229 ASSERT(args.length() == 2); 2230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 2231 CONVERT_SMI_ARG_CHECKED(num, 1); 2232 RUNTIME_ASSERT(num >= 0); 2233 SetExpectedNofProperties(function, num); 2234 return isolate->heap()->undefined_value(); 2235 } 2236 2237 2238 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate, 2239 Object* char_code) { 2240 uint32_t code; 2241 if (char_code->ToArrayIndex(&code)) { 2242 if (code <= 0xffff) { 2243 return isolate->heap()->LookupSingleCharacterStringFromCode(code); 2244 } 2245 } 2246 return isolate->heap()->empty_string(); 2247 } 2248 2249 2250 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { 2251 NoHandleAllocation ha; 2252 ASSERT(args.length() == 2); 2253 2254 CONVERT_ARG_CHECKED(String, subject, 0); 2255 Object* index = args[1]; 2256 RUNTIME_ASSERT(index->IsNumber()); 2257 2258 uint32_t i = 0; 2259 if (index->IsSmi()) { 2260 int value = Smi::cast(index)->value(); 2261 if (value < 0) return isolate->heap()->nan_value(); 2262 i = value; 2263 } else { 2264 ASSERT(index->IsHeapNumber()); 2265 double value = HeapNumber::cast(index)->value(); 2266 i = static_cast<uint32_t>(DoubleToInteger(value)); 2267 } 2268 2269 // Flatten the string. If someone wants to get a char at an index 2270 // in a cons string, it is likely that more indices will be 2271 // accessed. 2272 Object* flat; 2273 { MaybeObject* maybe_flat = subject->TryFlatten(); 2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat; 2275 } 2276 subject = String::cast(flat); 2277 2278 if (i >= static_cast<uint32_t>(subject->length())) { 2279 return isolate->heap()->nan_value(); 2280 } 2281 2282 return Smi::FromInt(subject->Get(i)); 2283 } 2284 2285 2286 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) { 2287 NoHandleAllocation ha; 2288 ASSERT(args.length() == 1); 2289 return CharFromCode(isolate, args[0]); 2290 } 2291 2292 2293 class FixedArrayBuilder { 2294 public: 2295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) 2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), 2297 length_(0), 2298 has_non_smi_elements_(false) { 2299 // Require a non-zero initial size. Ensures that doubling the size to 2300 // extend the array will work. 2301 ASSERT(initial_capacity > 0); 2302 } 2303 2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) 2305 : array_(backing_store), 2306 length_(0), 2307 has_non_smi_elements_(false) { 2308 // Require a non-zero initial size. Ensures that doubling the size to 2309 // extend the array will work. 2310 ASSERT(backing_store->length() > 0); 2311 } 2312 2313 bool HasCapacity(int elements) { 2314 int length = array_->length(); 2315 int required_length = length_ + elements; 2316 return (length >= required_length); 2317 } 2318 2319 void EnsureCapacity(int elements) { 2320 int length = array_->length(); 2321 int required_length = length_ + elements; 2322 if (length < required_length) { 2323 int new_length = length; 2324 do { 2325 new_length *= 2; 2326 } while (new_length < required_length); 2327 Handle<FixedArray> extended_array = 2328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); 2329 array_->CopyTo(0, *extended_array, 0, length_); 2330 array_ = extended_array; 2331 } 2332 } 2333 2334 void Add(Object* value) { 2335 ASSERT(!value->IsSmi()); 2336 ASSERT(length_ < capacity()); 2337 array_->set(length_, value); 2338 length_++; 2339 has_non_smi_elements_ = true; 2340 } 2341 2342 void Add(Smi* value) { 2343 ASSERT(value->IsSmi()); 2344 ASSERT(length_ < capacity()); 2345 array_->set(length_, value); 2346 length_++; 2347 } 2348 2349 Handle<FixedArray> array() { 2350 return array_; 2351 } 2352 2353 int length() { 2354 return length_; 2355 } 2356 2357 int capacity() { 2358 return array_->length(); 2359 } 2360 2361 Handle<JSArray> ToJSArray() { 2362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_); 2363 result_array->set_length(Smi::FromInt(length_)); 2364 return result_array; 2365 } 2366 2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { 2368 FACTORY->SetContent(target_array, array_); 2369 target_array->set_length(Smi::FromInt(length_)); 2370 return target_array; 2371 } 2372 2373 private: 2374 Handle<FixedArray> array_; 2375 int length_; 2376 bool has_non_smi_elements_; 2377 }; 2378 2379 2380 // Forward declarations. 2381 const int kStringBuilderConcatHelperLengthBits = 11; 2382 const int kStringBuilderConcatHelperPositionBits = 19; 2383 2384 template <typename schar> 2385 static inline void StringBuilderConcatHelper(String*, 2386 schar*, 2387 FixedArray*, 2388 int); 2389 2390 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> 2391 StringBuilderSubstringLength; 2392 typedef BitField<int, 2393 kStringBuilderConcatHelperLengthBits, 2394 kStringBuilderConcatHelperPositionBits> 2395 StringBuilderSubstringPosition; 2396 2397 2398 class ReplacementStringBuilder { 2399 public: 2400 ReplacementStringBuilder(Heap* heap, 2401 Handle<String> subject, 2402 int estimated_part_count) 2403 : heap_(heap), 2404 array_builder_(heap->isolate(), estimated_part_count), 2405 subject_(subject), 2406 character_count_(0), 2407 is_ascii_(subject->IsAsciiRepresentation()) { 2408 // Require a non-zero initial size. Ensures that doubling the size to 2409 // extend the array will work. 2410 ASSERT(estimated_part_count > 0); 2411 } 2412 2413 static inline void AddSubjectSlice(FixedArrayBuilder* builder, 2414 int from, 2415 int to) { 2416 ASSERT(from >= 0); 2417 int length = to - from; 2418 ASSERT(length > 0); 2419 if (StringBuilderSubstringLength::is_valid(length) && 2420 StringBuilderSubstringPosition::is_valid(from)) { 2421 int encoded_slice = StringBuilderSubstringLength::encode(length) | 2422 StringBuilderSubstringPosition::encode(from); 2423 builder->Add(Smi::FromInt(encoded_slice)); 2424 } else { 2425 // Otherwise encode as two smis. 2426 builder->Add(Smi::FromInt(-length)); 2427 builder->Add(Smi::FromInt(from)); 2428 } 2429 } 2430 2431 2432 void EnsureCapacity(int elements) { 2433 array_builder_.EnsureCapacity(elements); 2434 } 2435 2436 2437 void AddSubjectSlice(int from, int to) { 2438 AddSubjectSlice(&array_builder_, from, to); 2439 IncrementCharacterCount(to - from); 2440 } 2441 2442 2443 void AddString(Handle<String> string) { 2444 int length = string->length(); 2445 ASSERT(length > 0); 2446 AddElement(*string); 2447 if (!string->IsAsciiRepresentation()) { 2448 is_ascii_ = false; 2449 } 2450 IncrementCharacterCount(length); 2451 } 2452 2453 2454 Handle<String> ToString() { 2455 if (array_builder_.length() == 0) { 2456 return heap_->isolate()->factory()->empty_string(); 2457 } 2458 2459 Handle<String> joined_string; 2460 if (is_ascii_) { 2461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_); 2462 AssertNoAllocation no_alloc; 2463 char* char_buffer = seq->GetChars(); 2464 StringBuilderConcatHelper(*subject_, 2465 char_buffer, 2466 *array_builder_.array(), 2467 array_builder_.length()); 2468 joined_string = Handle<String>::cast(seq); 2469 } else { 2470 // Non-ASCII. 2471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_); 2472 AssertNoAllocation no_alloc; 2473 uc16* char_buffer = seq->GetChars(); 2474 StringBuilderConcatHelper(*subject_, 2475 char_buffer, 2476 *array_builder_.array(), 2477 array_builder_.length()); 2478 joined_string = Handle<String>::cast(seq); 2479 } 2480 return joined_string; 2481 } 2482 2483 2484 void IncrementCharacterCount(int by) { 2485 if (character_count_ > String::kMaxLength - by) { 2486 V8::FatalProcessOutOfMemory("String.replace result too large."); 2487 } 2488 character_count_ += by; 2489 } 2490 2491 Handle<JSArray> GetParts() { 2492 return array_builder_.ToJSArray(); 2493 } 2494 2495 private: 2496 Handle<SeqAsciiString> NewRawAsciiString(int length) { 2497 return heap_->isolate()->factory()->NewRawAsciiString(length); 2498 } 2499 2500 2501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) { 2502 return heap_->isolate()->factory()->NewRawTwoByteString(length); 2503 } 2504 2505 2506 void AddElement(Object* element) { 2507 ASSERT(element->IsSmi() || element->IsString()); 2508 ASSERT(array_builder_.capacity() > array_builder_.length()); 2509 array_builder_.Add(element); 2510 } 2511 2512 Heap* heap_; 2513 FixedArrayBuilder array_builder_; 2514 Handle<String> subject_; 2515 int character_count_; 2516 bool is_ascii_; 2517 }; 2518 2519 2520 class CompiledReplacement { 2521 public: 2522 CompiledReplacement() 2523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {} 2524 2525 void Compile(Handle<String> replacement, 2526 int capture_count, 2527 int subject_length); 2528 2529 void Apply(ReplacementStringBuilder* builder, 2530 int match_from, 2531 int match_to, 2532 Handle<JSArray> last_match_info); 2533 2534 // Number of distinct parts of the replacement pattern. 2535 int parts() { 2536 return parts_.length(); 2537 } 2538 2539 bool simple_hint() { 2540 return simple_hint_; 2541 } 2542 2543 private: 2544 enum PartType { 2545 SUBJECT_PREFIX = 1, 2546 SUBJECT_SUFFIX, 2547 SUBJECT_CAPTURE, 2548 REPLACEMENT_SUBSTRING, 2549 REPLACEMENT_STRING, 2550 2551 NUMBER_OF_PART_TYPES 2552 }; 2553 2554 struct ReplacementPart { 2555 static inline ReplacementPart SubjectMatch() { 2556 return ReplacementPart(SUBJECT_CAPTURE, 0); 2557 } 2558 static inline ReplacementPart SubjectCapture(int capture_index) { 2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 2560 } 2561 static inline ReplacementPart SubjectPrefix() { 2562 return ReplacementPart(SUBJECT_PREFIX, 0); 2563 } 2564 static inline ReplacementPart SubjectSuffix(int subject_length) { 2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 2566 } 2567 static inline ReplacementPart ReplacementString() { 2568 return ReplacementPart(REPLACEMENT_STRING, 0); 2569 } 2570 static inline ReplacementPart ReplacementSubString(int from, int to) { 2571 ASSERT(from >= 0); 2572 ASSERT(to > from); 2573 return ReplacementPart(-from, to); 2574 } 2575 2576 // If tag <= 0 then it is the negation of a start index of a substring of 2577 // the replacement pattern, otherwise it's a value from PartType. 2578 ReplacementPart(int tag, int data) 2579 : tag(tag), data(data) { 2580 // Must be non-positive or a PartType value. 2581 ASSERT(tag < NUMBER_OF_PART_TYPES); 2582 } 2583 // Either a value of PartType or a non-positive number that is 2584 // the negation of an index into the replacement string. 2585 int tag; 2586 // The data value's interpretation depends on the value of tag: 2587 // tag == SUBJECT_PREFIX || 2588 // tag == SUBJECT_SUFFIX: data is unused. 2589 // tag == SUBJECT_CAPTURE: data is the number of the capture. 2590 // tag == REPLACEMENT_SUBSTRING || 2591 // tag == REPLACEMENT_STRING: data is index into array of substrings 2592 // of the replacement string. 2593 // tag <= 0: Temporary representation of the substring of the replacement 2594 // string ranging over -tag .. data. 2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 2596 // substring objects. 2597 int data; 2598 }; 2599 2600 template<typename Char> 2601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 2602 Vector<Char> characters, 2603 int capture_count, 2604 int subject_length) { 2605 int length = characters.length(); 2606 int last = 0; 2607 for (int i = 0; i < length; i++) { 2608 Char c = characters[i]; 2609 if (c == '$') { 2610 int next_index = i + 1; 2611 if (next_index == length) { // No next character! 2612 break; 2613 } 2614 Char c2 = characters[next_index]; 2615 switch (c2) { 2616 case '$': 2617 if (i > last) { 2618 // There is a substring before. Include the first "$". 2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index)); 2620 last = next_index + 1; // Continue after the second "$". 2621 } else { 2622 // Let the next substring start with the second "$". 2623 last = next_index; 2624 } 2625 i = next_index; 2626 break; 2627 case '`': 2628 if (i > last) { 2629 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 2630 } 2631 parts->Add(ReplacementPart::SubjectPrefix()); 2632 i = next_index; 2633 last = i + 1; 2634 break; 2635 case '\'': 2636 if (i > last) { 2637 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 2638 } 2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length)); 2640 i = next_index; 2641 last = i + 1; 2642 break; 2643 case '&': 2644 if (i > last) { 2645 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 2646 } 2647 parts->Add(ReplacementPart::SubjectMatch()); 2648 i = next_index; 2649 last = i + 1; 2650 break; 2651 case '0': 2652 case '1': 2653 case '2': 2654 case '3': 2655 case '4': 2656 case '5': 2657 case '6': 2658 case '7': 2659 case '8': 2660 case '9': { 2661 int capture_ref = c2 - '0'; 2662 if (capture_ref > capture_count) { 2663 i = next_index; 2664 continue; 2665 } 2666 int second_digit_index = next_index + 1; 2667 if (second_digit_index < length) { 2668 // Peek ahead to see if we have two digits. 2669 Char c3 = characters[second_digit_index]; 2670 if ('0' <= c3 && c3 <= '9') { // Double digits. 2671 int double_digit_ref = capture_ref * 10 + c3 - '0'; 2672 if (double_digit_ref <= capture_count) { 2673 next_index = second_digit_index; 2674 capture_ref = double_digit_ref; 2675 } 2676 } 2677 } 2678 if (capture_ref > 0) { 2679 if (i > last) { 2680 parts->Add(ReplacementPart::ReplacementSubString(last, i)); 2681 } 2682 ASSERT(capture_ref <= capture_count); 2683 parts->Add(ReplacementPart::SubjectCapture(capture_ref)); 2684 last = next_index + 1; 2685 } 2686 i = next_index; 2687 break; 2688 } 2689 default: 2690 i = next_index; 2691 break; 2692 } 2693 } 2694 } 2695 if (length > last) { 2696 if (last == 0) { 2697 parts->Add(ReplacementPart::ReplacementString()); 2698 return true; 2699 } else { 2700 parts->Add(ReplacementPart::ReplacementSubString(last, length)); 2701 } 2702 } 2703 return false; 2704 } 2705 2706 ZoneList<ReplacementPart> parts_; 2707 ZoneList<Handle<String> > replacement_substrings_; 2708 bool simple_hint_; 2709 }; 2710 2711 2712 void CompiledReplacement::Compile(Handle<String> replacement, 2713 int capture_count, 2714 int subject_length) { 2715 { 2716 AssertNoAllocation no_alloc; 2717 String::FlatContent content = replacement->GetFlatContent(); 2718 ASSERT(content.IsFlat()); 2719 if (content.IsAscii()) { 2720 simple_hint_ = ParseReplacementPattern(&parts_, 2721 content.ToAsciiVector(), 2722 capture_count, 2723 subject_length); 2724 } else { 2725 ASSERT(content.IsTwoByte()); 2726 simple_hint_ = ParseReplacementPattern(&parts_, 2727 content.ToUC16Vector(), 2728 capture_count, 2729 subject_length); 2730 } 2731 } 2732 Isolate* isolate = replacement->GetIsolate(); 2733 // Find substrings of replacement string and create them as String objects. 2734 int substring_index = 0; 2735 for (int i = 0, n = parts_.length(); i < n; i++) { 2736 int tag = parts_[i].tag; 2737 if (tag <= 0) { // A replacement string slice. 2738 int from = -tag; 2739 int to = parts_[i].data; 2740 replacement_substrings_.Add( 2741 isolate->factory()->NewSubString(replacement, from, to)); 2742 parts_[i].tag = REPLACEMENT_SUBSTRING; 2743 parts_[i].data = substring_index; 2744 substring_index++; 2745 } else if (tag == REPLACEMENT_STRING) { 2746 replacement_substrings_.Add(replacement); 2747 parts_[i].data = substring_index; 2748 substring_index++; 2749 } 2750 } 2751 } 2752 2753 2754 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 2755 int match_from, 2756 int match_to, 2757 Handle<JSArray> last_match_info) { 2758 for (int i = 0, n = parts_.length(); i < n; i++) { 2759 ReplacementPart part = parts_[i]; 2760 switch (part.tag) { 2761 case SUBJECT_PREFIX: 2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 2763 break; 2764 case SUBJECT_SUFFIX: { 2765 int subject_length = part.data; 2766 if (match_to < subject_length) { 2767 builder->AddSubjectSlice(match_to, subject_length); 2768 } 2769 break; 2770 } 2771 case SUBJECT_CAPTURE: { 2772 int capture = part.data; 2773 FixedArray* match_info = FixedArray::cast(last_match_info->elements()); 2774 int from = RegExpImpl::GetCapture(match_info, capture * 2); 2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1); 2776 if (from >= 0 && to > from) { 2777 builder->AddSubjectSlice(from, to); 2778 } 2779 break; 2780 } 2781 case REPLACEMENT_SUBSTRING: 2782 case REPLACEMENT_STRING: 2783 builder->AddString(replacement_substrings_[part.data]); 2784 break; 2785 default: 2786 UNREACHABLE(); 2787 } 2788 } 2789 } 2790 2791 2792 void FindAsciiStringIndices(Vector<const char> subject, 2793 char pattern, 2794 ZoneList<int>* indices, 2795 unsigned int limit) { 2796 ASSERT(limit > 0); 2797 // Collect indices of pattern in subject using memchr. 2798 // Stop after finding at most limit values. 2799 const char* subject_start = reinterpret_cast<const char*>(subject.start()); 2800 const char* subject_end = subject_start + subject.length(); 2801 const char* pos = subject_start; 2802 while (limit > 0) { 2803 pos = reinterpret_cast<const char*>( 2804 memchr(pos, pattern, subject_end - pos)); 2805 if (pos == NULL) return; 2806 indices->Add(static_cast<int>(pos - subject_start)); 2807 pos++; 2808 limit--; 2809 } 2810 } 2811 2812 2813 template <typename SubjectChar, typename PatternChar> 2814 void FindStringIndices(Isolate* isolate, 2815 Vector<const SubjectChar> subject, 2816 Vector<const PatternChar> pattern, 2817 ZoneList<int>* indices, 2818 unsigned int limit) { 2819 ASSERT(limit > 0); 2820 // Collect indices of pattern in subject. 2821 // Stop after finding at most limit values. 2822 int pattern_length = pattern.length(); 2823 int index = 0; 2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); 2825 while (limit > 0) { 2826 index = search.Search(subject, index); 2827 if (index < 0) return; 2828 indices->Add(index); 2829 index += pattern_length; 2830 limit--; 2831 } 2832 } 2833 2834 2835 void FindStringIndicesDispatch(Isolate* isolate, 2836 String* subject, 2837 String* pattern, 2838 ZoneList<int>* indices, 2839 unsigned int limit) { 2840 { 2841 AssertNoAllocation no_gc; 2842 String::FlatContent subject_content = subject->GetFlatContent(); 2843 String::FlatContent pattern_content = pattern->GetFlatContent(); 2844 ASSERT(subject_content.IsFlat()); 2845 ASSERT(pattern_content.IsFlat()); 2846 if (subject_content.IsAscii()) { 2847 Vector<const char> subject_vector = subject_content.ToAsciiVector(); 2848 if (pattern_content.IsAscii()) { 2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector(); 2850 if (pattern_vector.length() == 1) { 2851 FindAsciiStringIndices(subject_vector, 2852 pattern_vector[0], 2853 indices, 2854 limit); 2855 } else { 2856 FindStringIndices(isolate, 2857 subject_vector, 2858 pattern_vector, 2859 indices, 2860 limit); 2861 } 2862 } else { 2863 FindStringIndices(isolate, 2864 subject_vector, 2865 pattern_content.ToUC16Vector(), 2866 indices, 2867 limit); 2868 } 2869 } else { 2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); 2871 if (pattern_content.IsAscii()) { 2872 FindStringIndices(isolate, 2873 subject_vector, 2874 pattern_content.ToAsciiVector(), 2875 indices, 2876 limit); 2877 } else { 2878 FindStringIndices(isolate, 2879 subject_vector, 2880 pattern_content.ToUC16Vector(), 2881 indices, 2882 limit); 2883 } 2884 } 2885 } 2886 } 2887 2888 2889 template<typename ResultSeqString> 2890 MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString( 2891 Isolate* isolate, 2892 Handle<String> subject, 2893 Handle<JSRegExp> pattern_regexp, 2894 Handle<String> replacement) { 2895 ASSERT(subject->IsFlat()); 2896 ASSERT(replacement->IsFlat()); 2897 2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT); 2899 ZoneList<int> indices(8); 2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 2901 String* pattern = 2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 2903 int subject_len = subject->length(); 2904 int pattern_len = pattern->length(); 2905 int replacement_len = replacement->length(); 2906 2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff); 2908 2909 int matches = indices.length(); 2910 if (matches == 0) return *subject; 2911 2912 int result_len = (replacement_len - pattern_len) * matches + subject_len; 2913 int subject_pos = 0; 2914 int result_pos = 0; 2915 2916 Handle<ResultSeqString> result; 2917 if (ResultSeqString::kHasAsciiEncoding) { 2918 result = Handle<ResultSeqString>::cast( 2919 isolate->factory()->NewRawAsciiString(result_len)); 2920 } else { 2921 result = Handle<ResultSeqString>::cast( 2922 isolate->factory()->NewRawTwoByteString(result_len)); 2923 } 2924 2925 for (int i = 0; i < matches; i++) { 2926 // Copy non-matched subject content. 2927 if (subject_pos < indices.at(i)) { 2928 String::WriteToFlat(*subject, 2929 result->GetChars() + result_pos, 2930 subject_pos, 2931 indices.at(i)); 2932 result_pos += indices.at(i) - subject_pos; 2933 } 2934 2935 // Replace match. 2936 if (replacement_len > 0) { 2937 String::WriteToFlat(*replacement, 2938 result->GetChars() + result_pos, 2939 0, 2940 replacement_len); 2941 result_pos += replacement_len; 2942 } 2943 2944 subject_pos = indices.at(i) + pattern_len; 2945 } 2946 // Add remaining subject content at the end. 2947 if (subject_pos < subject_len) { 2948 String::WriteToFlat(*subject, 2949 result->GetChars() + result_pos, 2950 subject_pos, 2951 subject_len); 2952 } 2953 return *result; 2954 } 2955 2956 2957 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString( 2958 Isolate* isolate, 2959 String* subject, 2960 JSRegExp* regexp, 2961 String* replacement, 2962 JSArray* last_match_info) { 2963 ASSERT(subject->IsFlat()); 2964 ASSERT(replacement->IsFlat()); 2965 2966 HandleScope handles(isolate); 2967 2968 int length = subject->length(); 2969 Handle<String> subject_handle(subject); 2970 Handle<JSRegExp> regexp_handle(regexp); 2971 Handle<String> replacement_handle(replacement); 2972 Handle<JSArray> last_match_info_handle(last_match_info); 2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle, 2974 subject_handle, 2975 0, 2976 last_match_info_handle); 2977 if (match.is_null()) { 2978 return Failure::Exception(); 2979 } 2980 if (match->IsNull()) { 2981 return *subject_handle; 2982 } 2983 2984 int capture_count = regexp_handle->CaptureCount(); 2985 2986 // CompiledReplacement uses zone allocation. 2987 ZoneScope zone(isolate, DELETE_ON_EXIT); 2988 CompiledReplacement compiled_replacement; 2989 compiled_replacement.Compile(replacement_handle, 2990 capture_count, 2991 length); 2992 2993 bool is_global = regexp_handle->GetFlags().is_global(); 2994 2995 // Shortcut for simple non-regexp global replacements 2996 if (is_global && 2997 regexp_handle->TypeTag() == JSRegExp::ATOM && 2998 compiled_replacement.simple_hint()) { 2999 if (subject_handle->HasOnlyAsciiChars() && 3000 replacement_handle->HasOnlyAsciiChars()) { 3001 return StringReplaceStringWithString<SeqAsciiString>( 3002 isolate, subject_handle, regexp_handle, replacement_handle); 3003 } else { 3004 return StringReplaceStringWithString<SeqTwoByteString>( 3005 isolate, subject_handle, regexp_handle, replacement_handle); 3006 } 3007 } 3008 3009 // Guessing the number of parts that the final result string is built 3010 // from. Global regexps can match any number of times, so we guess 3011 // conservatively. 3012 int expected_parts = 3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1; 3014 ReplacementStringBuilder builder(isolate->heap(), 3015 subject_handle, 3016 expected_parts); 3017 3018 // Index of end of last match. 3019 int prev = 0; 3020 3021 // Number of parts added by compiled replacement plus preceeding 3022 // string and possibly suffix after last match. It is possible for 3023 // all components to use two elements when encoded as two smis. 3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 3025 bool matched = true; 3026 do { 3027 ASSERT(last_match_info_handle->HasFastElements()); 3028 // Increase the capacity of the builder before entering local handle-scope, 3029 // so its internal buffer can safely allocate a new handle if it grows. 3030 builder.EnsureCapacity(parts_added_per_loop); 3031 3032 HandleScope loop_scope(isolate); 3033 int start, end; 3034 { 3035 AssertNoAllocation match_info_array_is_not_in_a_handle; 3036 FixedArray* match_info_array = 3037 FixedArray::cast(last_match_info_handle->elements()); 3038 3039 ASSERT_EQ(capture_count * 2 + 2, 3040 RegExpImpl::GetLastCaptureCount(match_info_array)); 3041 start = RegExpImpl::GetCapture(match_info_array, 0); 3042 end = RegExpImpl::GetCapture(match_info_array, 1); 3043 } 3044 3045 if (prev < start) { 3046 builder.AddSubjectSlice(prev, start); 3047 } 3048 compiled_replacement.Apply(&builder, 3049 start, 3050 end, 3051 last_match_info_handle); 3052 prev = end; 3053 3054 // Only continue checking for global regexps. 3055 if (!is_global) break; 3056 3057 // Continue from where the match ended, unless it was an empty match. 3058 int next = end; 3059 if (start == end) { 3060 next = end + 1; 3061 if (next > length) break; 3062 } 3063 3064 match = RegExpImpl::Exec(regexp_handle, 3065 subject_handle, 3066 next, 3067 last_match_info_handle); 3068 if (match.is_null()) { 3069 return Failure::Exception(); 3070 } 3071 matched = !match->IsNull(); 3072 } while (matched); 3073 3074 if (prev < length) { 3075 builder.AddSubjectSlice(prev, length); 3076 } 3077 3078 return *(builder.ToString()); 3079 } 3080 3081 3082 template <typename ResultSeqString> 3083 MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString( 3084 Isolate* isolate, 3085 String* subject, 3086 JSRegExp* regexp, 3087 JSArray* last_match_info) { 3088 ASSERT(subject->IsFlat()); 3089 3090 HandleScope handles(isolate); 3091 3092 Handle<String> subject_handle(subject); 3093 Handle<JSRegExp> regexp_handle(regexp); 3094 3095 // Shortcut for simple non-regexp global replacements 3096 if (regexp_handle->GetFlags().is_global() && 3097 regexp_handle->TypeTag() == JSRegExp::ATOM) { 3098 Handle<String> empty_string_handle(HEAP->empty_string()); 3099 if (subject_handle->HasOnlyAsciiChars()) { 3100 return StringReplaceStringWithString<SeqAsciiString>( 3101 isolate, subject_handle, regexp_handle, empty_string_handle); 3102 } else { 3103 return StringReplaceStringWithString<SeqTwoByteString>( 3104 isolate, subject_handle, regexp_handle, empty_string_handle); 3105 } 3106 } 3107 3108 Handle<JSArray> last_match_info_handle(last_match_info); 3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle, 3110 subject_handle, 3111 0, 3112 last_match_info_handle); 3113 if (match.is_null()) return Failure::Exception(); 3114 if (match->IsNull()) return *subject_handle; 3115 3116 ASSERT(last_match_info_handle->HasFastElements()); 3117 3118 int start, end; 3119 { 3120 AssertNoAllocation match_info_array_is_not_in_a_handle; 3121 FixedArray* match_info_array = 3122 FixedArray::cast(last_match_info_handle->elements()); 3123 3124 start = RegExpImpl::GetCapture(match_info_array, 0); 3125 end = RegExpImpl::GetCapture(match_info_array, 1); 3126 } 3127 3128 int length = subject_handle->length(); 3129 int new_length = length - (end - start); 3130 if (new_length == 0) { 3131 return isolate->heap()->empty_string(); 3132 } 3133 Handle<ResultSeqString> answer; 3134 if (ResultSeqString::kHasAsciiEncoding) { 3135 answer = Handle<ResultSeqString>::cast( 3136 isolate->factory()->NewRawAsciiString(new_length)); 3137 } else { 3138 answer = Handle<ResultSeqString>::cast( 3139 isolate->factory()->NewRawTwoByteString(new_length)); 3140 } 3141 3142 // If the regexp isn't global, only match once. 3143 if (!regexp_handle->GetFlags().is_global()) { 3144 if (start > 0) { 3145 String::WriteToFlat(*subject_handle, 3146 answer->GetChars(), 3147 0, 3148 start); 3149 } 3150 if (end < length) { 3151 String::WriteToFlat(*subject_handle, 3152 answer->GetChars() + start, 3153 end, 3154 length); 3155 } 3156 return *answer; 3157 } 3158 3159 int prev = 0; // Index of end of last match. 3160 int next = 0; // Start of next search (prev unless last match was empty). 3161 int position = 0; 3162 3163 do { 3164 if (prev < start) { 3165 // Add substring subject[prev;start] to answer string. 3166 String::WriteToFlat(*subject_handle, 3167 answer->GetChars() + position, 3168 prev, 3169 start); 3170 position += start - prev; 3171 } 3172 prev = end; 3173 next = end; 3174 // Continue from where the match ended, unless it was an empty match. 3175 if (start == end) { 3176 next++; 3177 if (next > length) break; 3178 } 3179 match = RegExpImpl::Exec(regexp_handle, 3180 subject_handle, 3181 next, 3182 last_match_info_handle); 3183 if (match.is_null()) return Failure::Exception(); 3184 if (match->IsNull()) break; 3185 3186 ASSERT(last_match_info_handle->HasFastElements()); 3187 HandleScope loop_scope(isolate); 3188 { 3189 AssertNoAllocation match_info_array_is_not_in_a_handle; 3190 FixedArray* match_info_array = 3191 FixedArray::cast(last_match_info_handle->elements()); 3192 start = RegExpImpl::GetCapture(match_info_array, 0); 3193 end = RegExpImpl::GetCapture(match_info_array, 1); 3194 } 3195 } while (true); 3196 3197 if (prev < length) { 3198 // Add substring subject[prev;length] to answer string. 3199 String::WriteToFlat(*subject_handle, 3200 answer->GetChars() + position, 3201 prev, 3202 length); 3203 position += length - prev; 3204 } 3205 3206 if (position == 0) { 3207 return isolate->heap()->empty_string(); 3208 } 3209 3210 // Shorten string and fill 3211 int string_size = ResultSeqString::SizeFor(position); 3212 int allocated_string_size = ResultSeqString::SizeFor(new_length); 3213 int delta = allocated_string_size - string_size; 3214 3215 answer->set_length(position); 3216 if (delta == 0) return *answer; 3217 3218 Address end_of_string = answer->address() + string_size; 3219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta); 3220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { 3221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); 3222 } 3223 3224 return *answer; 3225 } 3226 3227 3228 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) { 3229 ASSERT(args.length() == 4); 3230 3231 CONVERT_ARG_CHECKED(String, subject, 0); 3232 if (!subject->IsFlat()) { 3233 Object* flat_subject; 3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten(); 3235 if (!maybe_flat_subject->ToObject(&flat_subject)) { 3236 return maybe_flat_subject; 3237 } 3238 } 3239 subject = String::cast(flat_subject); 3240 } 3241 3242 CONVERT_ARG_CHECKED(String, replacement, 2); 3243 if (!replacement->IsFlat()) { 3244 Object* flat_replacement; 3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten(); 3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) { 3247 return maybe_flat_replacement; 3248 } 3249 } 3250 replacement = String::cast(flat_replacement); 3251 } 3252 3253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1); 3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3); 3255 3256 ASSERT(last_match_info->HasFastElements()); 3257 3258 if (replacement->length() == 0) { 3259 if (subject->HasOnlyAsciiChars()) { 3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>( 3261 isolate, subject, regexp, last_match_info); 3262 } else { 3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>( 3264 isolate, subject, regexp, last_match_info); 3265 } 3266 } 3267 3268 return StringReplaceRegExpWithString(isolate, 3269 subject, 3270 regexp, 3271 replacement, 3272 last_match_info); 3273 } 3274 3275 3276 Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate, 3277 Handle<String> subject, 3278 Handle<String> search, 3279 Handle<String> replace, 3280 bool* found, 3281 int recursion_limit) { 3282 if (recursion_limit == 0) return Handle<String>::null(); 3283 if (subject->IsConsString()) { 3284 ConsString* cons = ConsString::cast(*subject); 3285 Handle<String> first = Handle<String>(cons->first()); 3286 Handle<String> second = Handle<String>(cons->second()); 3287 Handle<String> new_first = 3288 StringReplaceOneCharWithString(isolate, 3289 first, 3290 search, 3291 replace, 3292 found, 3293 recursion_limit - 1); 3294 if (*found) return isolate->factory()->NewConsString(new_first, second); 3295 if (new_first.is_null()) return new_first; 3296 3297 Handle<String> new_second = 3298 StringReplaceOneCharWithString(isolate, 3299 second, 3300 search, 3301 replace, 3302 found, 3303 recursion_limit - 1); 3304 if (*found) return isolate->factory()->NewConsString(first, new_second); 3305 if (new_second.is_null()) return new_second; 3306 3307 return subject; 3308 } else { 3309 int index = StringMatch(isolate, subject, search, 0); 3310 if (index == -1) return subject; 3311 *found = true; 3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); 3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); 3314 Handle<String> second = 3315 isolate->factory()->NewSubString(subject, index + 1, subject->length()); 3316 return isolate->factory()->NewConsString(cons1, second); 3317 } 3318 } 3319 3320 3321 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { 3322 ASSERT(args.length() == 3); 3323 HandleScope scope(isolate); 3324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); 3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); 3327 3328 // If the cons string tree is too deep, we simply abort the recursion and 3329 // retry with a flattened subject string. 3330 const int kRecursionLimit = 0x1000; 3331 bool found = false; 3332 Handle<String> result = 3333 Runtime::StringReplaceOneCharWithString(isolate, 3334 subject, 3335 search, 3336 replace, 3337 &found, 3338 kRecursionLimit); 3339 if (!result.is_null()) return *result; 3340 return *Runtime::StringReplaceOneCharWithString(isolate, 3341 FlattenGetString(subject), 3342 search, 3343 replace, 3344 &found, 3345 kRecursionLimit); 3346 } 3347 3348 3349 // Perform string match of pattern on subject, starting at start index. 3350 // Caller must ensure that 0 <= start_index <= sub->length(), 3351 // and should check that pat->length() + start_index <= sub->length(). 3352 int Runtime::StringMatch(Isolate* isolate, 3353 Handle<String> sub, 3354 Handle<String> pat, 3355 int start_index) { 3356 ASSERT(0 <= start_index); 3357 ASSERT(start_index <= sub->length()); 3358 3359 int pattern_length = pat->length(); 3360 if (pattern_length == 0) return start_index; 3361 3362 int subject_length = sub->length(); 3363 if (start_index + pattern_length > subject_length) return -1; 3364 3365 if (!sub->IsFlat()) FlattenString(sub); 3366 if (!pat->IsFlat()) FlattenString(pat); 3367 3368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 3369 // Extract flattened substrings of cons strings before determining asciiness. 3370 String::FlatContent seq_sub = sub->GetFlatContent(); 3371 String::FlatContent seq_pat = pat->GetFlatContent(); 3372 3373 // dispatch on type of strings 3374 if (seq_pat.IsAscii()) { 3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector(); 3376 if (seq_sub.IsAscii()) { 3377 return SearchString(isolate, 3378 seq_sub.ToAsciiVector(), 3379 pat_vector, 3380 start_index); 3381 } 3382 return SearchString(isolate, 3383 seq_sub.ToUC16Vector(), 3384 pat_vector, 3385 start_index); 3386 } 3387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); 3388 if (seq_sub.IsAscii()) { 3389 return SearchString(isolate, 3390 seq_sub.ToAsciiVector(), 3391 pat_vector, 3392 start_index); 3393 } 3394 return SearchString(isolate, 3395 seq_sub.ToUC16Vector(), 3396 pat_vector, 3397 start_index); 3398 } 3399 3400 3401 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { 3402 HandleScope scope(isolate); // create a new handle scope 3403 ASSERT(args.length() == 3); 3404 3405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 3407 3408 Object* index = args[2]; 3409 uint32_t start_index; 3410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 3411 3412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 3413 int position = 3414 Runtime::StringMatch(isolate, sub, pat, start_index); 3415 return Smi::FromInt(position); 3416 } 3417 3418 3419 template <typename schar, typename pchar> 3420 static int StringMatchBackwards(Vector<const schar> subject, 3421 Vector<const pchar> pattern, 3422 int idx) { 3423 int pattern_length = pattern.length(); 3424 ASSERT(pattern_length >= 1); 3425 ASSERT(idx + pattern_length <= subject.length()); 3426 3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 3428 for (int i = 0; i < pattern_length; i++) { 3429 uc16 c = pattern[i]; 3430 if (c > String::kMaxAsciiCharCode) { 3431 return -1; 3432 } 3433 } 3434 } 3435 3436 pchar pattern_first_char = pattern[0]; 3437 for (int i = idx; i >= 0; i--) { 3438 if (subject[i] != pattern_first_char) continue; 3439 int j = 1; 3440 while (j < pattern_length) { 3441 if (pattern[j] != subject[i+j]) { 3442 break; 3443 } 3444 j++; 3445 } 3446 if (j == pattern_length) { 3447 return i; 3448 } 3449 } 3450 return -1; 3451 } 3452 3453 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { 3454 HandleScope scope(isolate); // create a new handle scope 3455 ASSERT(args.length() == 3); 3456 3457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 3459 3460 Object* index = args[2]; 3461 uint32_t start_index; 3462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 3463 3464 uint32_t pat_length = pat->length(); 3465 uint32_t sub_length = sub->length(); 3466 3467 if (start_index + pat_length > sub_length) { 3468 start_index = sub_length - pat_length; 3469 } 3470 3471 if (pat_length == 0) { 3472 return Smi::FromInt(start_index); 3473 } 3474 3475 if (!sub->IsFlat()) FlattenString(sub); 3476 if (!pat->IsFlat()) FlattenString(pat); 3477 3478 int position = -1; 3479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid 3480 3481 String::FlatContent sub_content = sub->GetFlatContent(); 3482 String::FlatContent pat_content = pat->GetFlatContent(); 3483 3484 if (pat_content.IsAscii()) { 3485 Vector<const char> pat_vector = pat_content.ToAsciiVector(); 3486 if (sub_content.IsAscii()) { 3487 position = StringMatchBackwards(sub_content.ToAsciiVector(), 3488 pat_vector, 3489 start_index); 3490 } else { 3491 position = StringMatchBackwards(sub_content.ToUC16Vector(), 3492 pat_vector, 3493 start_index); 3494 } 3495 } else { 3496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); 3497 if (sub_content.IsAscii()) { 3498 position = StringMatchBackwards(sub_content.ToAsciiVector(), 3499 pat_vector, 3500 start_index); 3501 } else { 3502 position = StringMatchBackwards(sub_content.ToUC16Vector(), 3503 pat_vector, 3504 start_index); 3505 } 3506 } 3507 3508 return Smi::FromInt(position); 3509 } 3510 3511 3512 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { 3513 NoHandleAllocation ha; 3514 ASSERT(args.length() == 2); 3515 3516 CONVERT_ARG_CHECKED(String, str1, 0); 3517 CONVERT_ARG_CHECKED(String, str2, 1); 3518 3519 if (str1 == str2) return Smi::FromInt(0); // Equal. 3520 int str1_length = str1->length(); 3521 int str2_length = str2->length(); 3522 3523 // Decide trivial cases without flattening. 3524 if (str1_length == 0) { 3525 if (str2_length == 0) return Smi::FromInt(0); // Equal. 3526 return Smi::FromInt(-str2_length); 3527 } else { 3528 if (str2_length == 0) return Smi::FromInt(str1_length); 3529 } 3530 3531 int end = str1_length < str2_length ? str1_length : str2_length; 3532 3533 // No need to flatten if we are going to find the answer on the first 3534 // character. At this point we know there is at least one character 3535 // in each string, due to the trivial case handling above. 3536 int d = str1->Get(0) - str2->Get(0); 3537 if (d != 0) return Smi::FromInt(d); 3538 3539 str1->TryFlatten(); 3540 str2->TryFlatten(); 3541 3542 StringInputBuffer& buf1 = 3543 *isolate->runtime_state()->string_locale_compare_buf1(); 3544 StringInputBuffer& buf2 = 3545 *isolate->runtime_state()->string_locale_compare_buf2(); 3546 3547 buf1.Reset(str1); 3548 buf2.Reset(str2); 3549 3550 for (int i = 0; i < end; i++) { 3551 uint16_t char1 = buf1.GetNext(); 3552 uint16_t char2 = buf2.GetNext(); 3553 if (char1 != char2) return Smi::FromInt(char1 - char2); 3554 } 3555 3556 return Smi::FromInt(str1_length - str2_length); 3557 } 3558 3559 3560 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { 3561 NoHandleAllocation ha; 3562 ASSERT(args.length() == 3); 3563 3564 CONVERT_ARG_CHECKED(String, value, 0); 3565 int start, end; 3566 // We have a fast integer-only case here to avoid a conversion to double in 3567 // the common case where from and to are Smis. 3568 if (args[1]->IsSmi() && args[2]->IsSmi()) { 3569 CONVERT_SMI_ARG_CHECKED(from_number, 1); 3570 CONVERT_SMI_ARG_CHECKED(to_number, 2); 3571 start = from_number; 3572 end = to_number; 3573 } else { 3574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); 3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); 3576 start = FastD2I(from_number); 3577 end = FastD2I(to_number); 3578 } 3579 RUNTIME_ASSERT(end >= start); 3580 RUNTIME_ASSERT(start >= 0); 3581 RUNTIME_ASSERT(end <= value->length()); 3582 isolate->counters()->sub_string_runtime()->Increment(); 3583 return value->SubString(start, end); 3584 } 3585 3586 3587 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { 3588 ASSERT_EQ(3, args.length()); 3589 3590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); 3593 HandleScope handles; 3594 3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info); 3596 3597 if (match.is_null()) { 3598 return Failure::Exception(); 3599 } 3600 if (match->IsNull()) { 3601 return isolate->heap()->null_value(); 3602 } 3603 int length = subject->length(); 3604 3605 ZoneScope zone_space(isolate, DELETE_ON_EXIT); 3606 ZoneList<int> offsets(8); 3607 int start; 3608 int end; 3609 do { 3610 { 3611 AssertNoAllocation no_alloc; 3612 FixedArray* elements = FixedArray::cast(regexp_info->elements()); 3613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value(); 3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value(); 3615 } 3616 offsets.Add(start); 3617 offsets.Add(end); 3618 if (start == end) if (++end > length) break; 3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info); 3620 if (match.is_null()) { 3621 return Failure::Exception(); 3622 } 3623 } while (!match->IsNull()); 3624 int matches = offsets.length() / 2; 3625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); 3626 Handle<String> substring = isolate->factory()-> 3627 NewSubString(subject, offsets.at(0), offsets.at(1)); 3628 elements->set(0, *substring); 3629 for (int i = 1; i < matches ; i++) { 3630 int from = offsets.at(i * 2); 3631 int to = offsets.at(i * 2 + 1); 3632 Handle<String> substring = isolate->factory()-> 3633 NewProperSubString(subject, from, to); 3634 elements->set(i, *substring); 3635 } 3636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); 3637 result->set_length(Smi::FromInt(matches)); 3638 return *result; 3639 } 3640 3641 3642 // Two smis before and after the match, for very long strings. 3643 const int kMaxBuilderEntriesPerRegExpMatch = 5; 3644 3645 3646 static void SetLastMatchInfoNoCaptures(Handle<String> subject, 3647 Handle<JSArray> last_match_info, 3648 int match_start, 3649 int match_end) { 3650 // Fill last_match_info with a single capture. 3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead); 3652 AssertNoAllocation no_gc; 3653 FixedArray* elements = FixedArray::cast(last_match_info->elements()); 3654 RegExpImpl::SetLastCaptureCount(elements, 2); 3655 RegExpImpl::SetLastInput(elements, *subject); 3656 RegExpImpl::SetLastSubject(elements, *subject); 3657 RegExpImpl::SetCapture(elements, 0, match_start); 3658 RegExpImpl::SetCapture(elements, 1, match_end); 3659 } 3660 3661 3662 template <typename SubjectChar, typename PatternChar> 3663 static bool SearchStringMultiple(Isolate* isolate, 3664 Vector<const SubjectChar> subject, 3665 Vector<const PatternChar> pattern, 3666 String* pattern_string, 3667 FixedArrayBuilder* builder, 3668 int* match_pos) { 3669 int pos = *match_pos; 3670 int subject_length = subject.length(); 3671 int pattern_length = pattern.length(); 3672 int max_search_start = subject_length - pattern_length; 3673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); 3674 while (pos <= max_search_start) { 3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { 3676 *match_pos = pos; 3677 return false; 3678 } 3679 // Position of end of previous match. 3680 int match_end = pos + pattern_length; 3681 int new_pos = search.Search(subject, match_end); 3682 if (new_pos >= 0) { 3683 // A match. 3684 if (new_pos > match_end) { 3685 ReplacementStringBuilder::AddSubjectSlice(builder, 3686 match_end, 3687 new_pos); 3688 } 3689 pos = new_pos; 3690 builder->Add(pattern_string); 3691 } else { 3692 break; 3693 } 3694 } 3695 3696 if (pos < max_search_start) { 3697 ReplacementStringBuilder::AddSubjectSlice(builder, 3698 pos + pattern_length, 3699 subject_length); 3700 } 3701 *match_pos = pos; 3702 return true; 3703 } 3704 3705 3706 static bool SearchStringMultiple(Isolate* isolate, 3707 Handle<String> subject, 3708 Handle<String> pattern, 3709 Handle<JSArray> last_match_info, 3710 FixedArrayBuilder* builder) { 3711 ASSERT(subject->IsFlat()); 3712 ASSERT(pattern->IsFlat()); 3713 3714 // Treating as if a previous match was before first character. 3715 int match_pos = -pattern->length(); 3716 3717 for (;;) { // Break when search complete. 3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3719 AssertNoAllocation no_gc; 3720 String::FlatContent subject_content = subject->GetFlatContent(); 3721 String::FlatContent pattern_content = pattern->GetFlatContent(); 3722 if (subject_content.IsAscii()) { 3723 Vector<const char> subject_vector = subject_content.ToAsciiVector(); 3724 if (pattern_content.IsAscii()) { 3725 if (SearchStringMultiple(isolate, 3726 subject_vector, 3727 pattern_content.ToAsciiVector(), 3728 *pattern, 3729 builder, 3730 &match_pos)) break; 3731 } else { 3732 if (SearchStringMultiple(isolate, 3733 subject_vector, 3734 pattern_content.ToUC16Vector(), 3735 *pattern, 3736 builder, 3737 &match_pos)) break; 3738 } 3739 } else { 3740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); 3741 if (pattern_content.IsAscii()) { 3742 if (SearchStringMultiple(isolate, 3743 subject_vector, 3744 pattern_content.ToAsciiVector(), 3745 *pattern, 3746 builder, 3747 &match_pos)) break; 3748 } else { 3749 if (SearchStringMultiple(isolate, 3750 subject_vector, 3751 pattern_content.ToUC16Vector(), 3752 *pattern, 3753 builder, 3754 &match_pos)) break; 3755 } 3756 } 3757 } 3758 3759 if (match_pos >= 0) { 3760 SetLastMatchInfoNoCaptures(subject, 3761 last_match_info, 3762 match_pos, 3763 match_pos + pattern->length()); 3764 return true; 3765 } 3766 return false; // No matches at all. 3767 } 3768 3769 3770 static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple( 3771 Isolate* isolate, 3772 Handle<String> subject, 3773 Handle<JSRegExp> regexp, 3774 Handle<JSArray> last_match_array, 3775 FixedArrayBuilder* builder) { 3776 ASSERT(subject->IsFlat()); 3777 int match_start = -1; 3778 int match_end = 0; 3779 int pos = 0; 3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); 3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; 3782 3783 OffsetsVector registers(required_registers, isolate); 3784 Vector<int32_t> register_vector(registers.vector(), registers.length()); 3785 int subject_length = subject->length(); 3786 bool first = true; 3787 3788 for (;;) { // Break on failure, return on exception. 3789 RegExpImpl::IrregexpResult result = 3790 RegExpImpl::IrregexpExecOnce(regexp, 3791 subject, 3792 pos, 3793 register_vector); 3794 if (result == RegExpImpl::RE_SUCCESS) { 3795 match_start = register_vector[0]; 3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3797 if (match_end < match_start) { 3798 ReplacementStringBuilder::AddSubjectSlice(builder, 3799 match_end, 3800 match_start); 3801 } 3802 match_end = register_vector[1]; 3803 HandleScope loop_scope(isolate); 3804 if (!first) { 3805 builder->Add(*isolate->factory()->NewProperSubString(subject, 3806 match_start, 3807 match_end)); 3808 } else { 3809 builder->Add(*isolate->factory()->NewSubString(subject, 3810 match_start, 3811 match_end)); 3812 } 3813 if (match_start != match_end) { 3814 pos = match_end; 3815 } else { 3816 pos = match_end + 1; 3817 if (pos > subject_length) break; 3818 } 3819 } else if (result == RegExpImpl::RE_FAILURE) { 3820 break; 3821 } else { 3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 3823 return result; 3824 } 3825 first = false; 3826 } 3827 3828 if (match_start >= 0) { 3829 if (match_end < subject_length) { 3830 ReplacementStringBuilder::AddSubjectSlice(builder, 3831 match_end, 3832 subject_length); 3833 } 3834 SetLastMatchInfoNoCaptures(subject, 3835 last_match_array, 3836 match_start, 3837 match_end); 3838 return RegExpImpl::RE_SUCCESS; 3839 } else { 3840 return RegExpImpl::RE_FAILURE; // No matches at all. 3841 } 3842 } 3843 3844 3845 static RegExpImpl::IrregexpResult SearchRegExpMultiple( 3846 Isolate* isolate, 3847 Handle<String> subject, 3848 Handle<JSRegExp> regexp, 3849 Handle<JSArray> last_match_array, 3850 FixedArrayBuilder* builder) { 3851 3852 ASSERT(subject->IsFlat()); 3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject); 3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION; 3855 3856 OffsetsVector registers(required_registers, isolate); 3857 Vector<int32_t> register_vector(registers.vector(), registers.length()); 3858 3859 RegExpImpl::IrregexpResult result = 3860 RegExpImpl::IrregexpExecOnce(regexp, 3861 subject, 3862 0, 3863 register_vector); 3864 3865 int capture_count = regexp->CaptureCount(); 3866 int subject_length = subject->length(); 3867 3868 // Position to search from. 3869 int pos = 0; 3870 // End of previous match. Differs from pos if match was empty. 3871 int match_end = 0; 3872 if (result == RegExpImpl::RE_SUCCESS) { 3873 // Need to keep a copy of the previous match for creating last_match_info 3874 // at the end, so we have two vectors that we swap between. 3875 OffsetsVector registers2(required_registers, isolate); 3876 Vector<int> prev_register_vector(registers2.vector(), registers2.length()); 3877 bool first = true; 3878 do { 3879 int match_start = register_vector[0]; 3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 3881 if (match_end < match_start) { 3882 ReplacementStringBuilder::AddSubjectSlice(builder, 3883 match_end, 3884 match_start); 3885 } 3886 match_end = register_vector[1]; 3887 3888 { 3889 // Avoid accumulating new handles inside loop. 3890 HandleScope temp_scope(isolate); 3891 // Arguments array to replace function is match, captures, index and 3892 // subject, i.e., 3 + capture count in total. 3893 Handle<FixedArray> elements = 3894 isolate->factory()->NewFixedArray(3 + capture_count); 3895 Handle<String> match; 3896 if (!first) { 3897 match = isolate->factory()->NewProperSubString(subject, 3898 match_start, 3899 match_end); 3900 } else { 3901 match = isolate->factory()->NewSubString(subject, 3902 match_start, 3903 match_end); 3904 } 3905 elements->set(0, *match); 3906 for (int i = 1; i <= capture_count; i++) { 3907 int start = register_vector[i * 2]; 3908 if (start >= 0) { 3909 int end = register_vector[i * 2 + 1]; 3910 ASSERT(start <= end); 3911 Handle<String> substring; 3912 if (!first) { 3913 substring = isolate->factory()->NewProperSubString(subject, 3914 start, 3915 end); 3916 } else { 3917 substring = isolate->factory()->NewSubString(subject, start, end); 3918 } 3919 elements->set(i, *substring); 3920 } else { 3921 ASSERT(register_vector[i * 2 + 1] < 0); 3922 elements->set(i, isolate->heap()->undefined_value()); 3923 } 3924 } 3925 elements->set(capture_count + 1, Smi::FromInt(match_start)); 3926 elements->set(capture_count + 2, *subject); 3927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements)); 3928 } 3929 // Swap register vectors, so the last successful match is in 3930 // prev_register_vector. 3931 Vector<int32_t> tmp = prev_register_vector; 3932 prev_register_vector = register_vector; 3933 register_vector = tmp; 3934 3935 if (match_end > match_start) { 3936 pos = match_end; 3937 } else { 3938 pos = match_end + 1; 3939 if (pos > subject_length) { 3940 break; 3941 } 3942 } 3943 3944 result = RegExpImpl::IrregexpExecOnce(regexp, 3945 subject, 3946 pos, 3947 register_vector); 3948 first = false; 3949 } while (result == RegExpImpl::RE_SUCCESS); 3950 3951 if (result != RegExpImpl::RE_EXCEPTION) { 3952 // Finished matching, with at least one match. 3953 if (match_end < subject_length) { 3954 ReplacementStringBuilder::AddSubjectSlice(builder, 3955 match_end, 3956 subject_length); 3957 } 3958 3959 int last_match_capture_count = (capture_count + 1) * 2; 3960 int last_match_array_size = 3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead; 3962 last_match_array->EnsureSize(last_match_array_size); 3963 AssertNoAllocation no_gc; 3964 FixedArray* elements = FixedArray::cast(last_match_array->elements()); 3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count); 3966 RegExpImpl::SetLastSubject(elements, *subject); 3967 RegExpImpl::SetLastInput(elements, *subject); 3968 for (int i = 0; i < last_match_capture_count; i++) { 3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]); 3970 } 3971 return RegExpImpl::RE_SUCCESS; 3972 } 3973 } 3974 // No matches at all, return failure or exception result directly. 3975 return result; 3976 } 3977 3978 3979 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { 3980 ASSERT(args.length() == 4); 3981 HandleScope handles(isolate); 3982 3983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 3984 if (!subject->IsFlat()) FlattenString(subject); 3985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); 3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); 3988 3989 ASSERT(last_match_info->HasFastElements()); 3990 ASSERT(regexp->GetFlags().is_global()); 3991 Handle<FixedArray> result_elements; 3992 if (result_array->HasFastElements()) { 3993 result_elements = 3994 Handle<FixedArray>(FixedArray::cast(result_array->elements())); 3995 } 3996 if (result_elements.is_null() || result_elements->length() < 16) { 3997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 3998 } 3999 FixedArrayBuilder builder(result_elements); 4000 4001 if (regexp->TypeTag() == JSRegExp::ATOM) { 4002 Handle<String> pattern( 4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex))); 4004 ASSERT(pattern->IsFlat()); 4005 if (SearchStringMultiple(isolate, subject, pattern, 4006 last_match_info, &builder)) { 4007 return *builder.ToJSArray(result_array); 4008 } 4009 return isolate->heap()->null_value(); 4010 } 4011 4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP); 4013 4014 RegExpImpl::IrregexpResult result; 4015 if (regexp->CaptureCount() == 0) { 4016 result = SearchRegExpNoCaptureMultiple(isolate, 4017 subject, 4018 regexp, 4019 last_match_info, 4020 &builder); 4021 } else { 4022 result = SearchRegExpMultiple(isolate, 4023 subject, 4024 regexp, 4025 last_match_info, 4026 &builder); 4027 } 4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array); 4029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value(); 4030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION); 4031 return Failure::Exception(); 4032 } 4033 4034 4035 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { 4036 NoHandleAllocation ha; 4037 ASSERT(args.length() == 2); 4038 CONVERT_SMI_ARG_CHECKED(radix, 1); 4039 RUNTIME_ASSERT(2 <= radix && radix <= 36); 4040 4041 // Fast case where the result is a one character string. 4042 if (args[0]->IsSmi()) { 4043 int value = args.smi_at(0); 4044 if (value >= 0 && value < radix) { 4045 // Character array used for conversion. 4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 4047 return isolate->heap()-> 4048 LookupSingleCharacterStringFromCode(kCharTable[value]); 4049 } 4050 } 4051 4052 // Slow case. 4053 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4054 if (isnan(value)) { 4055 return *isolate->factory()->nan_symbol(); 4056 } 4057 if (isinf(value)) { 4058 if (value < 0) { 4059 return *isolate->factory()->minus_infinity_symbol(); 4060 } 4061 return *isolate->factory()->infinity_symbol(); 4062 } 4063 char* str = DoubleToRadixCString(value, radix); 4064 MaybeObject* result = 4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str)); 4066 DeleteArray(str); 4067 return result; 4068 } 4069 4070 4071 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { 4072 NoHandleAllocation ha; 4073 ASSERT(args.length() == 2); 4074 4075 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4076 if (isnan(value)) { 4077 return *isolate->factory()->nan_symbol(); 4078 } 4079 if (isinf(value)) { 4080 if (value < 0) { 4081 return *isolate->factory()->minus_infinity_symbol(); 4082 } 4083 return *isolate->factory()->infinity_symbol(); 4084 } 4085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4086 int f = FastD2I(f_number); 4087 RUNTIME_ASSERT(f >= 0); 4088 char* str = DoubleToFixedCString(value, f); 4089 MaybeObject* res = 4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str)); 4091 DeleteArray(str); 4092 return res; 4093 } 4094 4095 4096 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { 4097 NoHandleAllocation ha; 4098 ASSERT(args.length() == 2); 4099 4100 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4101 if (isnan(value)) { 4102 return *isolate->factory()->nan_symbol(); 4103 } 4104 if (isinf(value)) { 4105 if (value < 0) { 4106 return *isolate->factory()->minus_infinity_symbol(); 4107 } 4108 return *isolate->factory()->infinity_symbol(); 4109 } 4110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4111 int f = FastD2I(f_number); 4112 RUNTIME_ASSERT(f >= -1 && f <= 20); 4113 char* str = DoubleToExponentialCString(value, f); 4114 MaybeObject* res = 4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str)); 4116 DeleteArray(str); 4117 return res; 4118 } 4119 4120 4121 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { 4122 NoHandleAllocation ha; 4123 ASSERT(args.length() == 2); 4124 4125 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4126 if (isnan(value)) { 4127 return *isolate->factory()->nan_symbol(); 4128 } 4129 if (isinf(value)) { 4130 if (value < 0) { 4131 return *isolate->factory()->minus_infinity_symbol(); 4132 } 4133 return *isolate->factory()->infinity_symbol(); 4134 } 4135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4136 int f = FastD2I(f_number); 4137 RUNTIME_ASSERT(f >= 1 && f <= 21); 4138 char* str = DoubleToPrecisionCString(value, f); 4139 MaybeObject* res = 4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str)); 4141 DeleteArray(str); 4142 return res; 4143 } 4144 4145 4146 // Returns a single character string where first character equals 4147 // string->Get(index). 4148 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 4149 if (index < static_cast<uint32_t>(string->length())) { 4150 string->TryFlatten(); 4151 return LookupSingleCharacterStringFromCode( 4152 string->Get(index)); 4153 } 4154 return Execution::CharAt(string, index); 4155 } 4156 4157 4158 MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, 4159 Handle<Object> object, 4160 uint32_t index) { 4161 // Handle [] indexing on Strings 4162 if (object->IsString()) { 4163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 4164 if (!result->IsUndefined()) return *result; 4165 } 4166 4167 // Handle [] indexing on String objects 4168 if (object->IsStringObjectWithCharacterAt(index)) { 4169 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 4170 Handle<Object> result = 4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 4172 if (!result->IsUndefined()) return *result; 4173 } 4174 4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 4176 return object->GetPrototype()->GetElement(index); 4177 } 4178 4179 return object->GetElement(index); 4180 } 4181 4182 4183 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, 4184 Handle<Object> object, 4185 Handle<Object> key) { 4186 HandleScope scope(isolate); 4187 4188 if (object->IsUndefined() || object->IsNull()) { 4189 Handle<Object> args[2] = { key, object }; 4190 Handle<Object> error = 4191 isolate->factory()->NewTypeError("non_object_property_load", 4192 HandleVector(args, 2)); 4193 return isolate->Throw(*error); 4194 } 4195 4196 // Check if the given key is an array index. 4197 uint32_t index; 4198 if (key->ToArrayIndex(&index)) { 4199 return GetElementOrCharAt(isolate, object, index); 4200 } 4201 4202 // Convert the key to a string - possibly by calling back into JavaScript. 4203 Handle<String> name; 4204 if (key->IsString()) { 4205 name = Handle<String>::cast(key); 4206 } else { 4207 bool has_pending_exception = false; 4208 Handle<Object> converted = 4209 Execution::ToString(key, &has_pending_exception); 4210 if (has_pending_exception) return Failure::Exception(); 4211 name = Handle<String>::cast(converted); 4212 } 4213 4214 // Check if the name is trivially convertible to an index and get 4215 // the element if so. 4216 if (name->AsArrayIndex(&index)) { 4217 return GetElementOrCharAt(isolate, object, index); 4218 } else { 4219 return object->GetProperty(*name); 4220 } 4221 } 4222 4223 4224 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { 4225 NoHandleAllocation ha; 4226 ASSERT(args.length() == 2); 4227 4228 Handle<Object> object = args.at<Object>(0); 4229 Handle<Object> key = args.at<Object>(1); 4230 4231 return Runtime::GetObjectProperty(isolate, object, key); 4232 } 4233 4234 4235 // KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric. 4236 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { 4237 NoHandleAllocation ha; 4238 ASSERT(args.length() == 2); 4239 4240 // Fast cases for getting named properties of the receiver JSObject 4241 // itself. 4242 // 4243 // The global proxy objects has to be excluded since LocalLookup on 4244 // the global proxy object can return a valid result even though the 4245 // global proxy object never has properties. This is the case 4246 // because the global proxy object forwards everything to its hidden 4247 // prototype including local lookups. 4248 // 4249 // Additionally, we need to make sure that we do not cache results 4250 // for objects that require access checks. 4251 if (args[0]->IsJSObject()) { 4252 if (!args[0]->IsJSGlobalProxy() && 4253 !args[0]->IsAccessCheckNeeded() && 4254 args[1]->IsString()) { 4255 JSObject* receiver = JSObject::cast(args[0]); 4256 String* key = String::cast(args[1]); 4257 if (receiver->HasFastProperties()) { 4258 // Attempt to use lookup cache. 4259 Map* receiver_map = receiver->map(); 4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); 4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key); 4262 if (offset != -1) { 4263 Object* value = receiver->FastPropertyAt(offset); 4264 return value->IsTheHole() 4265 ? isolate->heap()->undefined_value() 4266 : value; 4267 } 4268 // Lookup cache miss. Perform lookup and update the cache if 4269 // appropriate. 4270 LookupResult result(isolate); 4271 receiver->LocalLookup(key, &result); 4272 if (result.IsFound() && result.type() == FIELD) { 4273 int offset = result.GetFieldIndex(); 4274 keyed_lookup_cache->Update(receiver_map, key, offset); 4275 return receiver->FastPropertyAt(offset); 4276 } 4277 } else { 4278 // Attempt dictionary lookup. 4279 StringDictionary* dictionary = receiver->property_dictionary(); 4280 int entry = dictionary->FindEntry(key); 4281 if ((entry != StringDictionary::kNotFound) && 4282 (dictionary->DetailsAt(entry).type() == NORMAL)) { 4283 Object* value = dictionary->ValueAt(entry); 4284 if (!receiver->IsGlobalObject()) return value; 4285 value = JSGlobalPropertyCell::cast(value)->value(); 4286 if (!value->IsTheHole()) return value; 4287 // If value is the hole do the general lookup. 4288 } 4289 } 4290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { 4291 // JSObject without a string key. If the key is a Smi, check for a 4292 // definite out-of-bounds access to elements, which is a strong indicator 4293 // that subsequent accesses will also call the runtime. Proactively 4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of 4295 // doubles for those future calls in the case that the elements would 4296 // become FAST_DOUBLE_ELEMENTS. 4297 Handle<JSObject> js_object(args.at<JSObject>(0)); 4298 ElementsKind elements_kind = js_object->GetElementsKind(); 4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || 4300 elements_kind == FAST_DOUBLE_ELEMENTS) { 4301 FixedArrayBase* elements = js_object->elements(); 4302 if (args.at<Smi>(1)->value() >= elements->length()) { 4303 MaybeObject* maybe_object = TransitionElements(js_object, 4304 FAST_ELEMENTS, 4305 isolate); 4306 if (maybe_object->IsFailure()) return maybe_object; 4307 } 4308 } 4309 } 4310 } else if (args[0]->IsString() && args[1]->IsSmi()) { 4311 // Fast case for string indexing using [] with a smi index. 4312 HandleScope scope(isolate); 4313 Handle<String> str = args.at<String>(0); 4314 int index = args.smi_at(1); 4315 if (index >= 0 && index < str->length()) { 4316 Handle<Object> result = GetCharAt(str, index); 4317 return *result; 4318 } 4319 } 4320 4321 // Fall back to GetObjectProperty. 4322 return Runtime::GetObjectProperty(isolate, 4323 args.at<Object>(0), 4324 args.at<Object>(1)); 4325 } 4326 4327 4328 static bool IsValidAccessor(Handle<Object> obj) { 4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull(); 4330 } 4331 4332 4333 // Implements part of 8.12.9 DefineOwnProperty. 4334 // There are 3 cases that lead here: 4335 // Step 4b - define a new accessor property. 4336 // Steps 9c & 12 - replace an existing data property with an accessor property. 4337 // Step 12 - update an existing accessor property with an accessor or generic 4338 // descriptor. 4339 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { 4340 ASSERT(args.length() == 5); 4341 HandleScope scope(isolate); 4342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 4343 RUNTIME_ASSERT(!obj->IsNull()); 4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 4346 RUNTIME_ASSERT(IsValidAccessor(getter)); 4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 4348 RUNTIME_ASSERT(IsValidAccessor(setter)); 4349 CONVERT_SMI_ARG_CHECKED(unchecked, 4); 4350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 4352 4353 bool fast = obj->HasFastProperties(); 4354 JSObject::DefineAccessor(obj, name, getter, setter, attr); 4355 if (fast) JSObject::TransformToFastProperties(obj, 0); 4356 return isolate->heap()->undefined_value(); 4357 } 4358 4359 // Implements part of 8.12.9 DefineOwnProperty. 4360 // There are 3 cases that lead here: 4361 // Step 4a - define a new data property. 4362 // Steps 9b & 12 - replace an existing accessor property with a data property. 4363 // Step 12 - update an existing data property with a data or generic 4364 // descriptor. 4365 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { 4366 ASSERT(args.length() == 4); 4367 HandleScope scope(isolate); 4368 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); 4369 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 4370 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2); 4371 CONVERT_SMI_ARG_CHECKED(unchecked, 3); 4372 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4373 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 4374 4375 LookupResult result(isolate); 4376 js_object->LocalLookupRealNamedProperty(*name, &result); 4377 4378 // Special case for callback properties. 4379 if (result.IsFound() && result.type() == CALLBACKS) { 4380 Object* callback = result.GetCallbackObject(); 4381 // To be compatible with Safari we do not change the value on API objects 4382 // in Object.defineProperty(). Firefox disagrees here, and actually changes 4383 // the value. 4384 if (callback->IsAccessorInfo()) { 4385 return isolate->heap()->undefined_value(); 4386 } 4387 // Avoid redefining foreign callback as data property, just use the stored 4388 // setter to update the value instead. 4389 // TODO(mstarzinger): So far this only works if property attributes don't 4390 // change, this should be fixed once we cleanup the underlying code. 4391 if (callback->IsForeign() && result.GetAttributes() == attr) { 4392 return js_object->SetPropertyWithCallback(callback, 4393 *name, 4394 *obj_value, 4395 result.holder(), 4396 kStrictMode); 4397 } 4398 } 4399 4400 // Take special care when attributes are different and there is already 4401 // a property. For simplicity we normalize the property which enables us 4402 // to not worry about changing the instance_descriptor and creating a new 4403 // map. The current version of SetObjectProperty does not handle attributes 4404 // correctly in the case where a property is a field and is reset with 4405 // new attributes. 4406 if (result.IsProperty() && 4407 (attr != result.GetAttributes() || result.type() == CALLBACKS)) { 4408 // New attributes - normalize to avoid writing to instance descriptor 4409 if (js_object->IsJSGlobalProxy()) { 4410 // Since the result is a property, the prototype will exist so 4411 // we don't have to check for null. 4412 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); 4413 } 4414 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); 4415 // Use IgnoreAttributes version since a readonly property may be 4416 // overridden and SetProperty does not allow this. 4417 return js_object->SetLocalPropertyIgnoreAttributes(*name, 4418 *obj_value, 4419 attr); 4420 } 4421 4422 return Runtime::ForceSetObjectProperty(isolate, 4423 js_object, 4424 name, 4425 obj_value, 4426 attr); 4427 } 4428 4429 4430 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, 4431 Handle<Object> object, 4432 Handle<Object> key, 4433 Handle<Object> value, 4434 PropertyAttributes attr, 4435 StrictModeFlag strict_mode) { 4436 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; 4437 HandleScope scope(isolate); 4438 4439 if (object->IsUndefined() || object->IsNull()) { 4440 Handle<Object> args[2] = { key, object }; 4441 Handle<Object> error = 4442 isolate->factory()->NewTypeError("non_object_property_store", 4443 HandleVector(args, 2)); 4444 return isolate->Throw(*error); 4445 } 4446 4447 if (object->IsJSProxy()) { 4448 bool has_pending_exception = false; 4449 Handle<Object> name = Execution::ToString(key, &has_pending_exception); 4450 if (has_pending_exception) return Failure::Exception(); 4451 return JSProxy::cast(*object)->SetProperty( 4452 String::cast(*name), *value, attr, strict_mode); 4453 } 4454 4455 // If the object isn't a JavaScript object, we ignore the store. 4456 if (!object->IsJSObject()) return *value; 4457 4458 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 4459 4460 // Check if the given key is an array index. 4461 uint32_t index; 4462 if (key->ToArrayIndex(&index)) { 4463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 4464 // of a string using [] notation. We need to support this too in 4465 // JavaScript. 4466 // In the case of a String object we just need to redirect the assignment to 4467 // the underlying string if the index is in range. Since the underlying 4468 // string does nothing with the assignment then we can ignore such 4469 // assignments. 4470 if (js_object->IsStringObjectWithCharacterAt(index)) { 4471 return *value; 4472 } 4473 4474 Handle<Object> result = JSObject::SetElement( 4475 js_object, index, value, attr, strict_mode, set_mode); 4476 if (result.is_null()) return Failure::Exception(); 4477 return *value; 4478 } 4479 4480 if (key->IsString()) { 4481 Handle<Object> result; 4482 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 4483 result = JSObject::SetElement( 4484 js_object, index, value, attr, strict_mode, set_mode); 4485 } else { 4486 Handle<String> key_string = Handle<String>::cast(key); 4487 key_string->TryFlatten(); 4488 result = JSReceiver::SetProperty( 4489 js_object, key_string, value, attr, strict_mode); 4490 } 4491 if (result.is_null()) return Failure::Exception(); 4492 return *value; 4493 } 4494 4495 // Call-back into JavaScript to convert the key to a string. 4496 bool has_pending_exception = false; 4497 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 4498 if (has_pending_exception) return Failure::Exception(); 4499 Handle<String> name = Handle<String>::cast(converted); 4500 4501 if (name->AsArrayIndex(&index)) { 4502 return js_object->SetElement( 4503 index, *value, attr, strict_mode, true, set_mode); 4504 } else { 4505 return js_object->SetProperty(*name, *value, attr, strict_mode); 4506 } 4507 } 4508 4509 4510 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, 4511 Handle<JSObject> js_object, 4512 Handle<Object> key, 4513 Handle<Object> value, 4514 PropertyAttributes attr) { 4515 HandleScope scope(isolate); 4516 4517 // Check if the given key is an array index. 4518 uint32_t index; 4519 if (key->ToArrayIndex(&index)) { 4520 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 4521 // of a string using [] notation. We need to support this too in 4522 // JavaScript. 4523 // In the case of a String object we just need to redirect the assignment to 4524 // the underlying string if the index is in range. Since the underlying 4525 // string does nothing with the assignment then we can ignore such 4526 // assignments. 4527 if (js_object->IsStringObjectWithCharacterAt(index)) { 4528 return *value; 4529 } 4530 4531 return js_object->SetElement( 4532 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 4533 } 4534 4535 if (key->IsString()) { 4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 4537 return js_object->SetElement( 4538 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 4539 } else { 4540 Handle<String> key_string = Handle<String>::cast(key); 4541 key_string->TryFlatten(); 4542 return js_object->SetLocalPropertyIgnoreAttributes(*key_string, 4543 *value, 4544 attr); 4545 } 4546 } 4547 4548 // Call-back into JavaScript to convert the key to a string. 4549 bool has_pending_exception = false; 4550 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 4551 if (has_pending_exception) return Failure::Exception(); 4552 Handle<String> name = Handle<String>::cast(converted); 4553 4554 if (name->AsArrayIndex(&index)) { 4555 return js_object->SetElement( 4556 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 4557 } else { 4558 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); 4559 } 4560 } 4561 4562 4563 MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, 4564 Handle<JSReceiver> receiver, 4565 Handle<Object> key) { 4566 HandleScope scope(isolate); 4567 4568 // Check if the given key is an array index. 4569 uint32_t index; 4570 if (key->ToArrayIndex(&index)) { 4571 // In Firefox/SpiderMonkey, Safari and Opera you can access the 4572 // characters of a string using [] notation. In the case of a 4573 // String object we just need to redirect the deletion to the 4574 // underlying string if the index is in range. Since the 4575 // underlying string does nothing with the deletion, we can ignore 4576 // such deletions. 4577 if (receiver->IsStringObjectWithCharacterAt(index)) { 4578 return isolate->heap()->true_value(); 4579 } 4580 4581 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION); 4582 } 4583 4584 Handle<String> key_string; 4585 if (key->IsString()) { 4586 key_string = Handle<String>::cast(key); 4587 } else { 4588 // Call-back into JavaScript to convert the key to a string. 4589 bool has_pending_exception = false; 4590 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 4591 if (has_pending_exception) return Failure::Exception(); 4592 key_string = Handle<String>::cast(converted); 4593 } 4594 4595 key_string->TryFlatten(); 4596 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION); 4597 } 4598 4599 4600 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { 4601 NoHandleAllocation ha; 4602 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 4603 4604 Handle<Object> object = args.at<Object>(0); 4605 Handle<Object> key = args.at<Object>(1); 4606 Handle<Object> value = args.at<Object>(2); 4607 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); 4608 RUNTIME_ASSERT( 4609 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4610 // Compute attributes. 4611 PropertyAttributes attributes = 4612 static_cast<PropertyAttributes>(unchecked_attributes); 4613 4614 StrictModeFlag strict_mode = kNonStrictMode; 4615 if (args.length() == 5) { 4616 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4); 4617 strict_mode = strict_mode_flag; 4618 } 4619 4620 return Runtime::SetObjectProperty(isolate, 4621 object, 4622 key, 4623 value, 4624 attributes, 4625 strict_mode); 4626 } 4627 4628 4629 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) { 4630 NoHandleAllocation ha; 4631 RUNTIME_ASSERT(args.length() == 1); 4632 Handle<Object> object = args.at<Object>(0); 4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate); 4634 } 4635 4636 4637 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) { 4638 NoHandleAllocation ha; 4639 RUNTIME_ASSERT(args.length() == 1); 4640 Handle<Object> object = args.at<Object>(0); 4641 return TransitionElements(object, FAST_ELEMENTS, isolate); 4642 } 4643 4644 4645 // Set the native flag on the function. 4646 // This is used to decide if we should transform null and undefined 4647 // into the global object when doing call and apply. 4648 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { 4649 NoHandleAllocation ha; 4650 RUNTIME_ASSERT(args.length() == 1); 4651 4652 Handle<Object> object = args.at<Object>(0); 4653 4654 if (object->IsJSFunction()) { 4655 JSFunction* func = JSFunction::cast(*object); 4656 func->shared()->set_native(true); 4657 } 4658 return isolate->heap()->undefined_value(); 4659 } 4660 4661 4662 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { 4663 RUNTIME_ASSERT(args.length() == 5); 4664 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 4665 CONVERT_SMI_ARG_CHECKED(store_index, 1); 4666 Handle<Object> value = args.at<Object>(2); 4667 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); 4668 CONVERT_SMI_ARG_CHECKED(literal_index, 4); 4669 HandleScope scope; 4670 4671 Object* raw_boilerplate_object = literals->get(literal_index); 4672 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object)); 4673 #if DEBUG 4674 ElementsKind elements_kind = object->GetElementsKind(); 4675 #endif 4676 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS); 4677 // Smis should never trigger transitions. 4678 ASSERT(!value->IsSmi()); 4679 4680 if (value->IsNumber()) { 4681 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS); 4682 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS); 4683 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS); 4684 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS); 4685 FixedDoubleArray* double_array = 4686 FixedDoubleArray::cast(object->elements()); 4687 HeapNumber* number = HeapNumber::cast(*value); 4688 double_array->set(store_index, number->Number()); 4689 } else { 4690 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS || 4691 elements_kind == FAST_DOUBLE_ELEMENTS); 4692 JSObject::TransitionElementsKind(object, FAST_ELEMENTS); 4693 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS); 4694 FixedArray* object_array = 4695 FixedArray::cast(object->elements()); 4696 object_array->set(store_index, *value); 4697 } 4698 return *object; 4699 } 4700 4701 4702 // Set a local property, even if it is READ_ONLY. If the property does not 4703 // exist, it will be added with attributes NONE. 4704 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { 4705 NoHandleAllocation ha; 4706 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 4707 CONVERT_ARG_CHECKED(JSObject, object, 0); 4708 CONVERT_ARG_CHECKED(String, name, 1); 4709 // Compute attributes. 4710 PropertyAttributes attributes = NONE; 4711 if (args.length() == 4) { 4712 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3); 4713 // Only attribute bits should be set. 4714 RUNTIME_ASSERT( 4715 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4716 attributes = static_cast<PropertyAttributes>(unchecked_value); 4717 } 4718 4719 return object-> 4720 SetLocalPropertyIgnoreAttributes(name, args[2], attributes); 4721 } 4722 4723 4724 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { 4725 NoHandleAllocation ha; 4726 ASSERT(args.length() == 3); 4727 4728 CONVERT_ARG_CHECKED(JSReceiver, object, 0); 4729 CONVERT_ARG_CHECKED(String, key, 1); 4730 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); 4731 return object->DeleteProperty(key, (strict_mode == kStrictMode) 4732 ? JSReceiver::STRICT_DELETION 4733 : JSReceiver::NORMAL_DELETION); 4734 } 4735 4736 4737 static Object* HasLocalPropertyImplementation(Isolate* isolate, 4738 Handle<JSObject> object, 4739 Handle<String> key) { 4740 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value(); 4741 // Handle hidden prototypes. If there's a hidden prototype above this thing 4742 // then we have to check it for properties, because they are supposed to 4743 // look like they are on this object. 4744 Handle<Object> proto(object->GetPrototype()); 4745 if (proto->IsJSObject() && 4746 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 4747 return HasLocalPropertyImplementation(isolate, 4748 Handle<JSObject>::cast(proto), 4749 key); 4750 } 4751 return isolate->heap()->false_value(); 4752 } 4753 4754 4755 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { 4756 NoHandleAllocation ha; 4757 ASSERT(args.length() == 2); 4758 CONVERT_ARG_CHECKED(String, key, 1); 4759 4760 uint32_t index; 4761 const bool key_is_array_index = key->AsArrayIndex(&index); 4762 4763 Object* obj = args[0]; 4764 // Only JS objects can have properties. 4765 if (obj->IsJSObject()) { 4766 JSObject* object = JSObject::cast(obj); 4767 // Fast case: either the key is a real named property or it is not 4768 // an array index and there are no interceptors or hidden 4769 // prototypes. 4770 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value(); 4771 Map* map = object->map(); 4772 if (!key_is_array_index && 4773 !map->has_named_interceptor() && 4774 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) { 4775 return isolate->heap()->false_value(); 4776 } 4777 // Slow case. 4778 HandleScope scope(isolate); 4779 return HasLocalPropertyImplementation(isolate, 4780 Handle<JSObject>(object), 4781 Handle<String>(key)); 4782 } else if (obj->IsString() && key_is_array_index) { 4783 // Well, there is one exception: Handle [] on strings. 4784 String* string = String::cast(obj); 4785 if (index < static_cast<uint32_t>(string->length())) { 4786 return isolate->heap()->true_value(); 4787 } 4788 } 4789 return isolate->heap()->false_value(); 4790 } 4791 4792 4793 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { 4794 NoHandleAllocation na; 4795 ASSERT(args.length() == 2); 4796 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0); 4797 CONVERT_ARG_CHECKED(String, key, 1); 4798 4799 bool result = receiver->HasProperty(key); 4800 if (isolate->has_pending_exception()) return Failure::Exception(); 4801 return isolate->heap()->ToBoolean(result); 4802 } 4803 4804 4805 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) { 4806 NoHandleAllocation na; 4807 ASSERT(args.length() == 2); 4808 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0); 4809 CONVERT_SMI_ARG_CHECKED(index, 1); 4810 4811 bool result = receiver->HasElement(index); 4812 if (isolate->has_pending_exception()) return Failure::Exception(); 4813 return isolate->heap()->ToBoolean(result); 4814 } 4815 4816 4817 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { 4818 NoHandleAllocation ha; 4819 ASSERT(args.length() == 2); 4820 4821 CONVERT_ARG_CHECKED(JSObject, object, 0); 4822 CONVERT_ARG_CHECKED(String, key, 1); 4823 4824 uint32_t index; 4825 if (key->AsArrayIndex(&index)) { 4826 JSObject::LocalElementType type = object->HasLocalElement(index); 4827 switch (type) { 4828 case JSObject::UNDEFINED_ELEMENT: 4829 case JSObject::STRING_CHARACTER_ELEMENT: 4830 return isolate->heap()->false_value(); 4831 case JSObject::INTERCEPTED_ELEMENT: 4832 case JSObject::FAST_ELEMENT: 4833 return isolate->heap()->true_value(); 4834 case JSObject::DICTIONARY_ELEMENT: { 4835 if (object->IsJSGlobalProxy()) { 4836 Object* proto = object->GetPrototype(); 4837 if (proto->IsNull()) { 4838 return isolate->heap()->false_value(); 4839 } 4840 ASSERT(proto->IsJSGlobalObject()); 4841 object = JSObject::cast(proto); 4842 } 4843 FixedArray* elements = FixedArray::cast(object->elements()); 4844 SeededNumberDictionary* dictionary = NULL; 4845 if (elements->map() == 4846 isolate->heap()->non_strict_arguments_elements_map()) { 4847 dictionary = SeededNumberDictionary::cast(elements->get(1)); 4848 } else { 4849 dictionary = SeededNumberDictionary::cast(elements); 4850 } 4851 int entry = dictionary->FindEntry(index); 4852 ASSERT(entry != SeededNumberDictionary::kNotFound); 4853 PropertyDetails details = dictionary->DetailsAt(entry); 4854 return isolate->heap()->ToBoolean(!details.IsDontEnum()); 4855 } 4856 } 4857 } 4858 4859 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 4860 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0); 4861 } 4862 4863 4864 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { 4865 HandleScope scope(isolate); 4866 ASSERT(args.length() == 1); 4867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 4868 bool threw = false; 4869 Handle<JSArray> result = GetKeysFor(object, &threw); 4870 if (threw) return Failure::Exception(); 4871 return *result; 4872 } 4873 4874 4875 // Returns either a FixedArray as Runtime_GetPropertyNames, 4876 // or, if the given object has an enum cache that contains 4877 // all enumerable properties of the object and its prototypes 4878 // have none, the map of the object. This is used to speed up 4879 // the check for deletions during a for-in. 4880 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { 4881 ASSERT(args.length() == 1); 4882 4883 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0); 4884 4885 if (raw_object->IsSimpleEnum()) return raw_object->map(); 4886 4887 HandleScope scope(isolate); 4888 Handle<JSReceiver> object(raw_object); 4889 bool threw = false; 4890 Handle<FixedArray> content = 4891 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw); 4892 if (threw) return Failure::Exception(); 4893 4894 // Test again, since cache may have been built by preceding call. 4895 if (object->IsSimpleEnum()) return object->map(); 4896 4897 return *content; 4898 } 4899 4900 4901 // Find the length of the prototype chain that is to to handled as one. If a 4902 // prototype object is hidden it is to be viewed as part of the the object it 4903 // is prototype for. 4904 static int LocalPrototypeChainLength(JSObject* obj) { 4905 int count = 1; 4906 Object* proto = obj->GetPrototype(); 4907 while (proto->IsJSObject() && 4908 JSObject::cast(proto)->map()->is_hidden_prototype()) { 4909 count++; 4910 proto = JSObject::cast(proto)->GetPrototype(); 4911 } 4912 return count; 4913 } 4914 4915 4916 // Return the names of the local named properties. 4917 // args[0]: object 4918 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { 4919 HandleScope scope(isolate); 4920 ASSERT(args.length() == 1); 4921 if (!args[0]->IsJSObject()) { 4922 return isolate->heap()->undefined_value(); 4923 } 4924 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 4925 4926 // Skip the global proxy as it has no properties and always delegates to the 4927 // real global object. 4928 if (obj->IsJSGlobalProxy()) { 4929 // Only collect names if access is permitted. 4930 if (obj->IsAccessCheckNeeded() && 4931 !isolate->MayNamedAccess(*obj, 4932 isolate->heap()->undefined_value(), 4933 v8::ACCESS_KEYS)) { 4934 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); 4935 return *isolate->factory()->NewJSArray(0); 4936 } 4937 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 4938 } 4939 4940 // Find the number of objects making up this. 4941 int length = LocalPrototypeChainLength(*obj); 4942 4943 // Find the number of local properties for each of the objects. 4944 ScopedVector<int> local_property_count(length); 4945 int total_property_count = 0; 4946 Handle<JSObject> jsproto = obj; 4947 for (int i = 0; i < length; i++) { 4948 // Only collect names if access is permitted. 4949 if (jsproto->IsAccessCheckNeeded() && 4950 !isolate->MayNamedAccess(*jsproto, 4951 isolate->heap()->undefined_value(), 4952 v8::ACCESS_KEYS)) { 4953 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); 4954 return *isolate->factory()->NewJSArray(0); 4955 } 4956 int n; 4957 n = jsproto->NumberOfLocalProperties(); 4958 local_property_count[i] = n; 4959 total_property_count += n; 4960 if (i < length - 1) { 4961 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 4962 } 4963 } 4964 4965 // Allocate an array with storage for all the property names. 4966 Handle<FixedArray> names = 4967 isolate->factory()->NewFixedArray(total_property_count); 4968 4969 // Get the property names. 4970 jsproto = obj; 4971 int proto_with_hidden_properties = 0; 4972 int next_copy_index = 0; 4973 for (int i = 0; i < length; i++) { 4974 jsproto->GetLocalPropertyNames(*names, next_copy_index); 4975 next_copy_index += local_property_count[i]; 4976 if (jsproto->HasHiddenProperties()) { 4977 proto_with_hidden_properties++; 4978 } 4979 if (i < length - 1) { 4980 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 4981 } 4982 } 4983 4984 // Filter out name of hidden propeties object. 4985 if (proto_with_hidden_properties > 0) { 4986 Handle<FixedArray> old_names = names; 4987 names = isolate->factory()->NewFixedArray( 4988 names->length() - proto_with_hidden_properties); 4989 int dest_pos = 0; 4990 for (int i = 0; i < total_property_count; i++) { 4991 Object* name = old_names->get(i); 4992 if (name == isolate->heap()->hidden_symbol()) { 4993 continue; 4994 } 4995 names->set(dest_pos++, name); 4996 } 4997 } 4998 4999 return *isolate->factory()->NewJSArrayWithElements(names); 5000 } 5001 5002 5003 // Return the names of the local indexed properties. 5004 // args[0]: object 5005 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { 5006 HandleScope scope(isolate); 5007 ASSERT(args.length() == 1); 5008 if (!args[0]->IsJSObject()) { 5009 return isolate->heap()->undefined_value(); 5010 } 5011 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5012 5013 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); 5014 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); 5015 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 5016 return *isolate->factory()->NewJSArrayWithElements(names); 5017 } 5018 5019 5020 // Return information on whether an object has a named or indexed interceptor. 5021 // args[0]: object 5022 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { 5023 HandleScope scope(isolate); 5024 ASSERT(args.length() == 1); 5025 if (!args[0]->IsJSObject()) { 5026 return Smi::FromInt(0); 5027 } 5028 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5029 5030 int result = 0; 5031 if (obj->HasNamedInterceptor()) result |= 2; 5032 if (obj->HasIndexedInterceptor()) result |= 1; 5033 5034 return Smi::FromInt(result); 5035 } 5036 5037 5038 // Return property names from named interceptor. 5039 // args[0]: object 5040 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { 5041 HandleScope scope(isolate); 5042 ASSERT(args.length() == 1); 5043 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5044 5045 if (obj->HasNamedInterceptor()) { 5046 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); 5047 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5048 } 5049 return isolate->heap()->undefined_value(); 5050 } 5051 5052 5053 // Return element names from indexed interceptor. 5054 // args[0]: object 5055 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) { 5056 HandleScope scope(isolate); 5057 ASSERT(args.length() == 1); 5058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5059 5060 if (obj->HasIndexedInterceptor()) { 5061 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); 5062 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5063 } 5064 return isolate->heap()->undefined_value(); 5065 } 5066 5067 5068 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { 5069 ASSERT_EQ(args.length(), 1); 5070 CONVERT_ARG_CHECKED(JSObject, raw_object, 0); 5071 HandleScope scope(isolate); 5072 Handle<JSObject> object(raw_object); 5073 5074 if (object->IsJSGlobalProxy()) { 5075 // Do access checks before going to the global object. 5076 if (object->IsAccessCheckNeeded() && 5077 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), 5078 v8::ACCESS_KEYS)) { 5079 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); 5080 return *isolate->factory()->NewJSArray(0); 5081 } 5082 5083 Handle<Object> proto(object->GetPrototype()); 5084 // If proxy is detached we simply return an empty array. 5085 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); 5086 object = Handle<JSObject>::cast(proto); 5087 } 5088 5089 bool threw = false; 5090 Handle<FixedArray> contents = 5091 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); 5092 if (threw) return Failure::Exception(); 5093 5094 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 5095 // property array and since the result is mutable we have to create 5096 // a fresh clone on each invocation. 5097 int length = contents->length(); 5098 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); 5099 for (int i = 0; i < length; i++) { 5100 Object* entry = contents->get(i); 5101 if (entry->IsString()) { 5102 copy->set(i, entry); 5103 } else { 5104 ASSERT(entry->IsNumber()); 5105 HandleScope scope(isolate); 5106 Handle<Object> entry_handle(entry, isolate); 5107 Handle<Object> entry_str = 5108 isolate->factory()->NumberToString(entry_handle); 5109 copy->set(i, *entry_str); 5110 } 5111 } 5112 return *isolate->factory()->NewJSArrayWithElements(copy); 5113 } 5114 5115 5116 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { 5117 NoHandleAllocation ha; 5118 ASSERT(args.length() == 1); 5119 5120 // Compute the frame holding the arguments. 5121 JavaScriptFrameIterator it(isolate); 5122 it.AdvanceToArgumentsFrame(); 5123 JavaScriptFrame* frame = it.frame(); 5124 5125 // Get the actual number of provided arguments. 5126 const uint32_t n = frame->ComputeParametersCount(); 5127 5128 // Try to convert the key to an index. If successful and within 5129 // index return the the argument from the frame. 5130 uint32_t index; 5131 if (args[0]->ToArrayIndex(&index) && index < n) { 5132 return frame->GetParameter(index); 5133 } 5134 5135 // Convert the key to a string. 5136 HandleScope scope(isolate); 5137 bool exception = false; 5138 Handle<Object> converted = 5139 Execution::ToString(args.at<Object>(0), &exception); 5140 if (exception) return Failure::Exception(); 5141 Handle<String> key = Handle<String>::cast(converted); 5142 5143 // Try to convert the string key into an array index. 5144 if (key->AsArrayIndex(&index)) { 5145 if (index < n) { 5146 return frame->GetParameter(index); 5147 } else { 5148 return isolate->initial_object_prototype()->GetElement(index); 5149 } 5150 } 5151 5152 // Handle special arguments properties. 5153 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n); 5154 if (key->Equals(isolate->heap()->callee_symbol())) { 5155 Object* function = frame->function(); 5156 if (function->IsJSFunction() && 5157 !JSFunction::cast(function)->shared()->is_classic_mode()) { 5158 return isolate->Throw(*isolate->factory()->NewTypeError( 5159 "strict_arguments_callee", HandleVector<Object>(NULL, 0))); 5160 } 5161 return function; 5162 } 5163 5164 // Lookup in the initial Object.prototype object. 5165 return isolate->initial_object_prototype()->GetProperty(*key); 5166 } 5167 5168 5169 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { 5170 ASSERT(args.length() == 1); 5171 Object* object = args[0]; 5172 return (object->IsJSObject() && !object->IsGlobalObject()) 5173 ? JSObject::cast(object)->TransformToFastProperties(0) 5174 : object; 5175 } 5176 5177 5178 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) { 5179 ASSERT(args.length() == 1); 5180 Object* obj = args[0]; 5181 return (obj->IsJSObject() && !obj->IsJSGlobalProxy()) 5182 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0) 5183 : obj; 5184 } 5185 5186 5187 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { 5188 NoHandleAllocation ha; 5189 ASSERT(args.length() == 1); 5190 5191 return args[0]->ToBoolean(); 5192 } 5193 5194 5195 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 5196 // Possible optimizations: put the type string into the oddballs. 5197 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { 5198 NoHandleAllocation ha; 5199 5200 Object* obj = args[0]; 5201 if (obj->IsNumber()) return isolate->heap()->number_symbol(); 5202 HeapObject* heap_obj = HeapObject::cast(obj); 5203 5204 // typeof an undetectable object is 'undefined' 5205 if (heap_obj->map()->is_undetectable()) { 5206 return isolate->heap()->undefined_symbol(); 5207 } 5208 5209 InstanceType instance_type = heap_obj->map()->instance_type(); 5210 if (instance_type < FIRST_NONSTRING_TYPE) { 5211 return isolate->heap()->string_symbol(); 5212 } 5213 5214 switch (instance_type) { 5215 case ODDBALL_TYPE: 5216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 5217 return isolate->heap()->boolean_symbol(); 5218 } 5219 if (heap_obj->IsNull()) { 5220 return FLAG_harmony_typeof 5221 ? isolate->heap()->null_symbol() 5222 : isolate->heap()->object_symbol(); 5223 } 5224 ASSERT(heap_obj->IsUndefined()); 5225 return isolate->heap()->undefined_symbol(); 5226 case JS_FUNCTION_TYPE: 5227 case JS_FUNCTION_PROXY_TYPE: 5228 return isolate->heap()->function_symbol(); 5229 default: 5230 // For any kind of object not handled above, the spec rule for 5231 // host objects gives that it is okay to return "object" 5232 return isolate->heap()->object_symbol(); 5233 } 5234 } 5235 5236 5237 static bool AreDigits(const char*s, int from, int to) { 5238 for (int i = from; i < to; i++) { 5239 if (s[i] < '0' || s[i] > '9') return false; 5240 } 5241 5242 return true; 5243 } 5244 5245 5246 static int ParseDecimalInteger(const char*s, int from, int to) { 5247 ASSERT(to - from < 10); // Overflow is not possible. 5248 ASSERT(from < to); 5249 int d = s[from] - '0'; 5250 5251 for (int i = from + 1; i < to; i++) { 5252 d = 10 * d + (s[i] - '0'); 5253 } 5254 5255 return d; 5256 } 5257 5258 5259 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { 5260 NoHandleAllocation ha; 5261 ASSERT(args.length() == 1); 5262 CONVERT_ARG_CHECKED(String, subject, 0); 5263 subject->TryFlatten(); 5264 5265 // Fast case: short integer or some sorts of junk values. 5266 int len = subject->length(); 5267 if (subject->IsSeqAsciiString()) { 5268 if (len == 0) return Smi::FromInt(0); 5269 5270 char const* data = SeqAsciiString::cast(subject)->GetChars(); 5271 bool minus = (data[0] == '-'); 5272 int start_pos = (minus ? 1 : 0); 5273 5274 if (start_pos == len) { 5275 return isolate->heap()->nan_value(); 5276 } else if (data[start_pos] > '9') { 5277 // Fast check for a junk value. A valid string may start from a 5278 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or 5279 // the 'I' character ('Infinity'). All of that have codes not greater than 5280 // '9' except 'I'. 5281 if (data[start_pos] != 'I') { 5282 return isolate->heap()->nan_value(); 5283 } 5284 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 5285 // The maximal/minimal smi has 10 digits. If the string has less digits we 5286 // know it will fit into the smi-data type. 5287 int d = ParseDecimalInteger(data, start_pos, len); 5288 if (minus) { 5289 if (d == 0) return isolate->heap()->minus_zero_value(); 5290 d = -d; 5291 } else if (!subject->HasHashCode() && 5292 len <= String::kMaxArrayIndexSize && 5293 (len == 1 || data[0] != '0')) { 5294 // String hash is not calculated yet but all the data are present. 5295 // Update the hash field to speed up sequential convertions. 5296 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 5297 #ifdef DEBUG 5298 subject->Hash(); // Force hash calculation. 5299 ASSERT_EQ(static_cast<int>(subject->hash_field()), 5300 static_cast<int>(hash)); 5301 #endif 5302 subject->set_hash_field(hash); 5303 } 5304 return Smi::FromInt(d); 5305 } 5306 } 5307 5308 // Slower case. 5309 return isolate->heap()->NumberFromDouble( 5310 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX)); 5311 } 5312 5313 5314 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) { 5315 NoHandleAllocation ha; 5316 ASSERT(args.length() == 1); 5317 5318 CONVERT_ARG_CHECKED(JSArray, codes, 0); 5319 int length = Smi::cast(codes->length())->value(); 5320 5321 // Check if the string can be ASCII. 5322 int i; 5323 for (i = 0; i < length; i++) { 5324 Object* element; 5325 { MaybeObject* maybe_element = codes->GetElement(i); 5326 // We probably can't get an exception here, but just in order to enforce 5327 // the checking of inputs in the runtime calls we check here. 5328 if (!maybe_element->ToObject(&element)) return maybe_element; 5329 } 5330 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 5331 if ((chr & 0xffff) > String::kMaxAsciiCharCode) 5332 break; 5333 } 5334 5335 MaybeObject* maybe_object = NULL; 5336 if (i == length) { // The string is ASCII. 5337 maybe_object = isolate->heap()->AllocateRawAsciiString(length); 5338 } else { // The string is not ASCII. 5339 maybe_object = isolate->heap()->AllocateRawTwoByteString(length); 5340 } 5341 5342 Object* object = NULL; 5343 if (!maybe_object->ToObject(&object)) return maybe_object; 5344 String* result = String::cast(object); 5345 for (int i = 0; i < length; i++) { 5346 Object* element; 5347 { MaybeObject* maybe_element = codes->GetElement(i); 5348 if (!maybe_element->ToObject(&element)) return maybe_element; 5349 } 5350 CONVERT_NUMBER_CHECKED(int, chr, Int32, element); 5351 result->Set(i, chr & 0xffff); 5352 } 5353 return result; 5354 } 5355 5356 5357 // kNotEscaped is generated by the following: 5358 // 5359 // #!/bin/perl 5360 // for (my $i = 0; $i < 256; $i++) { 5361 // print "\n" if $i % 16 == 0; 5362 // my $c = chr($i); 5363 // my $escaped = 1; 5364 // $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#; 5365 // print $escaped ? "0, " : "1, "; 5366 // } 5367 5368 5369 static bool IsNotEscaped(uint16_t character) { 5370 // Only for 8 bit characters, the rest are always escaped (in a different way) 5371 ASSERT(character < 256); 5372 static const char kNotEscaped[256] = { 5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 5376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 5379 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5389 }; 5390 return kNotEscaped[character] != 0; 5391 } 5392 5393 5394 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { 5395 const char hex_chars[] = "0123456789ABCDEF"; 5396 NoHandleAllocation ha; 5397 ASSERT(args.length() == 1); 5398 CONVERT_ARG_CHECKED(String, source, 0); 5399 5400 source->TryFlatten(); 5401 5402 int escaped_length = 0; 5403 int length = source->length(); 5404 { 5405 Access<StringInputBuffer> buffer( 5406 isolate->runtime_state()->string_input_buffer()); 5407 buffer->Reset(source); 5408 while (buffer->has_more()) { 5409 uint16_t character = buffer->GetNext(); 5410 if (character >= 256) { 5411 escaped_length += 6; 5412 } else if (IsNotEscaped(character)) { 5413 escaped_length++; 5414 } else { 5415 escaped_length += 3; 5416 } 5417 // We don't allow strings that are longer than a maximal length. 5418 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow. 5419 if (escaped_length > String::kMaxLength) { 5420 isolate->context()->mark_out_of_memory(); 5421 return Failure::OutOfMemoryException(); 5422 } 5423 } 5424 } 5425 // No length change implies no change. Return original string if no change. 5426 if (escaped_length == length) { 5427 return source; 5428 } 5429 Object* o; 5430 { MaybeObject* maybe_o = 5431 isolate->heap()->AllocateRawAsciiString(escaped_length); 5432 if (!maybe_o->ToObject(&o)) return maybe_o; 5433 } 5434 String* destination = String::cast(o); 5435 int dest_position = 0; 5436 5437 Access<StringInputBuffer> buffer( 5438 isolate->runtime_state()->string_input_buffer()); 5439 buffer->Rewind(); 5440 while (buffer->has_more()) { 5441 uint16_t chr = buffer->GetNext(); 5442 if (chr >= 256) { 5443 destination->Set(dest_position, '%'); 5444 destination->Set(dest_position+1, 'u'); 5445 destination->Set(dest_position+2, hex_chars[chr >> 12]); 5446 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]); 5447 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]); 5448 destination->Set(dest_position+5, hex_chars[chr & 0xf]); 5449 dest_position += 6; 5450 } else if (IsNotEscaped(chr)) { 5451 destination->Set(dest_position, chr); 5452 dest_position++; 5453 } else { 5454 destination->Set(dest_position, '%'); 5455 destination->Set(dest_position+1, hex_chars[chr >> 4]); 5456 destination->Set(dest_position+2, hex_chars[chr & 0xf]); 5457 dest_position += 3; 5458 } 5459 } 5460 return destination; 5461 } 5462 5463 5464 static inline int TwoDigitHex(uint16_t character1, uint16_t character2) { 5465 static const signed char kHexValue['g'] = { 5466 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5467 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 5470 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5472 -1, 10, 11, 12, 13, 14, 15 }; 5473 5474 if (character1 > 'f') return -1; 5475 int hi = kHexValue[character1]; 5476 if (hi == -1) return -1; 5477 if (character2 > 'f') return -1; 5478 int lo = kHexValue[character2]; 5479 if (lo == -1) return -1; 5480 return (hi << 4) + lo; 5481 } 5482 5483 5484 static inline int Unescape(String* source, 5485 int i, 5486 int length, 5487 int* step) { 5488 uint16_t character = source->Get(i); 5489 int32_t hi = 0; 5490 int32_t lo = 0; 5491 if (character == '%' && 5492 i <= length - 6 && 5493 source->Get(i + 1) == 'u' && 5494 (hi = TwoDigitHex(source->Get(i + 2), 5495 source->Get(i + 3))) != -1 && 5496 (lo = TwoDigitHex(source->Get(i + 4), 5497 source->Get(i + 5))) != -1) { 5498 *step = 6; 5499 return (hi << 8) + lo; 5500 } else if (character == '%' && 5501 i <= length - 3 && 5502 (lo = TwoDigitHex(source->Get(i + 1), 5503 source->Get(i + 2))) != -1) { 5504 *step = 3; 5505 return lo; 5506 } else { 5507 *step = 1; 5508 return character; 5509 } 5510 } 5511 5512 5513 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { 5514 NoHandleAllocation ha; 5515 ASSERT(args.length() == 1); 5516 CONVERT_ARG_CHECKED(String, source, 0); 5517 5518 source->TryFlatten(); 5519 5520 bool ascii = true; 5521 int length = source->length(); 5522 5523 int unescaped_length = 0; 5524 for (int i = 0; i < length; unescaped_length++) { 5525 int step; 5526 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) { 5527 ascii = false; 5528 } 5529 i += step; 5530 } 5531 5532 // No length change implies no change. Return original string if no change. 5533 if (unescaped_length == length) 5534 return source; 5535 5536 Object* o; 5537 { MaybeObject* maybe_o = 5538 ascii ? 5539 isolate->heap()->AllocateRawAsciiString(unescaped_length) : 5540 isolate->heap()->AllocateRawTwoByteString(unescaped_length); 5541 if (!maybe_o->ToObject(&o)) return maybe_o; 5542 } 5543 String* destination = String::cast(o); 5544 5545 int dest_position = 0; 5546 for (int i = 0; i < length; dest_position++) { 5547 int step; 5548 destination->Set(dest_position, Unescape(source, i, length, &step)); 5549 i += step; 5550 } 5551 return destination; 5552 } 5553 5554 5555 static const unsigned int kQuoteTableLength = 128u; 5556 5557 static const int kJsonQuotesCharactersPerEntry = 8; 5558 static const char* const JsonQuotes = 5559 "\\u0000 \\u0001 \\u0002 \\u0003 " 5560 "\\u0004 \\u0005 \\u0006 \\u0007 " 5561 "\\b \\t \\n \\u000b " 5562 "\\f \\r \\u000e \\u000f " 5563 "\\u0010 \\u0011 \\u0012 \\u0013 " 5564 "\\u0014 \\u0015 \\u0016 \\u0017 " 5565 "\\u0018 \\u0019 \\u001a \\u001b " 5566 "\\u001c \\u001d \\u001e \\u001f " 5567 " ! \\\" # " 5568 "$ % & ' " 5569 "( ) * + " 5570 ", - . / " 5571 "0 1 2 3 " 5572 "4 5 6 7 " 5573 "8 9 : ; " 5574 "< = > ? " 5575 "@ A B C " 5576 "D E F G " 5577 "H I J K " 5578 "L M N O " 5579 "P Q R S " 5580 "T U V W " 5581 "X Y Z [ " 5582 "\\\\ ] ^ _ " 5583 "` a b c " 5584 "d e f g " 5585 "h i j k " 5586 "l m n o " 5587 "p q r s " 5588 "t u v w " 5589 "x y z { " 5590 "| } ~ \177 "; 5591 5592 5593 // For a string that is less than 32k characters it should always be 5594 // possible to allocate it in new space. 5595 static const int kMaxGuaranteedNewSpaceString = 32 * 1024; 5596 5597 5598 // Doing JSON quoting cannot make the string more than this many times larger. 5599 static const int kJsonQuoteWorstCaseBlowup = 6; 5600 5601 static const int kSpaceForQuotesAndComma = 3; 5602 static const int kSpaceForBrackets = 2; 5603 5604 // Covers the entire ASCII range (all other characters are unchanged by JSON 5605 // quoting). 5606 static const byte JsonQuoteLengths[kQuoteTableLength] = { 5607 6, 6, 6, 6, 6, 6, 6, 6, 5608 2, 2, 2, 6, 2, 2, 6, 6, 5609 6, 6, 6, 6, 6, 6, 6, 6, 5610 6, 6, 6, 6, 6, 6, 6, 6, 5611 1, 1, 2, 1, 1, 1, 1, 1, 5612 1, 1, 1, 1, 1, 1, 1, 1, 5613 1, 1, 1, 1, 1, 1, 1, 1, 5614 1, 1, 1, 1, 1, 1, 1, 1, 5615 1, 1, 1, 1, 1, 1, 1, 1, 5616 1, 1, 1, 1, 1, 1, 1, 1, 5617 1, 1, 1, 1, 1, 1, 1, 1, 5618 1, 1, 1, 1, 2, 1, 1, 1, 5619 1, 1, 1, 1, 1, 1, 1, 1, 5620 1, 1, 1, 1, 1, 1, 1, 1, 5621 1, 1, 1, 1, 1, 1, 1, 1, 5622 1, 1, 1, 1, 1, 1, 1, 1, 5623 }; 5624 5625 5626 template <typename StringType> 5627 MaybeObject* AllocateRawString(Isolate* isolate, int length); 5628 5629 5630 template <> 5631 MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) { 5632 return isolate->heap()->AllocateRawTwoByteString(length); 5633 } 5634 5635 5636 template <> 5637 MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) { 5638 return isolate->heap()->AllocateRawAsciiString(length); 5639 } 5640 5641 5642 template <typename Char, typename StringType, bool comma> 5643 static MaybeObject* SlowQuoteJsonString(Isolate* isolate, 5644 Vector<const Char> characters) { 5645 int length = characters.length(); 5646 const Char* read_cursor = characters.start(); 5647 const Char* end = read_cursor + length; 5648 const int kSpaceForQuotes = 2 + (comma ? 1 :0); 5649 int quoted_length = kSpaceForQuotes; 5650 while (read_cursor < end) { 5651 Char c = *(read_cursor++); 5652 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { 5653 quoted_length++; 5654 } else { 5655 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)]; 5656 } 5657 } 5658 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, 5659 quoted_length); 5660 Object* new_object; 5661 if (!new_alloc->ToObject(&new_object)) { 5662 return new_alloc; 5663 } 5664 StringType* new_string = StringType::cast(new_object); 5665 5666 Char* write_cursor = reinterpret_cast<Char*>( 5667 new_string->address() + SeqString::kHeaderSize); 5668 if (comma) *(write_cursor++) = ','; 5669 *(write_cursor++) = '"'; 5670 5671 read_cursor = characters.start(); 5672 while (read_cursor < end) { 5673 Char c = *(read_cursor++); 5674 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) { 5675 *(write_cursor++) = c; 5676 } else { 5677 int len = JsonQuoteLengths[static_cast<unsigned>(c)]; 5678 const char* replacement = JsonQuotes + 5679 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; 5680 for (int i = 0; i < len; i++) { 5681 *write_cursor++ = *replacement++; 5682 } 5683 } 5684 } 5685 *(write_cursor++) = '"'; 5686 return new_string; 5687 } 5688 5689 5690 template <typename SinkChar, typename SourceChar> 5691 static inline SinkChar* WriteQuoteJsonString( 5692 Isolate* isolate, 5693 SinkChar* write_cursor, 5694 Vector<const SourceChar> characters) { 5695 // SinkChar is only char if SourceChar is guaranteed to be char. 5696 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar)); 5697 const SourceChar* read_cursor = characters.start(); 5698 const SourceChar* end = read_cursor + characters.length(); 5699 *(write_cursor++) = '"'; 5700 while (read_cursor < end) { 5701 SourceChar c = *(read_cursor++); 5702 if (sizeof(SourceChar) > 1u && 5703 static_cast<unsigned>(c) >= kQuoteTableLength) { 5704 *(write_cursor++) = static_cast<SinkChar>(c); 5705 } else { 5706 int len = JsonQuoteLengths[static_cast<unsigned>(c)]; 5707 const char* replacement = JsonQuotes + 5708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry; 5709 write_cursor[0] = replacement[0]; 5710 if (len > 1) { 5711 write_cursor[1] = replacement[1]; 5712 if (len > 2) { 5713 ASSERT(len == 6); 5714 write_cursor[2] = replacement[2]; 5715 write_cursor[3] = replacement[3]; 5716 write_cursor[4] = replacement[4]; 5717 write_cursor[5] = replacement[5]; 5718 } 5719 } 5720 write_cursor += len; 5721 } 5722 } 5723 *(write_cursor++) = '"'; 5724 return write_cursor; 5725 } 5726 5727 5728 template <typename Char, typename StringType, bool comma> 5729 static MaybeObject* QuoteJsonString(Isolate* isolate, 5730 Vector<const Char> characters) { 5731 int length = characters.length(); 5732 isolate->counters()->quote_json_char_count()->Increment(length); 5733 int worst_case_length = 5734 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma; 5735 if (worst_case_length > kMaxGuaranteedNewSpaceString) { 5736 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5737 } 5738 5739 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, 5740 worst_case_length); 5741 Object* new_object; 5742 if (!new_alloc->ToObject(&new_object)) { 5743 return new_alloc; 5744 } 5745 if (!isolate->heap()->new_space()->Contains(new_object)) { 5746 // Even if our string is small enough to fit in new space we still have to 5747 // handle it being allocated in old space as may happen in the third 5748 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in 5749 // CEntryStub::GenerateCore. 5750 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters); 5751 } 5752 StringType* new_string = StringType::cast(new_object); 5753 ASSERT(isolate->heap()->new_space()->Contains(new_string)); 5754 5755 Char* write_cursor = reinterpret_cast<Char*>( 5756 new_string->address() + SeqString::kHeaderSize); 5757 if (comma) *(write_cursor++) = ','; 5758 write_cursor = WriteQuoteJsonString<Char, Char>(isolate, 5759 write_cursor, 5760 characters); 5761 int final_length = static_cast<int>( 5762 write_cursor - reinterpret_cast<Char*>( 5763 new_string->address() + SeqString::kHeaderSize)); 5764 isolate->heap()->new_space()-> 5765 template ShrinkStringAtAllocationBoundary<StringType>( 5766 new_string, final_length); 5767 return new_string; 5768 } 5769 5770 5771 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { 5772 NoHandleAllocation ha; 5773 CONVERT_ARG_CHECKED(String, str, 0); 5774 if (!str->IsFlat()) { 5775 MaybeObject* try_flatten = str->TryFlatten(); 5776 Object* flat; 5777 if (!try_flatten->ToObject(&flat)) { 5778 return try_flatten; 5779 } 5780 str = String::cast(flat); 5781 ASSERT(str->IsFlat()); 5782 } 5783 String::FlatContent flat = str->GetFlatContent(); 5784 ASSERT(flat.IsFlat()); 5785 if (flat.IsTwoByte()) { 5786 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate, 5787 flat.ToUC16Vector()); 5788 } else { 5789 return QuoteJsonString<char, SeqAsciiString, false>(isolate, 5790 flat.ToAsciiVector()); 5791 } 5792 } 5793 5794 5795 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) { 5796 NoHandleAllocation ha; 5797 CONVERT_ARG_CHECKED(String, str, 0); 5798 if (!str->IsFlat()) { 5799 MaybeObject* try_flatten = str->TryFlatten(); 5800 Object* flat; 5801 if (!try_flatten->ToObject(&flat)) { 5802 return try_flatten; 5803 } 5804 str = String::cast(flat); 5805 ASSERT(str->IsFlat()); 5806 } 5807 String::FlatContent flat = str->GetFlatContent(); 5808 if (flat.IsTwoByte()) { 5809 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate, 5810 flat.ToUC16Vector()); 5811 } else { 5812 return QuoteJsonString<char, SeqAsciiString, true>(isolate, 5813 flat.ToAsciiVector()); 5814 } 5815 } 5816 5817 5818 template <typename Char, typename StringType> 5819 static MaybeObject* QuoteJsonStringArray(Isolate* isolate, 5820 FixedArray* array, 5821 int worst_case_length) { 5822 int length = array->length(); 5823 5824 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate, 5825 worst_case_length); 5826 Object* new_object; 5827 if (!new_alloc->ToObject(&new_object)) { 5828 return new_alloc; 5829 } 5830 if (!isolate->heap()->new_space()->Contains(new_object)) { 5831 // Even if our string is small enough to fit in new space we still have to 5832 // handle it being allocated in old space as may happen in the third 5833 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in 5834 // CEntryStub::GenerateCore. 5835 return isolate->heap()->undefined_value(); 5836 } 5837 AssertNoAllocation no_gc; 5838 StringType* new_string = StringType::cast(new_object); 5839 ASSERT(isolate->heap()->new_space()->Contains(new_string)); 5840 5841 Char* write_cursor = reinterpret_cast<Char*>( 5842 new_string->address() + SeqString::kHeaderSize); 5843 *(write_cursor++) = '['; 5844 for (int i = 0; i < length; i++) { 5845 if (i != 0) *(write_cursor++) = ','; 5846 String* str = String::cast(array->get(i)); 5847 String::FlatContent content = str->GetFlatContent(); 5848 ASSERT(content.IsFlat()); 5849 if (content.IsTwoByte()) { 5850 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate, 5851 write_cursor, 5852 content.ToUC16Vector()); 5853 } else { 5854 write_cursor = WriteQuoteJsonString<Char, char>(isolate, 5855 write_cursor, 5856 content.ToAsciiVector()); 5857 } 5858 } 5859 *(write_cursor++) = ']'; 5860 5861 int final_length = static_cast<int>( 5862 write_cursor - reinterpret_cast<Char*>( 5863 new_string->address() + SeqString::kHeaderSize)); 5864 isolate->heap()->new_space()-> 5865 template ShrinkStringAtAllocationBoundary<StringType>( 5866 new_string, final_length); 5867 return new_string; 5868 } 5869 5870 5871 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) { 5872 NoHandleAllocation ha; 5873 ASSERT(args.length() == 1); 5874 CONVERT_ARG_CHECKED(JSArray, array, 0); 5875 5876 if (!array->HasFastElements()) return isolate->heap()->undefined_value(); 5877 FixedArray* elements = FixedArray::cast(array->elements()); 5878 int n = elements->length(); 5879 bool ascii = true; 5880 int total_length = 0; 5881 5882 for (int i = 0; i < n; i++) { 5883 Object* elt = elements->get(i); 5884 if (!elt->IsString()) return isolate->heap()->undefined_value(); 5885 String* element = String::cast(elt); 5886 if (!element->IsFlat()) return isolate->heap()->undefined_value(); 5887 total_length += element->length(); 5888 if (ascii && element->IsTwoByteRepresentation()) { 5889 ascii = false; 5890 } 5891 } 5892 5893 int worst_case_length = 5894 kSpaceForBrackets + n * kSpaceForQuotesAndComma 5895 + total_length * kJsonQuoteWorstCaseBlowup; 5896 5897 if (worst_case_length > kMaxGuaranteedNewSpaceString) { 5898 return isolate->heap()->undefined_value(); 5899 } 5900 5901 if (ascii) { 5902 return QuoteJsonStringArray<char, SeqAsciiString>(isolate, 5903 elements, 5904 worst_case_length); 5905 } else { 5906 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate, 5907 elements, 5908 worst_case_length); 5909 } 5910 } 5911 5912 5913 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 5914 NoHandleAllocation ha; 5915 5916 CONVERT_ARG_CHECKED(String, s, 0); 5917 CONVERT_SMI_ARG_CHECKED(radix, 1); 5918 5919 s->TryFlatten(); 5920 5921 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 5922 double value = StringToInt(isolate->unicode_cache(), s, radix); 5923 return isolate->heap()->NumberFromDouble(value); 5924 } 5925 5926 5927 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { 5928 NoHandleAllocation ha; 5929 CONVERT_ARG_CHECKED(String, str, 0); 5930 5931 // ECMA-262 section 15.1.2.3, empty string is NaN 5932 double value = StringToDouble(isolate->unicode_cache(), 5933 str, ALLOW_TRAILING_JUNK, OS::nan_value()); 5934 5935 // Create a number object from the value. 5936 return isolate->heap()->NumberFromDouble(value); 5937 } 5938 5939 5940 template <class Converter> 5941 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( 5942 Isolate* isolate, 5943 String* s, 5944 int length, 5945 int input_string_length, 5946 unibrow::Mapping<Converter, 128>* mapping) { 5947 // We try this twice, once with the assumption that the result is no longer 5948 // than the input and, if that assumption breaks, again with the exact 5949 // length. This may not be pretty, but it is nicer than what was here before 5950 // and I hereby claim my vaffel-is. 5951 // 5952 // Allocate the resulting string. 5953 // 5954 // NOTE: This assumes that the upper/lower case of an ASCII 5955 // character is also ASCII. This is currently the case, but it 5956 // might break in the future if we implement more context and locale 5957 // dependent upper/lower conversions. 5958 Object* o; 5959 { MaybeObject* maybe_o = s->IsAsciiRepresentation() 5960 ? isolate->heap()->AllocateRawAsciiString(length) 5961 : isolate->heap()->AllocateRawTwoByteString(length); 5962 if (!maybe_o->ToObject(&o)) return maybe_o; 5963 } 5964 String* result = String::cast(o); 5965 bool has_changed_character = false; 5966 5967 // Convert all characters to upper case, assuming that they will fit 5968 // in the buffer 5969 Access<StringInputBuffer> buffer( 5970 isolate->runtime_state()->string_input_buffer()); 5971 buffer->Reset(s); 5972 unibrow::uchar chars[Converter::kMaxWidth]; 5973 // We can assume that the string is not empty 5974 uc32 current = buffer->GetNext(); 5975 for (int i = 0; i < length;) { 5976 bool has_next = buffer->has_more(); 5977 uc32 next = has_next ? buffer->GetNext() : 0; 5978 int char_length = mapping->get(current, next, chars); 5979 if (char_length == 0) { 5980 // The case conversion of this character is the character itself. 5981 result->Set(i, current); 5982 i++; 5983 } else if (char_length == 1) { 5984 // Common case: converting the letter resulted in one character. 5985 ASSERT(static_cast<uc32>(chars[0]) != current); 5986 result->Set(i, chars[0]); 5987 has_changed_character = true; 5988 i++; 5989 } else if (length == input_string_length) { 5990 // We've assumed that the result would be as long as the 5991 // input but here is a character that converts to several 5992 // characters. No matter, we calculate the exact length 5993 // of the result and try the whole thing again. 5994 // 5995 // Note that this leaves room for optimization. We could just 5996 // memcpy what we already have to the result string. Also, 5997 // the result string is the last object allocated we could 5998 // "realloc" it and probably, in the vast majority of cases, 5999 // extend the existing string to be able to hold the full 6000 // result. 6001 int next_length = 0; 6002 if (has_next) { 6003 next_length = mapping->get(next, 0, chars); 6004 if (next_length == 0) next_length = 1; 6005 } 6006 int current_length = i + char_length + next_length; 6007 while (buffer->has_more()) { 6008 current = buffer->GetNext(); 6009 // NOTE: we use 0 as the next character here because, while 6010 // the next character may affect what a character converts to, 6011 // it does not in any case affect the length of what it convert 6012 // to. 6013 int char_length = mapping->get(current, 0, chars); 6014 if (char_length == 0) char_length = 1; 6015 current_length += char_length; 6016 if (current_length > Smi::kMaxValue) { 6017 isolate->context()->mark_out_of_memory(); 6018 return Failure::OutOfMemoryException(); 6019 } 6020 } 6021 // Try again with the real length. 6022 return Smi::FromInt(current_length); 6023 } else { 6024 for (int j = 0; j < char_length; j++) { 6025 result->Set(i, chars[j]); 6026 i++; 6027 } 6028 has_changed_character = true; 6029 } 6030 current = next; 6031 } 6032 if (has_changed_character) { 6033 return result; 6034 } else { 6035 // If we didn't actually change anything in doing the conversion 6036 // we simple return the result and let the converted string 6037 // become garbage; there is no reason to keep two identical strings 6038 // alive. 6039 return s; 6040 } 6041 } 6042 6043 6044 namespace { 6045 6046 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; 6047 6048 6049 // Given a word and two range boundaries returns a word with high bit 6050 // set in every byte iff the corresponding input byte was strictly in 6051 // the range (m, n). All the other bits in the result are cleared. 6052 // This function is only useful when it can be inlined and the 6053 // boundaries are statically known. 6054 // Requires: all bytes in the input word and the boundaries must be 6055 // ASCII (less than 0x7F). 6056 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { 6057 // Every byte in an ASCII string is less than or equal to 0x7F. 6058 ASSERT((w & (kOneInEveryByte * 0x7F)) == w); 6059 // Use strict inequalities since in edge cases the function could be 6060 // further simplified. 6061 ASSERT(0 < m && m < n && n < 0x7F); 6062 // Has high bit set in every w byte less than n. 6063 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; 6064 // Has high bit set in every w byte greater than m. 6065 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); 6066 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); 6067 } 6068 6069 6070 enum AsciiCaseConversion { 6071 ASCII_TO_LOWER, 6072 ASCII_TO_UPPER 6073 }; 6074 6075 6076 template <AsciiCaseConversion dir> 6077 struct FastAsciiConverter { 6078 static bool Convert(char* dst, char* src, int length) { 6079 #ifdef DEBUG 6080 char* saved_dst = dst; 6081 char* saved_src = src; 6082 #endif 6083 // We rely on the distance between upper and lower case letters 6084 // being a known power of 2. 6085 ASSERT('a' - 'A' == (1 << 5)); 6086 // Boundaries for the range of input characters than require conversion. 6087 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1; 6088 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1; 6089 bool changed = false; 6090 char* const limit = src + length; 6091 #ifdef V8_HOST_CAN_READ_UNALIGNED 6092 // Process the prefix of the input that requires no conversion one 6093 // (machine) word at a time. 6094 while (src <= limit - sizeof(uintptr_t)) { 6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6096 if (AsciiRangeMask(w, lo, hi) != 0) { 6097 changed = true; 6098 break; 6099 } 6100 *reinterpret_cast<uintptr_t*>(dst) = w; 6101 src += sizeof(uintptr_t); 6102 dst += sizeof(uintptr_t); 6103 } 6104 // Process the remainder of the input performing conversion when 6105 // required one word at a time. 6106 while (src <= limit - sizeof(uintptr_t)) { 6107 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6108 uintptr_t m = AsciiRangeMask(w, lo, hi); 6109 // The mask has high (7th) bit set in every byte that needs 6110 // conversion and we know that the distance between cases is 6111 // 1 << 5. 6112 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); 6113 src += sizeof(uintptr_t); 6114 dst += sizeof(uintptr_t); 6115 } 6116 #endif 6117 // Process the last few bytes of the input (or the whole input if 6118 // unaligned access is not supported). 6119 while (src < limit) { 6120 char c = *src; 6121 if (lo < c && c < hi) { 6122 c ^= (1 << 5); 6123 changed = true; 6124 } 6125 *dst = c; 6126 ++src; 6127 ++dst; 6128 } 6129 #ifdef DEBUG 6130 CheckConvert(saved_dst, saved_src, length, changed); 6131 #endif 6132 return changed; 6133 } 6134 6135 #ifdef DEBUG 6136 static void CheckConvert(char* dst, char* src, int length, bool changed) { 6137 bool expected_changed = false; 6138 for (int i = 0; i < length; i++) { 6139 if (dst[i] == src[i]) continue; 6140 expected_changed = true; 6141 if (dir == ASCII_TO_LOWER) { 6142 ASSERT('A' <= src[i] && src[i] <= 'Z'); 6143 ASSERT(dst[i] == src[i] + ('a' - 'A')); 6144 } else { 6145 ASSERT(dir == ASCII_TO_UPPER); 6146 ASSERT('a' <= src[i] && src[i] <= 'z'); 6147 ASSERT(dst[i] == src[i] - ('a' - 'A')); 6148 } 6149 } 6150 ASSERT(expected_changed == changed); 6151 } 6152 #endif 6153 }; 6154 6155 6156 struct ToLowerTraits { 6157 typedef unibrow::ToLowercase UnibrowConverter; 6158 6159 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter; 6160 }; 6161 6162 6163 struct ToUpperTraits { 6164 typedef unibrow::ToUppercase UnibrowConverter; 6165 6166 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter; 6167 }; 6168 6169 } // namespace 6170 6171 6172 template <typename ConvertTraits> 6173 MUST_USE_RESULT static MaybeObject* ConvertCase( 6174 Arguments args, 6175 Isolate* isolate, 6176 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { 6177 NoHandleAllocation ha; 6178 CONVERT_ARG_CHECKED(String, s, 0); 6179 s = s->TryFlattenGetString(); 6180 6181 const int length = s->length(); 6182 // Assume that the string is not empty; we need this assumption later 6183 if (length == 0) return s; 6184 6185 // Simpler handling of ASCII strings. 6186 // 6187 // NOTE: This assumes that the upper/lower case of an ASCII 6188 // character is also ASCII. This is currently the case, but it 6189 // might break in the future if we implement more context and locale 6190 // dependent upper/lower conversions. 6191 if (s->IsSeqAsciiString()) { 6192 Object* o; 6193 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length); 6194 if (!maybe_o->ToObject(&o)) return maybe_o; 6195 } 6196 SeqAsciiString* result = SeqAsciiString::cast(o); 6197 bool has_changed_character = ConvertTraits::AsciiConverter::Convert( 6198 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length); 6199 return has_changed_character ? result : s; 6200 } 6201 6202 Object* answer; 6203 { MaybeObject* maybe_answer = 6204 ConvertCaseHelper(isolate, s, length, length, mapping); 6205 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6206 } 6207 if (answer->IsSmi()) { 6208 // Retry with correct length. 6209 { MaybeObject* maybe_answer = 6210 ConvertCaseHelper(isolate, 6211 s, Smi::cast(answer)->value(), length, mapping); 6212 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6213 } 6214 } 6215 return answer; 6216 } 6217 6218 6219 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { 6220 return ConvertCase<ToLowerTraits>( 6221 args, isolate, isolate->runtime_state()->to_lower_mapping()); 6222 } 6223 6224 6225 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { 6226 return ConvertCase<ToUpperTraits>( 6227 args, isolate, isolate->runtime_state()->to_upper_mapping()); 6228 } 6229 6230 6231 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { 6232 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; 6233 } 6234 6235 6236 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { 6237 NoHandleAllocation ha; 6238 ASSERT(args.length() == 3); 6239 6240 CONVERT_ARG_CHECKED(String, s, 0); 6241 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); 6242 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); 6243 6244 s->TryFlatten(); 6245 int length = s->length(); 6246 6247 int left = 0; 6248 if (trimLeft) { 6249 while (left < length && IsTrimWhiteSpace(s->Get(left))) { 6250 left++; 6251 } 6252 } 6253 6254 int right = length; 6255 if (trimRight) { 6256 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { 6257 right--; 6258 } 6259 } 6260 return s->SubString(left, right); 6261 } 6262 6263 6264 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { 6265 ASSERT(args.length() == 3); 6266 HandleScope handle_scope(isolate); 6267 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6268 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 6269 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); 6270 6271 int subject_length = subject->length(); 6272 int pattern_length = pattern->length(); 6273 RUNTIME_ASSERT(pattern_length > 0); 6274 6275 if (limit == 0xffffffffu) { 6276 Handle<Object> cached_answer(StringSplitCache::Lookup( 6277 isolate->heap()->string_split_cache(), 6278 *subject, 6279 *pattern)); 6280 if (*cached_answer != Smi::FromInt(0)) { 6281 Handle<JSArray> result = 6282 isolate->factory()->NewJSArrayWithElements( 6283 Handle<FixedArray>::cast(cached_answer)); 6284 return *result; 6285 } 6286 } 6287 6288 // The limit can be very large (0xffffffffu), but since the pattern 6289 // isn't empty, we can never create more parts than ~half the length 6290 // of the subject. 6291 6292 if (!subject->IsFlat()) FlattenString(subject); 6293 6294 static const int kMaxInitialListCapacity = 16; 6295 6296 ZoneScope scope(isolate, DELETE_ON_EXIT); 6297 6298 // Find (up to limit) indices of separator and end-of-string in subject 6299 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); 6300 ZoneList<int> indices(initial_capacity); 6301 if (!pattern->IsFlat()) FlattenString(pattern); 6302 6303 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit); 6304 6305 if (static_cast<uint32_t>(indices.length()) < limit) { 6306 indices.Add(subject_length); 6307 } 6308 6309 // The list indices now contains the end of each part to create. 6310 6311 // Create JSArray of substrings separated by separator. 6312 int part_count = indices.length(); 6313 6314 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); 6315 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements(); 6316 if (maybe_result->IsFailure()) return maybe_result; 6317 result->set_length(Smi::FromInt(part_count)); 6318 6319 ASSERT(result->HasFastElements()); 6320 6321 if (part_count == 1 && indices.at(0) == subject_length) { 6322 FixedArray::cast(result->elements())->set(0, *subject); 6323 return *result; 6324 } 6325 6326 Handle<FixedArray> elements(FixedArray::cast(result->elements())); 6327 int part_start = 0; 6328 for (int i = 0; i < part_count; i++) { 6329 HandleScope local_loop_handle; 6330 int part_end = indices.at(i); 6331 Handle<String> substring = 6332 isolate->factory()->NewProperSubString(subject, part_start, part_end); 6333 elements->set(i, *substring); 6334 part_start = part_end + pattern_length; 6335 } 6336 6337 if (limit == 0xffffffffu) { 6338 if (result->HasFastElements()) { 6339 StringSplitCache::Enter(isolate->heap(), 6340 isolate->heap()->string_split_cache(), 6341 *subject, 6342 *pattern, 6343 *elements); 6344 } 6345 } 6346 6347 return *result; 6348 } 6349 6350 6351 // Copies ASCII characters to the given fixed array looking up 6352 // one-char strings in the cache. Gives up on the first char that is 6353 // not in the cache and fills the remainder with smi zeros. Returns 6354 // the length of the successfully copied prefix. 6355 static int CopyCachedAsciiCharsToArray(Heap* heap, 6356 const char* chars, 6357 FixedArray* elements, 6358 int length) { 6359 AssertNoAllocation no_gc; 6360 FixedArray* ascii_cache = heap->single_character_string_cache(); 6361 Object* undefined = heap->undefined_value(); 6362 int i; 6363 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 6364 for (i = 0; i < length; ++i) { 6365 Object* value = ascii_cache->get(chars[i]); 6366 if (value == undefined) break; 6367 elements->set(i, value, mode); 6368 } 6369 if (i < length) { 6370 ASSERT(Smi::FromInt(0) == 0); 6371 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 6372 } 6373 #ifdef DEBUG 6374 for (int j = 0; j < length; ++j) { 6375 Object* element = elements->get(j); 6376 ASSERT(element == Smi::FromInt(0) || 6377 (element->IsString() && String::cast(element)->LooksValid())); 6378 } 6379 #endif 6380 return i; 6381 } 6382 6383 6384 // Converts a String to JSArray. 6385 // For example, "foo" => ["f", "o", "o"]. 6386 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { 6387 HandleScope scope(isolate); 6388 ASSERT(args.length() == 2); 6389 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6390 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 6391 6392 s = FlattenGetString(s); 6393 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); 6394 6395 Handle<FixedArray> elements; 6396 int position = 0; 6397 if (s->IsFlat() && s->IsAsciiRepresentation()) { 6398 // Try using cached chars where possible. 6399 Object* obj; 6400 { MaybeObject* maybe_obj = 6401 isolate->heap()->AllocateUninitializedFixedArray(length); 6402 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6403 } 6404 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate); 6405 String::FlatContent content = s->GetFlatContent(); 6406 if (content.IsAscii()) { 6407 Vector<const char> chars = content.ToAsciiVector(); 6408 // Note, this will initialize all elements (not only the prefix) 6409 // to prevent GC from seeing partially initialized array. 6410 position = CopyCachedAsciiCharsToArray(isolate->heap(), 6411 chars.start(), 6412 *elements, 6413 length); 6414 } else { 6415 MemsetPointer(elements->data_start(), 6416 isolate->heap()->undefined_value(), 6417 length); 6418 } 6419 } else { 6420 elements = isolate->factory()->NewFixedArray(length); 6421 } 6422 for (int i = position; i < length; ++i) { 6423 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i)); 6424 elements->set(i, *str); 6425 } 6426 6427 #ifdef DEBUG 6428 for (int i = 0; i < length; ++i) { 6429 ASSERT(String::cast(elements->get(i))->length() == 1); 6430 } 6431 #endif 6432 6433 return *isolate->factory()->NewJSArrayWithElements(elements); 6434 } 6435 6436 6437 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) { 6438 NoHandleAllocation ha; 6439 ASSERT(args.length() == 1); 6440 CONVERT_ARG_CHECKED(String, value, 0); 6441 return value->ToObject(); 6442 } 6443 6444 6445 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { 6446 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 6447 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); 6448 return char_length == 0; 6449 } 6450 6451 6452 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) { 6453 NoHandleAllocation ha; 6454 ASSERT(args.length() == 1); 6455 6456 Object* number = args[0]; 6457 RUNTIME_ASSERT(number->IsNumber()); 6458 6459 return isolate->heap()->NumberToString(number); 6460 } 6461 6462 6463 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) { 6464 NoHandleAllocation ha; 6465 ASSERT(args.length() == 1); 6466 6467 Object* number = args[0]; 6468 RUNTIME_ASSERT(number->IsNumber()); 6469 6470 return isolate->heap()->NumberToString(number, false); 6471 } 6472 6473 6474 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { 6475 NoHandleAllocation ha; 6476 ASSERT(args.length() == 1); 6477 6478 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6479 6480 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6481 if (number > 0 && number <= Smi::kMaxValue) { 6482 return Smi::FromInt(static_cast<int>(number)); 6483 } 6484 return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); 6485 } 6486 6487 6488 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { 6489 NoHandleAllocation ha; 6490 ASSERT(args.length() == 1); 6491 6492 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6493 6494 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6495 if (number > 0 && number <= Smi::kMaxValue) { 6496 return Smi::FromInt(static_cast<int>(number)); 6497 } 6498 6499 double double_value = DoubleToInteger(number); 6500 // Map both -0 and +0 to +0. 6501 if (double_value == 0) double_value = 0; 6502 6503 return isolate->heap()->NumberFromDouble(double_value); 6504 } 6505 6506 6507 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) { 6508 NoHandleAllocation ha; 6509 ASSERT(args.length() == 1); 6510 6511 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); 6512 return isolate->heap()->NumberFromUint32(number); 6513 } 6514 6515 6516 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) { 6517 NoHandleAllocation ha; 6518 ASSERT(args.length() == 1); 6519 6520 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6521 6522 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6523 if (number > 0 && number <= Smi::kMaxValue) { 6524 return Smi::FromInt(static_cast<int>(number)); 6525 } 6526 return isolate->heap()->NumberFromInt32(DoubleToInt32(number)); 6527 } 6528 6529 6530 // Converts a Number to a Smi, if possible. Returns NaN if the number is not 6531 // a small integer. 6532 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { 6533 NoHandleAllocation ha; 6534 ASSERT(args.length() == 1); 6535 6536 Object* obj = args[0]; 6537 if (obj->IsSmi()) { 6538 return obj; 6539 } 6540 if (obj->IsHeapNumber()) { 6541 double value = HeapNumber::cast(obj)->value(); 6542 int int_value = FastD2I(value); 6543 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 6544 return Smi::FromInt(int_value); 6545 } 6546 } 6547 return isolate->heap()->nan_value(); 6548 } 6549 6550 6551 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { 6552 NoHandleAllocation ha; 6553 ASSERT(args.length() == 0); 6554 return isolate->heap()->AllocateHeapNumber(0); 6555 } 6556 6557 6558 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { 6559 NoHandleAllocation ha; 6560 ASSERT(args.length() == 2); 6561 6562 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6563 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6564 return isolate->heap()->NumberFromDouble(x + y); 6565 } 6566 6567 6568 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) { 6569 NoHandleAllocation ha; 6570 ASSERT(args.length() == 2); 6571 6572 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6573 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6574 return isolate->heap()->NumberFromDouble(x - y); 6575 } 6576 6577 6578 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) { 6579 NoHandleAllocation ha; 6580 ASSERT(args.length() == 2); 6581 6582 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6583 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6584 return isolate->heap()->NumberFromDouble(x * y); 6585 } 6586 6587 6588 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) { 6589 NoHandleAllocation ha; 6590 ASSERT(args.length() == 1); 6591 6592 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6593 return isolate->heap()->NumberFromDouble(-x); 6594 } 6595 6596 6597 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) { 6598 NoHandleAllocation ha; 6599 ASSERT(args.length() == 0); 6600 6601 return isolate->heap()->NumberFromDouble(9876543210.0); 6602 } 6603 6604 6605 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) { 6606 NoHandleAllocation ha; 6607 ASSERT(args.length() == 2); 6608 6609 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6610 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6611 return isolate->heap()->NumberFromDouble(x / y); 6612 } 6613 6614 6615 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) { 6616 NoHandleAllocation ha; 6617 ASSERT(args.length() == 2); 6618 6619 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6620 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6621 6622 x = modulo(x, y); 6623 // NumberFromDouble may return a Smi instead of a Number object 6624 return isolate->heap()->NumberFromDouble(x); 6625 } 6626 6627 6628 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { 6629 NoHandleAllocation ha; 6630 ASSERT(args.length() == 2); 6631 CONVERT_ARG_CHECKED(String, str1, 0); 6632 CONVERT_ARG_CHECKED(String, str2, 1); 6633 isolate->counters()->string_add_runtime()->Increment(); 6634 return isolate->heap()->AllocateConsString(str1, str2); 6635 } 6636 6637 6638 template <typename sinkchar> 6639 static inline void StringBuilderConcatHelper(String* special, 6640 sinkchar* sink, 6641 FixedArray* fixed_array, 6642 int array_length) { 6643 int position = 0; 6644 for (int i = 0; i < array_length; i++) { 6645 Object* element = fixed_array->get(i); 6646 if (element->IsSmi()) { 6647 // Smi encoding of position and length. 6648 int encoded_slice = Smi::cast(element)->value(); 6649 int pos; 6650 int len; 6651 if (encoded_slice > 0) { 6652 // Position and length encoded in one smi. 6653 pos = StringBuilderSubstringPosition::decode(encoded_slice); 6654 len = StringBuilderSubstringLength::decode(encoded_slice); 6655 } else { 6656 // Position and length encoded in two smis. 6657 Object* obj = fixed_array->get(++i); 6658 ASSERT(obj->IsSmi()); 6659 pos = Smi::cast(obj)->value(); 6660 len = -encoded_slice; 6661 } 6662 String::WriteToFlat(special, 6663 sink + position, 6664 pos, 6665 pos + len); 6666 position += len; 6667 } else { 6668 String* string = String::cast(element); 6669 int element_length = string->length(); 6670 String::WriteToFlat(string, sink + position, 0, element_length); 6671 position += element_length; 6672 } 6673 } 6674 } 6675 6676 6677 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { 6678 NoHandleAllocation ha; 6679 ASSERT(args.length() == 3); 6680 CONVERT_ARG_CHECKED(JSArray, array, 0); 6681 if (!args[1]->IsSmi()) { 6682 isolate->context()->mark_out_of_memory(); 6683 return Failure::OutOfMemoryException(); 6684 } 6685 int array_length = args.smi_at(1); 6686 CONVERT_ARG_CHECKED(String, special, 2); 6687 6688 // This assumption is used by the slice encoding in one or two smis. 6689 ASSERT(Smi::kMaxValue >= String::kMaxLength); 6690 6691 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements(); 6692 if (maybe_result->IsFailure()) return maybe_result; 6693 6694 int special_length = special->length(); 6695 if (!array->HasFastElements()) { 6696 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6697 } 6698 FixedArray* fixed_array = FixedArray::cast(array->elements()); 6699 if (fixed_array->length() < array_length) { 6700 array_length = fixed_array->length(); 6701 } 6702 6703 if (array_length == 0) { 6704 return isolate->heap()->empty_string(); 6705 } else if (array_length == 1) { 6706 Object* first = fixed_array->get(0); 6707 if (first->IsString()) return first; 6708 } 6709 6710 bool ascii = special->HasOnlyAsciiChars(); 6711 int position = 0; 6712 for (int i = 0; i < array_length; i++) { 6713 int increment = 0; 6714 Object* elt = fixed_array->get(i); 6715 if (elt->IsSmi()) { 6716 // Smi encoding of position and length. 6717 int smi_value = Smi::cast(elt)->value(); 6718 int pos; 6719 int len; 6720 if (smi_value > 0) { 6721 // Position and length encoded in one smi. 6722 pos = StringBuilderSubstringPosition::decode(smi_value); 6723 len = StringBuilderSubstringLength::decode(smi_value); 6724 } else { 6725 // Position and length encoded in two smis. 6726 len = -smi_value; 6727 // Get the position and check that it is a positive smi. 6728 i++; 6729 if (i >= array_length) { 6730 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6731 } 6732 Object* next_smi = fixed_array->get(i); 6733 if (!next_smi->IsSmi()) { 6734 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6735 } 6736 pos = Smi::cast(next_smi)->value(); 6737 if (pos < 0) { 6738 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6739 } 6740 } 6741 ASSERT(pos >= 0); 6742 ASSERT(len >= 0); 6743 if (pos > special_length || len > special_length - pos) { 6744 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6745 } 6746 increment = len; 6747 } else if (elt->IsString()) { 6748 String* element = String::cast(elt); 6749 int element_length = element->length(); 6750 increment = element_length; 6751 if (ascii && !element->HasOnlyAsciiChars()) { 6752 ascii = false; 6753 } 6754 } else { 6755 ASSERT(!elt->IsTheHole()); 6756 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6757 } 6758 if (increment > String::kMaxLength - position) { 6759 isolate->context()->mark_out_of_memory(); 6760 return Failure::OutOfMemoryException(); 6761 } 6762 position += increment; 6763 } 6764 6765 int length = position; 6766 Object* object; 6767 6768 if (ascii) { 6769 { MaybeObject* maybe_object = 6770 isolate->heap()->AllocateRawAsciiString(length); 6771 if (!maybe_object->ToObject(&object)) return maybe_object; 6772 } 6773 SeqAsciiString* answer = SeqAsciiString::cast(object); 6774 StringBuilderConcatHelper(special, 6775 answer->GetChars(), 6776 fixed_array, 6777 array_length); 6778 return answer; 6779 } else { 6780 { MaybeObject* maybe_object = 6781 isolate->heap()->AllocateRawTwoByteString(length); 6782 if (!maybe_object->ToObject(&object)) return maybe_object; 6783 } 6784 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 6785 StringBuilderConcatHelper(special, 6786 answer->GetChars(), 6787 fixed_array, 6788 array_length); 6789 return answer; 6790 } 6791 } 6792 6793 6794 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { 6795 NoHandleAllocation ha; 6796 ASSERT(args.length() == 3); 6797 CONVERT_ARG_CHECKED(JSArray, array, 0); 6798 if (!args[1]->IsSmi()) { 6799 isolate->context()->mark_out_of_memory(); 6800 return Failure::OutOfMemoryException(); 6801 } 6802 int array_length = args.smi_at(1); 6803 CONVERT_ARG_CHECKED(String, separator, 2); 6804 6805 if (!array->HasFastElements()) { 6806 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6807 } 6808 FixedArray* fixed_array = FixedArray::cast(array->elements()); 6809 if (fixed_array->length() < array_length) { 6810 array_length = fixed_array->length(); 6811 } 6812 6813 if (array_length == 0) { 6814 return isolate->heap()->empty_string(); 6815 } else if (array_length == 1) { 6816 Object* first = fixed_array->get(0); 6817 if (first->IsString()) return first; 6818 } 6819 6820 int separator_length = separator->length(); 6821 int max_nof_separators = 6822 (String::kMaxLength + separator_length - 1) / separator_length; 6823 if (max_nof_separators < (array_length - 1)) { 6824 isolate->context()->mark_out_of_memory(); 6825 return Failure::OutOfMemoryException(); 6826 } 6827 int length = (array_length - 1) * separator_length; 6828 for (int i = 0; i < array_length; i++) { 6829 Object* element_obj = fixed_array->get(i); 6830 if (!element_obj->IsString()) { 6831 // TODO(1161): handle this case. 6832 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 6833 } 6834 String* element = String::cast(element_obj); 6835 int increment = element->length(); 6836 if (increment > String::kMaxLength - length) { 6837 isolate->context()->mark_out_of_memory(); 6838 return Failure::OutOfMemoryException(); 6839 } 6840 length += increment; 6841 } 6842 6843 Object* object; 6844 { MaybeObject* maybe_object = 6845 isolate->heap()->AllocateRawTwoByteString(length); 6846 if (!maybe_object->ToObject(&object)) return maybe_object; 6847 } 6848 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 6849 6850 uc16* sink = answer->GetChars(); 6851 #ifdef DEBUG 6852 uc16* end = sink + length; 6853 #endif 6854 6855 String* first = String::cast(fixed_array->get(0)); 6856 int first_length = first->length(); 6857 String::WriteToFlat(first, sink, 0, first_length); 6858 sink += first_length; 6859 6860 for (int i = 1; i < array_length; i++) { 6861 ASSERT(sink + separator_length <= end); 6862 String::WriteToFlat(separator, sink, 0, separator_length); 6863 sink += separator_length; 6864 6865 String* element = String::cast(fixed_array->get(i)); 6866 int element_length = element->length(); 6867 ASSERT(sink + element_length <= end); 6868 String::WriteToFlat(element, sink, 0, element_length); 6869 sink += element_length; 6870 } 6871 ASSERT(sink == end); 6872 6873 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead. 6874 return answer; 6875 } 6876 6877 template <typename Char> 6878 static void JoinSparseArrayWithSeparator(FixedArray* elements, 6879 int elements_length, 6880 uint32_t array_length, 6881 String* separator, 6882 Vector<Char> buffer) { 6883 int previous_separator_position = 0; 6884 int separator_length = separator->length(); 6885 int cursor = 0; 6886 for (int i = 0; i < elements_length; i += 2) { 6887 int position = NumberToInt32(elements->get(i)); 6888 String* string = String::cast(elements->get(i + 1)); 6889 int string_length = string->length(); 6890 if (string->length() > 0) { 6891 while (previous_separator_position < position) { 6892 String::WriteToFlat<Char>(separator, &buffer[cursor], 6893 0, separator_length); 6894 cursor += separator_length; 6895 previous_separator_position++; 6896 } 6897 String::WriteToFlat<Char>(string, &buffer[cursor], 6898 0, string_length); 6899 cursor += string->length(); 6900 } 6901 } 6902 if (separator_length > 0) { 6903 // Array length must be representable as a signed 32-bit number, 6904 // otherwise the total string length would have been too large. 6905 ASSERT(array_length <= 0x7fffffff); // Is int32_t. 6906 int last_array_index = static_cast<int>(array_length - 1); 6907 while (previous_separator_position < last_array_index) { 6908 String::WriteToFlat<Char>(separator, &buffer[cursor], 6909 0, separator_length); 6910 cursor += separator_length; 6911 previous_separator_position++; 6912 } 6913 } 6914 ASSERT(cursor <= buffer.length()); 6915 } 6916 6917 6918 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { 6919 NoHandleAllocation ha; 6920 ASSERT(args.length() == 3); 6921 CONVERT_ARG_CHECKED(JSArray, elements_array, 0); 6922 RUNTIME_ASSERT(elements_array->HasFastElements() || 6923 elements_array->HasFastSmiOnlyElements()); 6924 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); 6925 CONVERT_ARG_CHECKED(String, separator, 2); 6926 // elements_array is fast-mode JSarray of alternating positions 6927 // (increasing order) and strings. 6928 // array_length is length of original array (used to add separators); 6929 // separator is string to put between elements. Assumed to be non-empty. 6930 6931 // Find total length of join result. 6932 int string_length = 0; 6933 bool is_ascii = separator->IsAsciiRepresentation(); 6934 int max_string_length; 6935 if (is_ascii) { 6936 max_string_length = SeqAsciiString::kMaxLength; 6937 } else { 6938 max_string_length = SeqTwoByteString::kMaxLength; 6939 } 6940 bool overflow = false; 6941 CONVERT_NUMBER_CHECKED(int, elements_length, 6942 Int32, elements_array->length()); 6943 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. 6944 FixedArray* elements = FixedArray::cast(elements_array->elements()); 6945 for (int i = 0; i < elements_length; i += 2) { 6946 RUNTIME_ASSERT(elements->get(i)->IsNumber()); 6947 RUNTIME_ASSERT(elements->get(i + 1)->IsString()); 6948 String* string = String::cast(elements->get(i + 1)); 6949 int length = string->length(); 6950 if (is_ascii && !string->IsAsciiRepresentation()) { 6951 is_ascii = false; 6952 max_string_length = SeqTwoByteString::kMaxLength; 6953 } 6954 if (length > max_string_length || 6955 max_string_length - length < string_length) { 6956 overflow = true; 6957 break; 6958 } 6959 string_length += length; 6960 } 6961 int separator_length = separator->length(); 6962 if (!overflow && separator_length > 0) { 6963 if (array_length <= 0x7fffffffu) { 6964 int separator_count = static_cast<int>(array_length) - 1; 6965 int remaining_length = max_string_length - string_length; 6966 if ((remaining_length / separator_length) >= separator_count) { 6967 string_length += separator_length * (array_length - 1); 6968 } else { 6969 // Not room for the separators within the maximal string length. 6970 overflow = true; 6971 } 6972 } else { 6973 // Nonempty separator and at least 2^31-1 separators necessary 6974 // means that the string is too large to create. 6975 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); 6976 overflow = true; 6977 } 6978 } 6979 if (overflow) { 6980 // Throw OutOfMemory exception for creating too large a string. 6981 V8::FatalProcessOutOfMemory("Array join result too large."); 6982 } 6983 6984 if (is_ascii) { 6985 MaybeObject* result_allocation = 6986 isolate->heap()->AllocateRawAsciiString(string_length); 6987 if (result_allocation->IsFailure()) return result_allocation; 6988 SeqAsciiString* result_string = 6989 SeqAsciiString::cast(result_allocation->ToObjectUnchecked()); 6990 JoinSparseArrayWithSeparator<char>(elements, 6991 elements_length, 6992 array_length, 6993 separator, 6994 Vector<char>(result_string->GetChars(), 6995 string_length)); 6996 return result_string; 6997 } else { 6998 MaybeObject* result_allocation = 6999 isolate->heap()->AllocateRawTwoByteString(string_length); 7000 if (result_allocation->IsFailure()) return result_allocation; 7001 SeqTwoByteString* result_string = 7002 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked()); 7003 JoinSparseArrayWithSeparator<uc16>(elements, 7004 elements_length, 7005 array_length, 7006 separator, 7007 Vector<uc16>(result_string->GetChars(), 7008 string_length)); 7009 return result_string; 7010 } 7011 } 7012 7013 7014 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) { 7015 NoHandleAllocation ha; 7016 ASSERT(args.length() == 2); 7017 7018 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7019 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7020 return isolate->heap()->NumberFromInt32(x | y); 7021 } 7022 7023 7024 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) { 7025 NoHandleAllocation ha; 7026 ASSERT(args.length() == 2); 7027 7028 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7029 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7030 return isolate->heap()->NumberFromInt32(x & y); 7031 } 7032 7033 7034 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { 7035 NoHandleAllocation ha; 7036 ASSERT(args.length() == 2); 7037 7038 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7039 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7040 return isolate->heap()->NumberFromInt32(x ^ y); 7041 } 7042 7043 7044 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) { 7045 NoHandleAllocation ha; 7046 ASSERT(args.length() == 1); 7047 7048 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7049 return isolate->heap()->NumberFromInt32(~x); 7050 } 7051 7052 7053 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { 7054 NoHandleAllocation ha; 7055 ASSERT(args.length() == 2); 7056 7057 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7058 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7059 return isolate->heap()->NumberFromInt32(x << (y & 0x1f)); 7060 } 7061 7062 7063 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) { 7064 NoHandleAllocation ha; 7065 ASSERT(args.length() == 2); 7066 7067 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 7068 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7069 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f)); 7070 } 7071 7072 7073 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) { 7074 NoHandleAllocation ha; 7075 ASSERT(args.length() == 2); 7076 7077 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7078 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7079 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); 7080 } 7081 7082 7083 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { 7084 NoHandleAllocation ha; 7085 ASSERT(args.length() == 2); 7086 7087 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7088 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7089 if (isnan(x)) return Smi::FromInt(NOT_EQUAL); 7090 if (isnan(y)) return Smi::FromInt(NOT_EQUAL); 7091 if (x == y) return Smi::FromInt(EQUAL); 7092 Object* result; 7093 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 7094 result = Smi::FromInt(EQUAL); 7095 } else { 7096 result = Smi::FromInt(NOT_EQUAL); 7097 } 7098 return result; 7099 } 7100 7101 7102 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { 7103 NoHandleAllocation ha; 7104 ASSERT(args.length() == 2); 7105 7106 CONVERT_ARG_CHECKED(String, x, 0); 7107 CONVERT_ARG_CHECKED(String, y, 1); 7108 7109 bool not_equal = !x->Equals(y); 7110 // This is slightly convoluted because the value that signifies 7111 // equality is 0 and inequality is 1 so we have to negate the result 7112 // from String::Equals. 7113 ASSERT(not_equal == 0 || not_equal == 1); 7114 STATIC_CHECK(EQUAL == 0); 7115 STATIC_CHECK(NOT_EQUAL == 1); 7116 return Smi::FromInt(not_equal); 7117 } 7118 7119 7120 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { 7121 NoHandleAllocation ha; 7122 ASSERT(args.length() == 3); 7123 7124 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7125 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7126 if (isnan(x) || isnan(y)) return args[2]; 7127 if (x == y) return Smi::FromInt(EQUAL); 7128 if (isless(x, y)) return Smi::FromInt(LESS); 7129 return Smi::FromInt(GREATER); 7130 } 7131 7132 7133 // Compare two Smis as if they were converted to strings and then 7134 // compared lexicographically. 7135 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { 7136 NoHandleAllocation ha; 7137 ASSERT(args.length() == 2); 7138 CONVERT_SMI_ARG_CHECKED(x_value, 0); 7139 CONVERT_SMI_ARG_CHECKED(y_value, 1); 7140 7141 // If the integers are equal so are the string representations. 7142 if (x_value == y_value) return Smi::FromInt(EQUAL); 7143 7144 // If one of the integers is zero the normal integer order is the 7145 // same as the lexicographic order of the string representations. 7146 if (x_value == 0 || y_value == 0) 7147 return Smi::FromInt(x_value < y_value ? LESS : GREATER); 7148 7149 // If only one of the integers is negative the negative number is 7150 // smallest because the char code of '-' is less than the char code 7151 // of any digit. Otherwise, we make both values positive. 7152 7153 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on 7154 // architectures using 32-bit Smis. 7155 uint32_t x_scaled = x_value; 7156 uint32_t y_scaled = y_value; 7157 if (x_value < 0 || y_value < 0) { 7158 if (y_value >= 0) return Smi::FromInt(LESS); 7159 if (x_value >= 0) return Smi::FromInt(GREATER); 7160 x_scaled = -x_value; 7161 y_scaled = -y_value; 7162 } 7163 7164 static const uint32_t kPowersOf10[] = { 7165 1, 10, 100, 1000, 10*1000, 100*1000, 7166 1000*1000, 10*1000*1000, 100*1000*1000, 7167 1000*1000*1000 7168 }; 7169 7170 // If the integers have the same number of decimal digits they can be 7171 // compared directly as the numeric order is the same as the 7172 // lexicographic order. If one integer has fewer digits, it is scaled 7173 // by some power of 10 to have the same number of digits as the longer 7174 // integer. If the scaled integers are equal it means the shorter 7175 // integer comes first in the lexicographic order. 7176 7177 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 7178 int x_log2 = IntegerLog2(x_scaled); 7179 int x_log10 = ((x_log2 + 1) * 1233) >> 12; 7180 x_log10 -= x_scaled < kPowersOf10[x_log10]; 7181 7182 int y_log2 = IntegerLog2(y_scaled); 7183 int y_log10 = ((y_log2 + 1) * 1233) >> 12; 7184 y_log10 -= y_scaled < kPowersOf10[y_log10]; 7185 7186 int tie = EQUAL; 7187 7188 if (x_log10 < y_log10) { 7189 // X has fewer digits. We would like to simply scale up X but that 7190 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would 7191 // be scaled up to 9_000_000_000. So we scale up by the next 7192 // smallest power and scale down Y to drop one digit. It is OK to 7193 // drop one digit from the longer integer since the final digit is 7194 // past the length of the shorter integer. 7195 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; 7196 y_scaled /= 10; 7197 tie = LESS; 7198 } else if (y_log10 < x_log10) { 7199 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; 7200 x_scaled /= 10; 7201 tie = GREATER; 7202 } 7203 7204 if (x_scaled < y_scaled) return Smi::FromInt(LESS); 7205 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); 7206 return Smi::FromInt(tie); 7207 } 7208 7209 7210 static Object* StringInputBufferCompare(RuntimeState* state, 7211 String* x, 7212 String* y) { 7213 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx(); 7214 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy(); 7215 bufx.Reset(x); 7216 bufy.Reset(y); 7217 while (bufx.has_more() && bufy.has_more()) { 7218 int d = bufx.GetNext() - bufy.GetNext(); 7219 if (d < 0) return Smi::FromInt(LESS); 7220 else if (d > 0) return Smi::FromInt(GREATER); 7221 } 7222 7223 // x is (non-trivial) prefix of y: 7224 if (bufy.has_more()) return Smi::FromInt(LESS); 7225 // y is prefix of x: 7226 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL); 7227 } 7228 7229 7230 static Object* FlatStringCompare(String* x, String* y) { 7231 ASSERT(x->IsFlat()); 7232 ASSERT(y->IsFlat()); 7233 Object* equal_prefix_result = Smi::FromInt(EQUAL); 7234 int prefix_length = x->length(); 7235 if (y->length() < prefix_length) { 7236 prefix_length = y->length(); 7237 equal_prefix_result = Smi::FromInt(GREATER); 7238 } else if (y->length() > prefix_length) { 7239 equal_prefix_result = Smi::FromInt(LESS); 7240 } 7241 int r; 7242 String::FlatContent x_content = x->GetFlatContent(); 7243 String::FlatContent y_content = y->GetFlatContent(); 7244 if (x_content.IsAscii()) { 7245 Vector<const char> x_chars = x_content.ToAsciiVector(); 7246 if (y_content.IsAscii()) { 7247 Vector<const char> y_chars = y_content.ToAsciiVector(); 7248 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7249 } else { 7250 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7251 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7252 } 7253 } else { 7254 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 7255 if (y_content.IsAscii()) { 7256 Vector<const char> y_chars = y_content.ToAsciiVector(); 7257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7258 } else { 7259 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7260 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7261 } 7262 } 7263 Object* result; 7264 if (r == 0) { 7265 result = equal_prefix_result; 7266 } else { 7267 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); 7268 } 7269 ASSERT(result == 7270 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y)); 7271 return result; 7272 } 7273 7274 7275 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { 7276 NoHandleAllocation ha; 7277 ASSERT(args.length() == 2); 7278 7279 CONVERT_ARG_CHECKED(String, x, 0); 7280 CONVERT_ARG_CHECKED(String, y, 1); 7281 7282 isolate->counters()->string_compare_runtime()->Increment(); 7283 7284 // A few fast case tests before we flatten. 7285 if (x == y) return Smi::FromInt(EQUAL); 7286 if (y->length() == 0) { 7287 if (x->length() == 0) return Smi::FromInt(EQUAL); 7288 return Smi::FromInt(GREATER); 7289 } else if (x->length() == 0) { 7290 return Smi::FromInt(LESS); 7291 } 7292 7293 int d = x->Get(0) - y->Get(0); 7294 if (d < 0) return Smi::FromInt(LESS); 7295 else if (d > 0) return Smi::FromInt(GREATER); 7296 7297 Object* obj; 7298 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); 7299 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7300 } 7301 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); 7302 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7303 } 7304 7305 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) 7306 : StringInputBufferCompare(isolate->runtime_state(), x, y); 7307 } 7308 7309 7310 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { 7311 NoHandleAllocation ha; 7312 ASSERT(args.length() == 1); 7313 isolate->counters()->math_acos()->Increment(); 7314 7315 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7316 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); 7317 } 7318 7319 7320 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) { 7321 NoHandleAllocation ha; 7322 ASSERT(args.length() == 1); 7323 isolate->counters()->math_asin()->Increment(); 7324 7325 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7326 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x); 7327 } 7328 7329 7330 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) { 7331 NoHandleAllocation ha; 7332 ASSERT(args.length() == 1); 7333 isolate->counters()->math_atan()->Increment(); 7334 7335 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7336 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x); 7337 } 7338 7339 7340 static const double kPiDividedBy4 = 0.78539816339744830962; 7341 7342 7343 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { 7344 NoHandleAllocation ha; 7345 ASSERT(args.length() == 2); 7346 isolate->counters()->math_atan2()->Increment(); 7347 7348 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7349 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7350 double result; 7351 if (isinf(x) && isinf(y)) { 7352 // Make sure that the result in case of two infinite arguments 7353 // is a multiple of Pi / 4. The sign of the result is determined 7354 // by the first argument (x) and the sign of the second argument 7355 // determines the multiplier: one or three. 7356 int multiplier = (x < 0) ? -1 : 1; 7357 if (y < 0) multiplier *= 3; 7358 result = multiplier * kPiDividedBy4; 7359 } else { 7360 result = atan2(x, y); 7361 } 7362 return isolate->heap()->AllocateHeapNumber(result); 7363 } 7364 7365 7366 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) { 7367 NoHandleAllocation ha; 7368 ASSERT(args.length() == 1); 7369 isolate->counters()->math_ceil()->Increment(); 7370 7371 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7372 return isolate->heap()->NumberFromDouble(ceiling(x)); 7373 } 7374 7375 7376 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) { 7377 NoHandleAllocation ha; 7378 ASSERT(args.length() == 1); 7379 isolate->counters()->math_cos()->Increment(); 7380 7381 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7382 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x); 7383 } 7384 7385 7386 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { 7387 NoHandleAllocation ha; 7388 ASSERT(args.length() == 1); 7389 isolate->counters()->math_exp()->Increment(); 7390 7391 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7392 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x); 7393 } 7394 7395 7396 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) { 7397 NoHandleAllocation ha; 7398 ASSERT(args.length() == 1); 7399 isolate->counters()->math_floor()->Increment(); 7400 7401 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7402 return isolate->heap()->NumberFromDouble(floor(x)); 7403 } 7404 7405 7406 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { 7407 NoHandleAllocation ha; 7408 ASSERT(args.length() == 1); 7409 isolate->counters()->math_log()->Increment(); 7410 7411 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7412 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); 7413 } 7414 7415 // Slow version of Math.pow. We check for fast paths for special cases. 7416 // Used if SSE2/VFP3 is not available. 7417 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { 7418 NoHandleAllocation ha; 7419 ASSERT(args.length() == 2); 7420 isolate->counters()->math_pow()->Increment(); 7421 7422 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7423 7424 // If the second argument is a smi, it is much faster to call the 7425 // custom powi() function than the generic pow(). 7426 if (args[1]->IsSmi()) { 7427 int y = args.smi_at(1); 7428 return isolate->heap()->NumberFromDouble(power_double_int(x, y)); 7429 } 7430 7431 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7432 int y_int = static_cast<int>(y); 7433 double result; 7434 if (y == y_int) { 7435 result = power_double_int(x, y_int); // Returns 1 if exponent is 0. 7436 } else if (y == 0.5) { 7437 result = (isinf(x)) ? V8_INFINITY 7438 : fast_sqrt(x + 0.0); // Convert -0 to +0. 7439 } else if (y == -0.5) { 7440 result = (isinf(x)) ? 0 7441 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0. 7442 } else { 7443 result = power_double_double(x, y); 7444 } 7445 if (isnan(result)) return isolate->heap()->nan_value(); 7446 return isolate->heap()->AllocateHeapNumber(result); 7447 } 7448 7449 // Fast version of Math.pow if we know that y is not an integer and y is not 7450 // -0.5 or 0.5. Used as slow case from full codegen. 7451 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { 7452 NoHandleAllocation ha; 7453 ASSERT(args.length() == 2); 7454 isolate->counters()->math_pow()->Increment(); 7455 7456 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7457 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7458 if (y == 0) { 7459 return Smi::FromInt(1); 7460 } else { 7461 double result = power_double_double(x, y); 7462 if (isnan(result)) return isolate->heap()->nan_value(); 7463 return isolate->heap()->AllocateHeapNumber(result); 7464 } 7465 } 7466 7467 7468 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { 7469 NoHandleAllocation ha; 7470 ASSERT(args.length() == 1); 7471 isolate->counters()->math_round()->Increment(); 7472 7473 if (!args[0]->IsHeapNumber()) { 7474 // Must be smi. Return the argument unchanged for all the other types 7475 // to make fuzz-natives test happy. 7476 return args[0]; 7477 } 7478 7479 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); 7480 7481 double value = number->value(); 7482 int exponent = number->get_exponent(); 7483 int sign = number->get_sign(); 7484 7485 if (exponent < -1) { 7486 // Number in range ]-0.5..0.5[. These always round to +/-zero. 7487 if (sign) return isolate->heap()->minus_zero_value(); 7488 return Smi::FromInt(0); 7489 } 7490 7491 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and 7492 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar 7493 // argument holds for 32-bit smis). 7494 if (!sign && exponent < kSmiValueSize - 2) { 7495 return Smi::FromInt(static_cast<int>(value + 0.5)); 7496 } 7497 7498 // If the magnitude is big enough, there's no place for fraction part. If we 7499 // try to add 0.5 to this number, 1.0 will be added instead. 7500 if (exponent >= 52) { 7501 return number; 7502 } 7503 7504 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); 7505 7506 // Do not call NumberFromDouble() to avoid extra checks. 7507 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5)); 7508 } 7509 7510 7511 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) { 7512 NoHandleAllocation ha; 7513 ASSERT(args.length() == 1); 7514 isolate->counters()->math_sin()->Increment(); 7515 7516 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7517 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x); 7518 } 7519 7520 7521 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { 7522 NoHandleAllocation ha; 7523 ASSERT(args.length() == 1); 7524 isolate->counters()->math_sqrt()->Increment(); 7525 7526 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7527 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x)); 7528 } 7529 7530 7531 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { 7532 NoHandleAllocation ha; 7533 ASSERT(args.length() == 1); 7534 isolate->counters()->math_tan()->Increment(); 7535 7536 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7537 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x); 7538 } 7539 7540 7541 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { 7542 NoHandleAllocation ha; 7543 ASSERT(args.length() == 2); 7544 7545 CONVERT_SMI_ARG_CHECKED(year, 0); 7546 CONVERT_SMI_ARG_CHECKED(month, 1); 7547 7548 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month)); 7549 } 7550 7551 7552 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { 7553 HandleScope scope(isolate); 7554 ASSERT(args.length() == 3); 7555 7556 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); 7557 CONVERT_DOUBLE_ARG_CHECKED(time, 1); 7558 CONVERT_SMI_ARG_CHECKED(is_utc, 2); 7559 7560 DateCache* date_cache = isolate->date_cache(); 7561 7562 Object* value = NULL; 7563 bool is_value_nan = false; 7564 if (isnan(time)) { 7565 value = isolate->heap()->nan_value(); 7566 is_value_nan = true; 7567 } else if (!is_utc && 7568 (time < -DateCache::kMaxTimeBeforeUTCInMs || 7569 time > DateCache::kMaxTimeBeforeUTCInMs)) { 7570 value = isolate->heap()->nan_value(); 7571 is_value_nan = true; 7572 } else { 7573 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); 7574 if (time < -DateCache::kMaxTimeInMs || 7575 time > DateCache::kMaxTimeInMs) { 7576 value = isolate->heap()->nan_value(); 7577 is_value_nan = true; 7578 } else { 7579 MaybeObject* maybe_result = 7580 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time)); 7581 if (!maybe_result->ToObject(&value)) return maybe_result; 7582 } 7583 } 7584 date->SetValue(value, is_value_nan); 7585 return value; 7586 } 7587 7588 7589 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { 7590 HandleScope scope(isolate); 7591 ASSERT(args.length() == 3); 7592 7593 Handle<JSFunction> callee = args.at<JSFunction>(0); 7594 Object** parameters = reinterpret_cast<Object**>(args[1]); 7595 const int argument_count = Smi::cast(args[2])->value(); 7596 7597 Handle<JSObject> result = 7598 isolate->factory()->NewArgumentsObject(callee, argument_count); 7599 // Allocate the elements if needed. 7600 int parameter_count = callee->shared()->formal_parameter_count(); 7601 if (argument_count > 0) { 7602 if (parameter_count > 0) { 7603 int mapped_count = Min(argument_count, parameter_count); 7604 Handle<FixedArray> parameter_map = 7605 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); 7606 parameter_map->set_map( 7607 isolate->heap()->non_strict_arguments_elements_map()); 7608 7609 Handle<Map> old_map(result->map()); 7610 Handle<Map> new_map = 7611 isolate->factory()->CopyMapDropTransitions(old_map); 7612 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); 7613 7614 result->set_map(*new_map); 7615 result->set_elements(*parameter_map); 7616 7617 // Store the context and the arguments array at the beginning of the 7618 // parameter map. 7619 Handle<Context> context(isolate->context()); 7620 Handle<FixedArray> arguments = 7621 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 7622 parameter_map->set(0, *context); 7623 parameter_map->set(1, *arguments); 7624 7625 // Loop over the actual parameters backwards. 7626 int index = argument_count - 1; 7627 while (index >= mapped_count) { 7628 // These go directly in the arguments array and have no 7629 // corresponding slot in the parameter map. 7630 arguments->set(index, *(parameters - index - 1)); 7631 --index; 7632 } 7633 7634 Handle<ScopeInfo> scope_info(callee->shared()->scope_info()); 7635 while (index >= 0) { 7636 // Detect duplicate names to the right in the parameter list. 7637 Handle<String> name(scope_info->ParameterName(index)); 7638 int context_local_count = scope_info->ContextLocalCount(); 7639 bool duplicate = false; 7640 for (int j = index + 1; j < parameter_count; ++j) { 7641 if (scope_info->ParameterName(j) == *name) { 7642 duplicate = true; 7643 break; 7644 } 7645 } 7646 7647 if (duplicate) { 7648 // This goes directly in the arguments array with a hole in the 7649 // parameter map. 7650 arguments->set(index, *(parameters - index - 1)); 7651 parameter_map->set_the_hole(index + 2); 7652 } else { 7653 // The context index goes in the parameter map with a hole in the 7654 // arguments array. 7655 int context_index = -1; 7656 for (int j = 0; j < context_local_count; ++j) { 7657 if (scope_info->ContextLocalName(j) == *name) { 7658 context_index = j; 7659 break; 7660 } 7661 } 7662 ASSERT(context_index >= 0); 7663 arguments->set_the_hole(index); 7664 parameter_map->set(index + 2, Smi::FromInt( 7665 Context::MIN_CONTEXT_SLOTS + context_index)); 7666 } 7667 7668 --index; 7669 } 7670 } else { 7671 // If there is no aliasing, the arguments object elements are not 7672 // special in any way. 7673 Handle<FixedArray> elements = 7674 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 7675 result->set_elements(*elements); 7676 for (int i = 0; i < argument_count; ++i) { 7677 elements->set(i, *(parameters - i - 1)); 7678 } 7679 } 7680 } 7681 return *result; 7682 } 7683 7684 7685 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) { 7686 NoHandleAllocation ha; 7687 ASSERT(args.length() == 3); 7688 7689 JSFunction* callee = JSFunction::cast(args[0]); 7690 Object** parameters = reinterpret_cast<Object**>(args[1]); 7691 const int length = args.smi_at(2); 7692 7693 Object* result; 7694 { MaybeObject* maybe_result = 7695 isolate->heap()->AllocateArgumentsObject(callee, length); 7696 if (!maybe_result->ToObject(&result)) return maybe_result; 7697 } 7698 // Allocate the elements if needed. 7699 if (length > 0) { 7700 // Allocate the fixed array. 7701 Object* obj; 7702 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length); 7703 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7704 } 7705 7706 AssertNoAllocation no_gc; 7707 FixedArray* array = reinterpret_cast<FixedArray*>(obj); 7708 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map()); 7709 array->set_length(length); 7710 7711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 7712 for (int i = 0; i < length; i++) { 7713 array->set(i, *--parameters, mode); 7714 } 7715 JSObject::cast(result)->set_elements(FixedArray::cast(obj)); 7716 } 7717 return result; 7718 } 7719 7720 7721 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { 7722 HandleScope scope(isolate); 7723 ASSERT(args.length() == 3); 7724 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 7725 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1); 7726 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2); 7727 7728 // The caller ensures that we pretenure closures that are assigned 7729 // directly to properties. 7730 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 7731 Handle<JSFunction> result = 7732 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 7733 context, 7734 pretenure_flag); 7735 return *result; 7736 } 7737 7738 7739 // Find the arguments of the JavaScript function invocation that called 7740 // into C++ code. Collect these in a newly allocated array of handles (possibly 7741 // prefixed by a number of empty handles). 7742 static SmartArrayPointer<Handle<Object> > GetCallerArguments( 7743 int prefix_argc, 7744 int* total_argc) { 7745 // Find frame containing arguments passed to the caller. 7746 JavaScriptFrameIterator it; 7747 JavaScriptFrame* frame = it.frame(); 7748 List<JSFunction*> functions(2); 7749 frame->GetFunctions(&functions); 7750 if (functions.length() > 1) { 7751 int inlined_jsframe_index = functions.length() - 1; 7752 JSFunction* inlined_function = functions[inlined_jsframe_index]; 7753 Vector<SlotRef> args_slots = 7754 SlotRef::ComputeSlotMappingForArguments( 7755 frame, 7756 inlined_jsframe_index, 7757 inlined_function->shared()->formal_parameter_count()); 7758 7759 int args_count = args_slots.length(); 7760 7761 *total_argc = prefix_argc + args_count; 7762 SmartArrayPointer<Handle<Object> > param_data( 7763 NewArray<Handle<Object> >(*total_argc)); 7764 for (int i = 0; i < args_count; i++) { 7765 Handle<Object> val = args_slots[i].GetValue(); 7766 param_data[prefix_argc + i] = val; 7767 } 7768 7769 args_slots.Dispose(); 7770 7771 return param_data; 7772 } else { 7773 it.AdvanceToArgumentsFrame(); 7774 frame = it.frame(); 7775 int args_count = frame->ComputeParametersCount(); 7776 7777 *total_argc = prefix_argc + args_count; 7778 SmartArrayPointer<Handle<Object> > param_data( 7779 NewArray<Handle<Object> >(*total_argc)); 7780 for (int i = 0; i < args_count; i++) { 7781 Handle<Object> val = Handle<Object>(frame->GetParameter(i)); 7782 param_data[prefix_argc + i] = val; 7783 } 7784 return param_data; 7785 } 7786 } 7787 7788 7789 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { 7790 HandleScope scope(isolate); 7791 ASSERT(args.length() == 4); 7792 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); 7793 RUNTIME_ASSERT(args[3]->IsNumber()); 7794 Handle<Object> bindee = args.at<Object>(1); 7795 7796 // TODO(lrn): Create bound function in C++ code from premade shared info. 7797 bound_function->shared()->set_bound(true); 7798 // Get all arguments of calling function (Function.prototype.bind). 7799 int argc = 0; 7800 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc); 7801 // Don't count the this-arg. 7802 if (argc > 0) { 7803 ASSERT(*arguments[0] == args[2]); 7804 argc--; 7805 } else { 7806 ASSERT(args[2]->IsUndefined()); 7807 } 7808 // Initialize array of bindings (function, this, and any existing arguments 7809 // if the function was already bound). 7810 Handle<FixedArray> new_bindings; 7811 int i; 7812 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { 7813 Handle<FixedArray> old_bindings( 7814 JSFunction::cast(*bindee)->function_bindings()); 7815 new_bindings = 7816 isolate->factory()->NewFixedArray(old_bindings->length() + argc); 7817 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex)); 7818 i = 0; 7819 for (int n = old_bindings->length(); i < n; i++) { 7820 new_bindings->set(i, old_bindings->get(i)); 7821 } 7822 } else { 7823 int array_size = JSFunction::kBoundArgumentsStartIndex + argc; 7824 new_bindings = isolate->factory()->NewFixedArray(array_size); 7825 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); 7826 new_bindings->set(JSFunction::kBoundThisIndex, args[2]); 7827 i = 2; 7828 } 7829 // Copy arguments, skipping the first which is "this_arg". 7830 for (int j = 0; j < argc; j++, i++) { 7831 new_bindings->set(i, *arguments[j + 1]); 7832 } 7833 new_bindings->set_map_no_write_barrier( 7834 isolate->heap()->fixed_cow_array_map()); 7835 bound_function->set_function_bindings(*new_bindings); 7836 7837 // Update length. 7838 Handle<String> length_symbol = isolate->factory()->length_symbol(); 7839 Handle<Object> new_length(args.at<Object>(3)); 7840 PropertyAttributes attr = 7841 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); 7842 ForceSetProperty(bound_function, length_symbol, new_length, attr); 7843 return *bound_function; 7844 } 7845 7846 7847 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { 7848 HandleScope handles(isolate); 7849 ASSERT(args.length() == 1); 7850 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); 7851 if (callable->IsJSFunction()) { 7852 Handle<JSFunction> function = Handle<JSFunction>::cast(callable); 7853 if (function->shared()->bound()) { 7854 Handle<FixedArray> bindings(function->function_bindings()); 7855 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); 7856 return *isolate->factory()->NewJSArrayWithElements(bindings); 7857 } 7858 } 7859 return isolate->heap()->undefined_value(); 7860 } 7861 7862 7863 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { 7864 HandleScope scope(isolate); 7865 ASSERT(args.length() == 1); 7866 // First argument is a function to use as a constructor. 7867 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 7868 RUNTIME_ASSERT(function->shared()->bound()); 7869 7870 // The argument is a bound function. Extract its bound arguments 7871 // and callable. 7872 Handle<FixedArray> bound_args = 7873 Handle<FixedArray>(FixedArray::cast(function->function_bindings())); 7874 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; 7875 Handle<Object> bound_function( 7876 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex))); 7877 ASSERT(!bound_function->IsJSFunction() || 7878 !Handle<JSFunction>::cast(bound_function)->shared()->bound()); 7879 7880 int total_argc = 0; 7881 SmartArrayPointer<Handle<Object> > param_data = 7882 GetCallerArguments(bound_argc, &total_argc); 7883 for (int i = 0; i < bound_argc; i++) { 7884 param_data[i] = Handle<Object>(bound_args->get( 7885 JSFunction::kBoundArgumentsStartIndex + i)); 7886 } 7887 7888 if (!bound_function->IsJSFunction()) { 7889 bool exception_thrown; 7890 bound_function = Execution::TryGetConstructorDelegate(bound_function, 7891 &exception_thrown); 7892 if (exception_thrown) return Failure::Exception(); 7893 } 7894 ASSERT(bound_function->IsJSFunction()); 7895 7896 bool exception = false; 7897 Handle<Object> result = 7898 Execution::New(Handle<JSFunction>::cast(bound_function), 7899 total_argc, *param_data, &exception); 7900 if (exception) { 7901 return Failure::Exception(); 7902 } 7903 ASSERT(!result.is_null()); 7904 return *result; 7905 } 7906 7907 7908 static void TrySettingInlineConstructStub(Isolate* isolate, 7909 Handle<JSFunction> function) { 7910 Handle<Object> prototype = isolate->factory()->null_value(); 7911 if (function->has_instance_prototype()) { 7912 prototype = Handle<Object>(function->instance_prototype(), isolate); 7913 } 7914 if (function->shared()->CanGenerateInlineConstructor(*prototype)) { 7915 ConstructStubCompiler compiler(isolate); 7916 Handle<Code> code = compiler.CompileConstructStub(function); 7917 function->shared()->set_construct_stub(*code); 7918 } 7919 } 7920 7921 7922 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { 7923 HandleScope scope(isolate); 7924 ASSERT(args.length() == 1); 7925 7926 Handle<Object> constructor = args.at<Object>(0); 7927 7928 // If the constructor isn't a proper function we throw a type error. 7929 if (!constructor->IsJSFunction()) { 7930 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 7931 Handle<Object> type_error = 7932 isolate->factory()->NewTypeError("not_constructor", arguments); 7933 return isolate->Throw(*type_error); 7934 } 7935 7936 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 7937 7938 // If function should not have prototype, construction is not allowed. In this 7939 // case generated code bailouts here, since function has no initial_map. 7940 if (!function->should_have_prototype() && !function->shared()->bound()) { 7941 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 7942 Handle<Object> type_error = 7943 isolate->factory()->NewTypeError("not_constructor", arguments); 7944 return isolate->Throw(*type_error); 7945 } 7946 7947 #ifdef ENABLE_DEBUGGER_SUPPORT 7948 Debug* debug = isolate->debug(); 7949 // Handle stepping into constructors if step into is active. 7950 if (debug->StepInActive()) { 7951 debug->HandleStepIn(function, Handle<Object>::null(), 0, true); 7952 } 7953 #endif 7954 7955 if (function->has_initial_map()) { 7956 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 7957 // The 'Function' function ignores the receiver object when 7958 // called using 'new' and creates a new JSFunction object that 7959 // is returned. The receiver object is only used for error 7960 // reporting if an error occurs when constructing the new 7961 // JSFunction. FACTORY->NewJSObject() should not be used to 7962 // allocate JSFunctions since it does not properly initialize 7963 // the shared part of the function. Since the receiver is 7964 // ignored anyway, we use the global object as the receiver 7965 // instead of a new JSFunction object. This way, errors are 7966 // reported the same way whether or not 'Function' is called 7967 // using 'new'. 7968 return isolate->context()->global(); 7969 } 7970 } 7971 7972 // The function should be compiled for the optimization hints to be 7973 // available. We cannot use EnsureCompiled because that forces a 7974 // compilation through the shared function info which makes it 7975 // impossible for us to optimize. 7976 if (!function->is_compiled()) { 7977 JSFunction::CompileLazy(function, CLEAR_EXCEPTION); 7978 } 7979 7980 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 7981 if (!function->has_initial_map() && 7982 shared->IsInobjectSlackTrackingInProgress()) { 7983 // The tracking is already in progress for another function. We can only 7984 // track one initial_map at a time, so we force the completion before the 7985 // function is called as a constructor for the first time. 7986 shared->CompleteInobjectSlackTracking(); 7987 } 7988 7989 bool first_allocation = !shared->live_objects_may_exist(); 7990 Handle<JSObject> result = isolate->factory()->NewJSObject(function); 7991 RETURN_IF_EMPTY_HANDLE(isolate, result); 7992 // Delay setting the stub if inobject slack tracking is in progress. 7993 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) { 7994 TrySettingInlineConstructStub(isolate, function); 7995 } 7996 7997 isolate->counters()->constructed_objects()->Increment(); 7998 isolate->counters()->constructed_objects_runtime()->Increment(); 7999 8000 return *result; 8001 } 8002 8003 8004 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { 8005 HandleScope scope(isolate); 8006 ASSERT(args.length() == 1); 8007 8008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8009 function->shared()->CompleteInobjectSlackTracking(); 8010 TrySettingInlineConstructStub(isolate, function); 8011 8012 return isolate->heap()->undefined_value(); 8013 } 8014 8015 8016 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { 8017 HandleScope scope(isolate); 8018 ASSERT(args.length() == 1); 8019 8020 Handle<JSFunction> function = args.at<JSFunction>(0); 8021 #ifdef DEBUG 8022 if (FLAG_trace_lazy && !function->shared()->is_compiled()) { 8023 PrintF("[lazy: "); 8024 function->PrintName(); 8025 PrintF("]\n"); 8026 } 8027 #endif 8028 8029 // Compile the target function. 8030 ASSERT(!function->is_compiled()); 8031 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) { 8032 return Failure::Exception(); 8033 } 8034 8035 // All done. Return the compiled code. 8036 ASSERT(function->is_compiled()); 8037 return function->code(); 8038 } 8039 8040 8041 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { 8042 HandleScope scope(isolate); 8043 ASSERT(args.length() == 1); 8044 Handle<JSFunction> function = args.at<JSFunction>(0); 8045 8046 // If the function is not compiled ignore the lazy 8047 // recompilation. This can happen if the debugger is activated and 8048 // the function is returned to the not compiled state. 8049 if (!function->shared()->is_compiled()) { 8050 function->ReplaceCode(function->shared()->code()); 8051 return function->code(); 8052 } 8053 8054 // If the function is not optimizable or debugger is active continue using the 8055 // code from the full compiler. 8056 if (!function->shared()->code()->optimizable() || 8057 isolate->DebuggerHasBreakPoints()) { 8058 if (FLAG_trace_opt) { 8059 PrintF("[failed to optimize "); 8060 function->PrintName(); 8061 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", 8062 function->shared()->code()->optimizable() ? "T" : "F", 8063 isolate->DebuggerHasBreakPoints() ? "T" : "F"); 8064 } 8065 function->ReplaceCode(function->shared()->code()); 8066 return function->code(); 8067 } 8068 function->shared()->code()->set_profiler_ticks(0); 8069 if (JSFunction::CompileOptimized(function, 8070 AstNode::kNoNumber, 8071 CLEAR_EXCEPTION)) { 8072 return function->code(); 8073 } 8074 if (FLAG_trace_opt) { 8075 PrintF("[failed to optimize "); 8076 function->PrintName(); 8077 PrintF(": optimized compilation failed]\n"); 8078 } 8079 function->ReplaceCode(function->shared()->code()); 8080 return function->code(); 8081 } 8082 8083 8084 class ActivationsFinder : public ThreadVisitor { 8085 public: 8086 explicit ActivationsFinder(JSFunction* function) 8087 : function_(function), has_activations_(false) {} 8088 8089 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 8090 if (has_activations_) return; 8091 8092 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { 8093 JavaScriptFrame* frame = it.frame(); 8094 if (frame->is_optimized() && frame->function() == function_) { 8095 has_activations_ = true; 8096 return; 8097 } 8098 } 8099 } 8100 8101 bool has_activations() { return has_activations_; } 8102 8103 private: 8104 JSFunction* function_; 8105 bool has_activations_; 8106 }; 8107 8108 8109 static void MaterializeArgumentsObjectInFrame(Isolate* isolate, 8110 JavaScriptFrame* frame) { 8111 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); 8112 Handle<Object> arguments; 8113 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) { 8114 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) { 8115 if (arguments.is_null()) { 8116 // FunctionGetArguments can't throw an exception, so cast away the 8117 // doubt with an assert. 8118 arguments = Handle<Object>( 8119 Accessors::FunctionGetArguments(*function, 8120 NULL)->ToObjectUnchecked()); 8121 ASSERT(*arguments != isolate->heap()->null_value()); 8122 ASSERT(*arguments != isolate->heap()->undefined_value()); 8123 } 8124 frame->SetExpression(i, *arguments); 8125 } 8126 } 8127 } 8128 8129 8130 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { 8131 HandleScope scope(isolate); 8132 ASSERT(args.length() == 1); 8133 RUNTIME_ASSERT(args[0]->IsSmi()); 8134 Deoptimizer::BailoutType type = 8135 static_cast<Deoptimizer::BailoutType>(args.smi_at(0)); 8136 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8137 ASSERT(isolate->heap()->IsAllocationAllowed()); 8138 int jsframes = deoptimizer->jsframe_count(); 8139 8140 deoptimizer->MaterializeHeapNumbers(); 8141 delete deoptimizer; 8142 8143 JavaScriptFrameIterator it(isolate); 8144 for (int i = 0; i < jsframes - 1; i++) { 8145 MaterializeArgumentsObjectInFrame(isolate, it.frame()); 8146 it.Advance(); 8147 } 8148 8149 JavaScriptFrame* frame = it.frame(); 8150 RUNTIME_ASSERT(frame->function()->IsJSFunction()); 8151 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate); 8152 MaterializeArgumentsObjectInFrame(isolate, frame); 8153 8154 if (type == Deoptimizer::EAGER) { 8155 RUNTIME_ASSERT(function->IsOptimized()); 8156 } 8157 8158 // Avoid doing too much work when running with --always-opt and keep 8159 // the optimized code around. 8160 if (FLAG_always_opt || type == Deoptimizer::LAZY) { 8161 return isolate->heap()->undefined_value(); 8162 } 8163 8164 // Find other optimized activations of the function. 8165 bool has_other_activations = false; 8166 while (!it.done()) { 8167 JavaScriptFrame* frame = it.frame(); 8168 if (frame->is_optimized() && frame->function() == *function) { 8169 has_other_activations = true; 8170 break; 8171 } 8172 it.Advance(); 8173 } 8174 8175 if (!has_other_activations) { 8176 ActivationsFinder activations_finder(*function); 8177 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); 8178 has_other_activations = activations_finder.has_activations(); 8179 } 8180 8181 if (!has_other_activations) { 8182 if (FLAG_trace_deopt) { 8183 PrintF("[removing optimized code for: "); 8184 function->PrintName(); 8185 PrintF("]\n"); 8186 } 8187 function->ReplaceCode(function->shared()->code()); 8188 } else { 8189 Deoptimizer::DeoptimizeFunction(*function); 8190 } 8191 return isolate->heap()->undefined_value(); 8192 } 8193 8194 8195 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) { 8196 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8197 delete deoptimizer; 8198 return isolate->heap()->undefined_value(); 8199 } 8200 8201 8202 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { 8203 HandleScope scope(isolate); 8204 ASSERT(args.length() == 1); 8205 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8206 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 8207 8208 Deoptimizer::DeoptimizeFunction(*function); 8209 8210 return isolate->heap()->undefined_value(); 8211 } 8212 8213 8214 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { 8215 #if defined(USE_SIMULATOR) 8216 return isolate->heap()->true_value(); 8217 #else 8218 return isolate->heap()->false_value(); 8219 #endif 8220 } 8221 8222 8223 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { 8224 HandleScope scope(isolate); 8225 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8226 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8227 8228 if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); 8229 function->MarkForLazyRecompilation(); 8230 8231 Code* unoptimized = function->shared()->code(); 8232 if (args.length() == 2 && 8233 unoptimized->kind() == Code::FUNCTION) { 8234 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 8235 CHECK(type->IsEqualTo(CStrVector("osr"))); 8236 isolate->runtime_profiler()->AttemptOnStackReplacement(*function); 8237 unoptimized->set_allow_osr_at_loop_nesting_level( 8238 Code::kMaxLoopNestingMarker); 8239 } 8240 8241 return isolate->heap()->undefined_value(); 8242 } 8243 8244 8245 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { 8246 HandleScope scope(isolate); 8247 ASSERT(args.length() == 1); 8248 // The least significant bit (after untagging) indicates whether the 8249 // function is currently optimized, regardless of reason. 8250 if (!V8::UseCrankshaft()) { 8251 return Smi::FromInt(4); // 4 == "never". 8252 } 8253 if (FLAG_always_opt) { 8254 return Smi::FromInt(3); // 3 == "always". 8255 } 8256 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8257 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". 8258 : Smi::FromInt(2); // 2 == "no". 8259 } 8260 8261 8262 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { 8263 HandleScope scope(isolate); 8264 ASSERT(args.length() == 1); 8265 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8266 return Smi::FromInt(function->shared()->opt_count()); 8267 } 8268 8269 8270 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { 8271 HandleScope scope(isolate); 8272 ASSERT(args.length() == 1); 8273 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8274 8275 // We're not prepared to handle a function with arguments object. 8276 ASSERT(!function->shared()->uses_arguments()); 8277 8278 // We have hit a back edge in an unoptimized frame for a function that was 8279 // selected for on-stack replacement. Find the unoptimized code object. 8280 Handle<Code> unoptimized(function->shared()->code(), isolate); 8281 // Keep track of whether we've succeeded in optimizing. 8282 bool succeeded = unoptimized->optimizable(); 8283 if (succeeded) { 8284 // If we are trying to do OSR when there are already optimized 8285 // activations of the function, it means (a) the function is directly or 8286 // indirectly recursive and (b) an optimized invocation has been 8287 // deoptimized so that we are currently in an unoptimized activation. 8288 // Check for optimized activations of this function. 8289 JavaScriptFrameIterator it(isolate); 8290 while (succeeded && !it.done()) { 8291 JavaScriptFrame* frame = it.frame(); 8292 succeeded = !frame->is_optimized() || frame->function() != *function; 8293 it.Advance(); 8294 } 8295 } 8296 8297 int ast_id = AstNode::kNoNumber; 8298 if (succeeded) { 8299 // The top JS function is this one, the PC is somewhere in the 8300 // unoptimized code. 8301 JavaScriptFrameIterator it(isolate); 8302 JavaScriptFrame* frame = it.frame(); 8303 ASSERT(frame->function() == *function); 8304 ASSERT(frame->LookupCode() == *unoptimized); 8305 ASSERT(unoptimized->contains(frame->pc())); 8306 8307 // Use linear search of the unoptimized code's stack check table to find 8308 // the AST id matching the PC. 8309 Address start = unoptimized->instruction_start(); 8310 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start); 8311 Address table_cursor = start + unoptimized->stack_check_table_offset(); 8312 uint32_t table_length = Memory::uint32_at(table_cursor); 8313 table_cursor += kIntSize; 8314 for (unsigned i = 0; i < table_length; ++i) { 8315 // Table entries are (AST id, pc offset) pairs. 8316 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize); 8317 if (pc_offset == target_pc_offset) { 8318 ast_id = static_cast<int>(Memory::uint32_at(table_cursor)); 8319 break; 8320 } 8321 table_cursor += 2 * kIntSize; 8322 } 8323 ASSERT(ast_id != AstNode::kNoNumber); 8324 if (FLAG_trace_osr) { 8325 PrintF("[replacing on-stack at AST id %d in ", ast_id); 8326 function->PrintName(); 8327 PrintF("]\n"); 8328 } 8329 8330 // Try to compile the optimized code. A true return value from 8331 // CompileOptimized means that compilation succeeded, not necessarily 8332 // that optimization succeeded. 8333 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) && 8334 function->IsOptimized()) { 8335 DeoptimizationInputData* data = DeoptimizationInputData::cast( 8336 function->code()->deoptimization_data()); 8337 if (data->OsrPcOffset()->value() >= 0) { 8338 if (FLAG_trace_osr) { 8339 PrintF("[on-stack replacement offset %d in optimized code]\n", 8340 data->OsrPcOffset()->value()); 8341 } 8342 ASSERT(data->OsrAstId()->value() == ast_id); 8343 } else { 8344 // We may never generate the desired OSR entry if we emit an 8345 // early deoptimize. 8346 succeeded = false; 8347 } 8348 } else { 8349 succeeded = false; 8350 } 8351 } 8352 8353 // Revert to the original stack checks in the original unoptimized code. 8354 if (FLAG_trace_osr) { 8355 PrintF("[restoring original stack checks in "); 8356 function->PrintName(); 8357 PrintF("]\n"); 8358 } 8359 Handle<Code> check_code; 8360 #if defined(V8_TARGET_ARCH_IA32) || \ 8361 defined(V8_TARGET_ARCH_ARM) || \ 8362 defined(V8_TARGET_ARCH_MIPS) 8363 if (FLAG_count_based_interrupts) { 8364 InterruptStub interrupt_stub; 8365 check_code = interrupt_stub.GetCode(); 8366 } else // NOLINT 8367 #endif 8368 { // NOLINT 8369 StackCheckStub check_stub; 8370 check_code = check_stub.GetCode(); 8371 } 8372 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement(); 8373 Deoptimizer::RevertStackCheckCode(*unoptimized, 8374 *check_code, 8375 *replacement_code); 8376 8377 // Allow OSR only at nesting level zero again. 8378 unoptimized->set_allow_osr_at_loop_nesting_level(0); 8379 8380 // If the optimization attempt succeeded, return the AST id tagged as a 8381 // smi. This tells the builtin that we need to translate the unoptimized 8382 // frame to an optimized one. 8383 if (succeeded) { 8384 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); 8385 return Smi::FromInt(ast_id); 8386 } else { 8387 if (function->IsMarkedForLazyRecompilation()) { 8388 function->ReplaceCode(function->shared()->code()); 8389 } 8390 return Smi::FromInt(-1); 8391 } 8392 } 8393 8394 8395 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { 8396 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8397 return isolate->heap()->undefined_value(); 8398 } 8399 8400 8401 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) { 8402 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8403 return isolate->heap()->nan_value(); 8404 } 8405 8406 8407 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { 8408 HandleScope scope(isolate); 8409 ASSERT(args.length() >= 2); 8410 int argc = args.length() - 2; 8411 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1); 8412 Object* receiver = args[0]; 8413 8414 // If there are too many arguments, allocate argv via malloc. 8415 const int argv_small_size = 10; 8416 Handle<Object> argv_small_buffer[argv_small_size]; 8417 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8418 Handle<Object>* argv = argv_small_buffer; 8419 if (argc > argv_small_size) { 8420 argv = new Handle<Object>[argc]; 8421 if (argv == NULL) return isolate->StackOverflow(); 8422 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8423 } 8424 8425 for (int i = 0; i < argc; ++i) { 8426 MaybeObject* maybe = args[1 + i]; 8427 Object* object; 8428 if (!maybe->To<Object>(&object)) return maybe; 8429 argv[i] = Handle<Object>(object); 8430 } 8431 8432 bool threw; 8433 Handle<JSReceiver> hfun(fun); 8434 Handle<Object> hreceiver(receiver); 8435 Handle<Object> result = 8436 Execution::Call(hfun, hreceiver, argc, argv, &threw, true); 8437 8438 if (threw) return Failure::Exception(); 8439 return *result; 8440 } 8441 8442 8443 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { 8444 HandleScope scope(isolate); 8445 ASSERT(args.length() == 5); 8446 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); 8447 Handle<Object> receiver = args.at<Object>(1); 8448 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); 8449 CONVERT_SMI_ARG_CHECKED(offset, 3); 8450 CONVERT_SMI_ARG_CHECKED(argc, 4); 8451 ASSERT(offset >= 0); 8452 ASSERT(argc >= 0); 8453 8454 // If there are too many arguments, allocate argv via malloc. 8455 const int argv_small_size = 10; 8456 Handle<Object> argv_small_buffer[argv_small_size]; 8457 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8458 Handle<Object>* argv = argv_small_buffer; 8459 if (argc > argv_small_size) { 8460 argv = new Handle<Object>[argc]; 8461 if (argv == NULL) return isolate->StackOverflow(); 8462 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8463 } 8464 8465 for (int i = 0; i < argc; ++i) { 8466 argv[i] = Object::GetElement(arguments, offset + i); 8467 } 8468 8469 bool threw; 8470 Handle<Object> result = 8471 Execution::Call(fun, receiver, argc, argv, &threw, true); 8472 8473 if (threw) return Failure::Exception(); 8474 return *result; 8475 } 8476 8477 8478 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { 8479 HandleScope scope(isolate); 8480 ASSERT(args.length() == 1); 8481 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8482 return *Execution::GetFunctionDelegate(args.at<Object>(0)); 8483 } 8484 8485 8486 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) { 8487 HandleScope scope(isolate); 8488 ASSERT(args.length() == 1); 8489 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8490 return *Execution::GetConstructorDelegate(args.at<Object>(0)); 8491 } 8492 8493 8494 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) { 8495 NoHandleAllocation ha; 8496 ASSERT(args.length() == 1); 8497 8498 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8499 int length = function->shared()->scope_info()->ContextLength(); 8500 Object* result; 8501 { MaybeObject* maybe_result = 8502 isolate->heap()->AllocateFunctionContext(length, function); 8503 if (!maybe_result->ToObject(&result)) return maybe_result; 8504 } 8505 8506 isolate->set_context(Context::cast(result)); 8507 8508 return result; // non-failure 8509 } 8510 8511 8512 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) { 8513 NoHandleAllocation ha; 8514 ASSERT(args.length() == 2); 8515 JSObject* extension_object; 8516 if (args[0]->IsJSObject()) { 8517 extension_object = JSObject::cast(args[0]); 8518 } else { 8519 // Convert the object to a proper JavaScript object. 8520 MaybeObject* maybe_js_object = args[0]->ToObject(); 8521 if (!maybe_js_object->To(&extension_object)) { 8522 if (Failure::cast(maybe_js_object)->IsInternalError()) { 8523 HandleScope scope(isolate); 8524 Handle<Object> handle = args.at<Object>(0); 8525 Handle<Object> result = 8526 isolate->factory()->NewTypeError("with_expression", 8527 HandleVector(&handle, 1)); 8528 return isolate->Throw(*result); 8529 } else { 8530 return maybe_js_object; 8531 } 8532 } 8533 } 8534 8535 JSFunction* function; 8536 if (args[1]->IsSmi()) { 8537 // A smi sentinel indicates a context nested inside global code rather 8538 // than some function. There is a canonical empty function that can be 8539 // gotten from the global context. 8540 function = isolate->context()->global_context()->closure(); 8541 } else { 8542 function = JSFunction::cast(args[1]); 8543 } 8544 8545 Context* context; 8546 MaybeObject* maybe_context = 8547 isolate->heap()->AllocateWithContext(function, 8548 isolate->context(), 8549 extension_object); 8550 if (!maybe_context->To(&context)) return maybe_context; 8551 isolate->set_context(context); 8552 return context; 8553 } 8554 8555 8556 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { 8557 NoHandleAllocation ha; 8558 ASSERT(args.length() == 3); 8559 String* name = String::cast(args[0]); 8560 Object* thrown_object = args[1]; 8561 JSFunction* function; 8562 if (args[2]->IsSmi()) { 8563 // A smi sentinel indicates a context nested inside global code rather 8564 // than some function. There is a canonical empty function that can be 8565 // gotten from the global context. 8566 function = isolate->context()->global_context()->closure(); 8567 } else { 8568 function = JSFunction::cast(args[2]); 8569 } 8570 Context* context; 8571 MaybeObject* maybe_context = 8572 isolate->heap()->AllocateCatchContext(function, 8573 isolate->context(), 8574 name, 8575 thrown_object); 8576 if (!maybe_context->To(&context)) return maybe_context; 8577 isolate->set_context(context); 8578 return context; 8579 } 8580 8581 8582 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { 8583 NoHandleAllocation ha; 8584 ASSERT(args.length() == 2); 8585 ScopeInfo* scope_info = ScopeInfo::cast(args[0]); 8586 JSFunction* function; 8587 if (args[1]->IsSmi()) { 8588 // A smi sentinel indicates a context nested inside global code rather 8589 // than some function. There is a canonical empty function that can be 8590 // gotten from the global context. 8591 function = isolate->context()->global_context()->closure(); 8592 } else { 8593 function = JSFunction::cast(args[1]); 8594 } 8595 Context* context; 8596 MaybeObject* maybe_context = 8597 isolate->heap()->AllocateBlockContext(function, 8598 isolate->context(), 8599 scope_info); 8600 if (!maybe_context->To(&context)) return maybe_context; 8601 isolate->set_context(context); 8602 return context; 8603 } 8604 8605 8606 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { 8607 HandleScope scope(isolate); 8608 ASSERT(args.length() == 2); 8609 8610 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 8611 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 8612 8613 int index; 8614 PropertyAttributes attributes; 8615 ContextLookupFlags flags = FOLLOW_CHAINS; 8616 BindingFlags binding_flags; 8617 Handle<Object> holder = context->Lookup(name, 8618 flags, 8619 &index, 8620 &attributes, 8621 &binding_flags); 8622 8623 // If the slot was not found the result is true. 8624 if (holder.is_null()) { 8625 return isolate->heap()->true_value(); 8626 } 8627 8628 // If the slot was found in a context, it should be DONT_DELETE. 8629 if (holder->IsContext()) { 8630 return isolate->heap()->false_value(); 8631 } 8632 8633 // The slot was found in a JSObject, either a context extension object, 8634 // the global object, or the subject of a with. Try to delete it 8635 // (respecting DONT_DELETE). 8636 Handle<JSObject> object = Handle<JSObject>::cast(holder); 8637 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION); 8638 } 8639 8640 8641 // A mechanism to return a pair of Object pointers in registers (if possible). 8642 // How this is achieved is calling convention-dependent. 8643 // All currently supported x86 compiles uses calling conventions that are cdecl 8644 // variants where a 64-bit value is returned in two 32-bit registers 8645 // (edx:eax on ia32, r1:r0 on ARM). 8646 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 8647 // In Win64 calling convention, a struct of two pointers is returned in memory, 8648 // allocated by the caller, and passed as a pointer in a hidden first parameter. 8649 #ifdef V8_HOST_ARCH_64_BIT 8650 struct ObjectPair { 8651 MaybeObject* x; 8652 MaybeObject* y; 8653 }; 8654 8655 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 8656 ObjectPair result = {x, y}; 8657 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 8658 // In Win64 they are assigned to a hidden first argument. 8659 return result; 8660 } 8661 #else 8662 typedef uint64_t ObjectPair; 8663 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 8664 return reinterpret_cast<uint32_t>(x) | 8665 (reinterpret_cast<ObjectPair>(y) << 32); 8666 } 8667 #endif 8668 8669 8670 static inline MaybeObject* Unhole(Heap* heap, 8671 MaybeObject* x, 8672 PropertyAttributes attributes) { 8673 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 8674 USE(attributes); 8675 return x->IsTheHole() ? heap->undefined_value() : x; 8676 } 8677 8678 8679 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, 8680 JSObject* holder) { 8681 ASSERT(!holder->IsGlobalObject()); 8682 Context* top = isolate->context(); 8683 // Get the context extension function. 8684 JSFunction* context_extension_function = 8685 top->global_context()->context_extension_function(); 8686 // If the holder isn't a context extension object, we just return it 8687 // as the receiver. This allows arguments objects to be used as 8688 // receivers, but only if they are put in the context scope chain 8689 // explicitly via a with-statement. 8690 Object* constructor = holder->map()->constructor(); 8691 if (constructor != context_extension_function) return holder; 8692 // Fall back to using the global object as the implicit receiver if 8693 // the property turns out to be a local variable allocated in a 8694 // context extension object - introduced via eval. Implicit global 8695 // receivers are indicated with the hole value. 8696 return isolate->heap()->the_hole_value(); 8697 } 8698 8699 8700 static ObjectPair LoadContextSlotHelper(Arguments args, 8701 Isolate* isolate, 8702 bool throw_error) { 8703 HandleScope scope(isolate); 8704 ASSERT_EQ(2, args.length()); 8705 8706 if (!args[0]->IsContext() || !args[1]->IsString()) { 8707 return MakePair(isolate->ThrowIllegalOperation(), NULL); 8708 } 8709 Handle<Context> context = args.at<Context>(0); 8710 Handle<String> name = args.at<String>(1); 8711 8712 int index; 8713 PropertyAttributes attributes; 8714 ContextLookupFlags flags = FOLLOW_CHAINS; 8715 BindingFlags binding_flags; 8716 Handle<Object> holder = context->Lookup(name, 8717 flags, 8718 &index, 8719 &attributes, 8720 &binding_flags); 8721 8722 // If the index is non-negative, the slot has been found in a context. 8723 if (index >= 0) { 8724 ASSERT(holder->IsContext()); 8725 // If the "property" we were looking for is a local variable, the 8726 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. 8727 // 8728 // Use the hole as the receiver to signal that the receiver is implicit 8729 // and that the global receiver should be used (as distinguished from an 8730 // explicit receiver that happens to be a global object). 8731 Handle<Object> receiver = isolate->factory()->the_hole_value(); 8732 Object* value = Context::cast(*holder)->get(index); 8733 // Check for uninitialized bindings. 8734 switch (binding_flags) { 8735 case MUTABLE_CHECK_INITIALIZED: 8736 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: 8737 if (value->IsTheHole()) { 8738 Handle<Object> reference_error = 8739 isolate->factory()->NewReferenceError("not_defined", 8740 HandleVector(&name, 1)); 8741 return MakePair(isolate->Throw(*reference_error), NULL); 8742 } 8743 // FALLTHROUGH 8744 case MUTABLE_IS_INITIALIZED: 8745 case IMMUTABLE_IS_INITIALIZED: 8746 case IMMUTABLE_IS_INITIALIZED_HARMONY: 8747 ASSERT(!value->IsTheHole()); 8748 return MakePair(value, *receiver); 8749 case IMMUTABLE_CHECK_INITIALIZED: 8750 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); 8751 case MISSING_BINDING: 8752 UNREACHABLE(); 8753 return MakePair(NULL, NULL); 8754 } 8755 } 8756 8757 // Otherwise, if the slot was found the holder is a context extension 8758 // object, subject of a with, or a global object. We read the named 8759 // property from it. 8760 if (!holder.is_null()) { 8761 Handle<JSObject> object = Handle<JSObject>::cast(holder); 8762 ASSERT(object->HasProperty(*name)); 8763 // GetProperty below can cause GC. 8764 Handle<Object> receiver_handle(object->IsGlobalObject() 8765 ? GlobalObject::cast(*object)->global_receiver() 8766 : ComputeReceiverForNonGlobal(isolate, *object)); 8767 8768 // No need to unhole the value here. This is taken care of by the 8769 // GetProperty function. 8770 MaybeObject* value = object->GetProperty(*name); 8771 return MakePair(value, *receiver_handle); 8772 } 8773 8774 if (throw_error) { 8775 // The property doesn't exist - throw exception. 8776 Handle<Object> reference_error = 8777 isolate->factory()->NewReferenceError("not_defined", 8778 HandleVector(&name, 1)); 8779 return MakePair(isolate->Throw(*reference_error), NULL); 8780 } else { 8781 // The property doesn't exist - return undefined. 8782 return MakePair(isolate->heap()->undefined_value(), 8783 isolate->heap()->undefined_value()); 8784 } 8785 } 8786 8787 8788 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) { 8789 return LoadContextSlotHelper(args, isolate, true); 8790 } 8791 8792 8793 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) { 8794 return LoadContextSlotHelper(args, isolate, false); 8795 } 8796 8797 8798 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { 8799 HandleScope scope(isolate); 8800 ASSERT(args.length() == 4); 8801 8802 Handle<Object> value(args[0], isolate); 8803 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); 8804 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); 8805 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 8806 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE) 8807 ? kNonStrictMode : kStrictMode; 8808 8809 int index; 8810 PropertyAttributes attributes; 8811 ContextLookupFlags flags = FOLLOW_CHAINS; 8812 BindingFlags binding_flags; 8813 Handle<Object> holder = context->Lookup(name, 8814 flags, 8815 &index, 8816 &attributes, 8817 &binding_flags); 8818 8819 if (index >= 0) { 8820 // The property was found in a context slot. 8821 Handle<Context> context = Handle<Context>::cast(holder); 8822 if (binding_flags == MUTABLE_CHECK_INITIALIZED && 8823 context->get(index)->IsTheHole()) { 8824 Handle<Object> error = 8825 isolate->factory()->NewReferenceError("not_defined", 8826 HandleVector(&name, 1)); 8827 return isolate->Throw(*error); 8828 } 8829 // Ignore if read_only variable. 8830 if ((attributes & READ_ONLY) == 0) { 8831 // Context is a fixed array and set cannot fail. 8832 context->set(index, *value); 8833 } else if (strict_mode == kStrictMode) { 8834 // Setting read only property in strict mode. 8835 Handle<Object> error = 8836 isolate->factory()->NewTypeError("strict_cannot_assign", 8837 HandleVector(&name, 1)); 8838 return isolate->Throw(*error); 8839 } 8840 return *value; 8841 } 8842 8843 // Slow case: The property is not in a context slot. It is either in a 8844 // context extension object, a property of the subject of a with, or a 8845 // property of the global object. 8846 Handle<JSObject> object; 8847 8848 if (!holder.is_null()) { 8849 // The property exists on the holder. 8850 object = Handle<JSObject>::cast(holder); 8851 } else { 8852 // The property was not found. 8853 ASSERT(attributes == ABSENT); 8854 8855 if (strict_mode == kStrictMode) { 8856 // Throw in strict mode (assignment to undefined variable). 8857 Handle<Object> error = 8858 isolate->factory()->NewReferenceError( 8859 "not_defined", HandleVector(&name, 1)); 8860 return isolate->Throw(*error); 8861 } 8862 // In non-strict mode, the property is added to the global object. 8863 attributes = NONE; 8864 object = Handle<JSObject>(isolate->context()->global()); 8865 } 8866 8867 // Set the property if it's not read only or doesn't yet exist. 8868 if ((attributes & READ_ONLY) == 0 || 8869 (object->GetLocalPropertyAttribute(*name) == ABSENT)) { 8870 RETURN_IF_EMPTY_HANDLE( 8871 isolate, 8872 JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); 8873 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { 8874 // Setting read only property in strict mode. 8875 Handle<Object> error = 8876 isolate->factory()->NewTypeError( 8877 "strict_cannot_assign", HandleVector(&name, 1)); 8878 return isolate->Throw(*error); 8879 } 8880 return *value; 8881 } 8882 8883 8884 RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { 8885 HandleScope scope(isolate); 8886 ASSERT(args.length() == 1); 8887 8888 return isolate->Throw(args[0]); 8889 } 8890 8891 8892 RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { 8893 HandleScope scope(isolate); 8894 ASSERT(args.length() == 1); 8895 8896 return isolate->ReThrow(args[0]); 8897 } 8898 8899 8900 RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) { 8901 ASSERT_EQ(0, args.length()); 8902 return isolate->PromoteScheduledException(); 8903 } 8904 8905 8906 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { 8907 HandleScope scope(isolate); 8908 ASSERT(args.length() == 1); 8909 8910 Handle<Object> name(args[0], isolate); 8911 Handle<Object> reference_error = 8912 isolate->factory()->NewReferenceError("not_defined", 8913 HandleVector(&name, 1)); 8914 return isolate->Throw(*reference_error); 8915 } 8916 8917 8918 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { 8919 ASSERT(args.length() == 0); 8920 8921 // First check if this is a real stack overflow. 8922 if (isolate->stack_guard()->IsStackOverflow()) { 8923 NoHandleAllocation na; 8924 return isolate->StackOverflow(); 8925 } 8926 8927 return Execution::HandleStackGuardInterrupt(isolate); 8928 } 8929 8930 8931 RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) { 8932 ASSERT(args.length() == 0); 8933 return Execution::HandleStackGuardInterrupt(isolate); 8934 } 8935 8936 8937 static int StackSize() { 8938 int n = 0; 8939 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++; 8940 return n; 8941 } 8942 8943 8944 static void PrintTransition(Object* result) { 8945 // indentation 8946 { const int nmax = 80; 8947 int n = StackSize(); 8948 if (n <= nmax) 8949 PrintF("%4d:%*s", n, n, ""); 8950 else 8951 PrintF("%4d:%*s", n, nmax, "..."); 8952 } 8953 8954 if (result == NULL) { 8955 JavaScriptFrame::PrintTop(stdout, true, false); 8956 PrintF(" {\n"); 8957 } else { 8958 // function result 8959 PrintF("} -> "); 8960 result->ShortPrint(); 8961 PrintF("\n"); 8962 } 8963 } 8964 8965 8966 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { 8967 ASSERT(args.length() == 0); 8968 NoHandleAllocation ha; 8969 PrintTransition(NULL); 8970 return isolate->heap()->undefined_value(); 8971 } 8972 8973 8974 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) { 8975 NoHandleAllocation ha; 8976 PrintTransition(args[0]); 8977 return args[0]; // return TOS 8978 } 8979 8980 8981 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { 8982 NoHandleAllocation ha; 8983 ASSERT(args.length() == 1); 8984 8985 #ifdef DEBUG 8986 if (args[0]->IsString()) { 8987 // If we have a string, assume it's a code "marker" 8988 // and print some interesting cpu debugging info. 8989 JavaScriptFrameIterator it(isolate); 8990 JavaScriptFrame* frame = it.frame(); 8991 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 8992 frame->fp(), frame->sp(), frame->caller_sp()); 8993 } else { 8994 PrintF("DebugPrint: "); 8995 } 8996 args[0]->Print(); 8997 if (args[0]->IsHeapObject()) { 8998 PrintF("\n"); 8999 HeapObject::cast(args[0])->map()->Print(); 9000 } 9001 #else 9002 // ShortPrint is available in release mode. Print is not. 9003 args[0]->ShortPrint(); 9004 #endif 9005 PrintF("\n"); 9006 Flush(); 9007 9008 return args[0]; // return TOS 9009 } 9010 9011 9012 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { 9013 ASSERT(args.length() == 0); 9014 NoHandleAllocation ha; 9015 isolate->PrintStack(); 9016 return isolate->heap()->undefined_value(); 9017 } 9018 9019 9020 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) { 9021 NoHandleAllocation ha; 9022 ASSERT(args.length() == 0); 9023 9024 // According to ECMA-262, section 15.9.1, page 117, the precision of 9025 // the number in a Date object representing a particular instant in 9026 // time is milliseconds. Therefore, we floor the result of getting 9027 // the OS time. 9028 double millis = floor(OS::TimeCurrentMillis()); 9029 return isolate->heap()->NumberFromDouble(millis); 9030 } 9031 9032 9033 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { 9034 HandleScope scope(isolate); 9035 ASSERT(args.length() == 2); 9036 9037 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 9038 FlattenString(str); 9039 9040 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); 9041 9042 MaybeObject* maybe_result_array = 9043 output->EnsureCanContainHeapObjectElements(); 9044 if (maybe_result_array->IsFailure()) return maybe_result_array; 9045 RUNTIME_ASSERT(output->HasFastElements()); 9046 9047 AssertNoAllocation no_allocation; 9048 9049 FixedArray* output_array = FixedArray::cast(output->elements()); 9050 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 9051 bool result; 9052 String::FlatContent str_content = str->GetFlatContent(); 9053 if (str_content.IsAscii()) { 9054 result = DateParser::Parse(str_content.ToAsciiVector(), 9055 output_array, 9056 isolate->unicode_cache()); 9057 } else { 9058 ASSERT(str_content.IsTwoByte()); 9059 result = DateParser::Parse(str_content.ToUC16Vector(), 9060 output_array, 9061 isolate->unicode_cache()); 9062 } 9063 9064 if (result) { 9065 return *output; 9066 } else { 9067 return isolate->heap()->null_value(); 9068 } 9069 } 9070 9071 9072 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) { 9073 NoHandleAllocation ha; 9074 ASSERT(args.length() == 1); 9075 9076 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9077 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x)); 9078 const char* zone = OS::LocalTimezone(static_cast<double>(time)); 9079 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone)); 9080 } 9081 9082 9083 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) { 9084 NoHandleAllocation ha; 9085 ASSERT(args.length() == 1); 9086 9087 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9088 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); 9089 9090 return isolate->heap()->NumberFromDouble(static_cast<double>(time)); 9091 } 9092 9093 9094 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) { 9095 ASSERT(args.length() == 1); 9096 Object* global = args[0]; 9097 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); 9098 return JSGlobalObject::cast(global)->global_receiver(); 9099 } 9100 9101 9102 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { 9103 HandleScope scope(isolate); 9104 ASSERT_EQ(1, args.length()); 9105 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9106 9107 source = Handle<String>(source->TryFlattenGetString()); 9108 // Optimized fast case where we only have ASCII characters. 9109 Handle<Object> result; 9110 if (source->IsSeqAsciiString()) { 9111 result = JsonParser<true>::Parse(source); 9112 } else { 9113 result = JsonParser<false>::Parse(source); 9114 } 9115 if (result.is_null()) { 9116 // Syntax error or stack overflow in scanner. 9117 ASSERT(isolate->has_pending_exception()); 9118 return Failure::Exception(); 9119 } 9120 return *result; 9121 } 9122 9123 9124 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 9125 Handle<Context> context) { 9126 ASSERT(context->allow_code_gen_from_strings()->IsFalse()); 9127 // Check with callback if set. 9128 AllowCodeGenerationFromStringsCallback callback = 9129 isolate->allow_code_gen_callback(); 9130 if (callback == NULL) { 9131 // No callback set and code generation disallowed. 9132 return false; 9133 } else { 9134 // Callback set. Let it decide if code generation is allowed. 9135 VMState state(isolate, EXTERNAL); 9136 return callback(v8::Utils::ToLocal(context)); 9137 } 9138 } 9139 9140 9141 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { 9142 HandleScope scope(isolate); 9143 ASSERT_EQ(1, args.length()); 9144 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9145 9146 // Extract global context. 9147 Handle<Context> context(isolate->context()->global_context()); 9148 9149 // Check if global context allows code generation from 9150 // strings. Throw an exception if it doesn't. 9151 if (context->allow_code_gen_from_strings()->IsFalse() && 9152 !CodeGenerationFromStringsAllowed(isolate, context)) { 9153 return isolate->Throw(*isolate->factory()->NewError( 9154 "code_gen_from_strings", HandleVector<Object>(NULL, 0))); 9155 } 9156 9157 // Compile source string in the global context. 9158 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9159 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition); 9160 if (shared.is_null()) return Failure::Exception(); 9161 Handle<JSFunction> fun = 9162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 9163 context, 9164 NOT_TENURED); 9165 return *fun; 9166 } 9167 9168 9169 static ObjectPair CompileGlobalEval(Isolate* isolate, 9170 Handle<String> source, 9171 Handle<Object> receiver, 9172 LanguageMode language_mode, 9173 int scope_position) { 9174 Handle<Context> context = Handle<Context>(isolate->context()); 9175 Handle<Context> global_context = Handle<Context>(context->global_context()); 9176 9177 // Check if global context allows code generation from 9178 // strings. Throw an exception if it doesn't. 9179 if (global_context->allow_code_gen_from_strings()->IsFalse() && 9180 !CodeGenerationFromStringsAllowed(isolate, global_context)) { 9181 isolate->Throw(*isolate->factory()->NewError( 9182 "code_gen_from_strings", HandleVector<Object>(NULL, 0))); 9183 return MakePair(Failure::Exception(), NULL); 9184 } 9185 9186 // Deal with a normal eval call with a string argument. Compile it 9187 // and return the compiled function bound in the local context. 9188 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9189 source, 9190 Handle<Context>(isolate->context()), 9191 context->IsGlobalContext(), 9192 language_mode, 9193 scope_position); 9194 if (shared.is_null()) return MakePair(Failure::Exception(), NULL); 9195 Handle<JSFunction> compiled = 9196 isolate->factory()->NewFunctionFromSharedFunctionInfo( 9197 shared, context, NOT_TENURED); 9198 return MakePair(*compiled, *receiver); 9199 } 9200 9201 9202 RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { 9203 ASSERT(args.length() == 5); 9204 9205 HandleScope scope(isolate); 9206 Handle<Object> callee = args.at<Object>(0); 9207 9208 // If "eval" didn't refer to the original GlobalEval, it's not a 9209 // direct call to eval. 9210 // (And even if it is, but the first argument isn't a string, just let 9211 // execution default to an indirect call to eval, which will also return 9212 // the first argument without doing anything). 9213 if (*callee != isolate->global_context()->global_eval_fun() || 9214 !args[1]->IsString()) { 9215 return MakePair(*callee, isolate->heap()->the_hole_value()); 9216 } 9217 9218 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 9219 ASSERT(args[4]->IsSmi()); 9220 return CompileGlobalEval(isolate, 9221 args.at<String>(1), 9222 args.at<Object>(2), 9223 language_mode, 9224 args.smi_at(4)); 9225 } 9226 9227 9228 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) { 9229 // This utility adjusts the property attributes for newly created Function 9230 // object ("new Function(...)") by changing the map. 9231 // All it does is changing the prototype property to enumerable 9232 // as specified in ECMA262, 15.3.5.2. 9233 HandleScope scope(isolate); 9234 ASSERT(args.length() == 1); 9235 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 9236 9237 Handle<Map> map = func->shared()->is_classic_mode() 9238 ? isolate->function_instance_map() 9239 : isolate->strict_mode_function_instance_map(); 9240 9241 ASSERT(func->map()->instance_type() == map->instance_type()); 9242 ASSERT(func->map()->instance_size() == map->instance_size()); 9243 func->set_map(*map); 9244 return *func; 9245 } 9246 9247 9248 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { 9249 // Allocate a block of memory in NewSpace (filled with a filler). 9250 // Use as fallback for allocation in generated code when NewSpace 9251 // is full. 9252 ASSERT(args.length() == 1); 9253 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0); 9254 int size = size_smi->value(); 9255 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); 9256 RUNTIME_ASSERT(size > 0); 9257 Heap* heap = isolate->heap(); 9258 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4; 9259 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC); 9260 Object* allocation; 9261 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size); 9262 if (maybe_allocation->ToObject(&allocation)) { 9263 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size); 9264 } 9265 return maybe_allocation; 9266 } 9267 } 9268 9269 9270 // Push an object unto an array of objects if it is not already in the 9271 // array. Returns true if the element was pushed on the stack and 9272 // false otherwise. 9273 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { 9274 ASSERT(args.length() == 2); 9275 CONVERT_ARG_CHECKED(JSArray, array, 0); 9276 CONVERT_ARG_CHECKED(JSObject, element, 1); 9277 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements()); 9278 int length = Smi::cast(array->length())->value(); 9279 FixedArray* elements = FixedArray::cast(array->elements()); 9280 for (int i = 0; i < length; i++) { 9281 if (elements->get(i) == element) return isolate->heap()->false_value(); 9282 } 9283 Object* obj; 9284 // Strict not needed. Used for cycle detection in Array join implementation. 9285 { MaybeObject* maybe_obj = 9286 array->SetFastElement(length, element, kNonStrictMode, true); 9287 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9288 } 9289 return isolate->heap()->true_value(); 9290 } 9291 9292 9293 /** 9294 * A simple visitor visits every element of Array's. 9295 * The backend storage can be a fixed array for fast elements case, 9296 * or a dictionary for sparse array. Since Dictionary is a subtype 9297 * of FixedArray, the class can be used by both fast and slow cases. 9298 * The second parameter of the constructor, fast_elements, specifies 9299 * whether the storage is a FixedArray or Dictionary. 9300 * 9301 * An index limit is used to deal with the situation that a result array 9302 * length overflows 32-bit non-negative integer. 9303 */ 9304 class ArrayConcatVisitor { 9305 public: 9306 ArrayConcatVisitor(Isolate* isolate, 9307 Handle<FixedArray> storage, 9308 bool fast_elements) : 9309 isolate_(isolate), 9310 storage_(Handle<FixedArray>::cast( 9311 isolate->global_handles()->Create(*storage))), 9312 index_offset_(0u), 9313 fast_elements_(fast_elements) { } 9314 9315 ~ArrayConcatVisitor() { 9316 clear_storage(); 9317 } 9318 9319 void visit(uint32_t i, Handle<Object> elm) { 9320 if (i >= JSObject::kMaxElementCount - index_offset_) return; 9321 uint32_t index = index_offset_ + i; 9322 9323 if (fast_elements_) { 9324 if (index < static_cast<uint32_t>(storage_->length())) { 9325 storage_->set(index, *elm); 9326 return; 9327 } 9328 // Our initial estimate of length was foiled, possibly by 9329 // getters on the arrays increasing the length of later arrays 9330 // during iteration. 9331 // This shouldn't happen in anything but pathological cases. 9332 SetDictionaryMode(index); 9333 // Fall-through to dictionary mode. 9334 } 9335 ASSERT(!fast_elements_); 9336 Handle<SeededNumberDictionary> dict( 9337 SeededNumberDictionary::cast(*storage_)); 9338 Handle<SeededNumberDictionary> result = 9339 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); 9340 if (!result.is_identical_to(dict)) { 9341 // Dictionary needed to grow. 9342 clear_storage(); 9343 set_storage(*result); 9344 } 9345 } 9346 9347 void increase_index_offset(uint32_t delta) { 9348 if (JSObject::kMaxElementCount - index_offset_ < delta) { 9349 index_offset_ = JSObject::kMaxElementCount; 9350 } else { 9351 index_offset_ += delta; 9352 } 9353 } 9354 9355 Handle<JSArray> ToArray() { 9356 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 9357 Handle<Object> length = 9358 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 9359 Handle<Map> map; 9360 if (fast_elements_) { 9361 map = isolate_->factory()->GetElementsTransitionMap(array, 9362 FAST_ELEMENTS); 9363 } else { 9364 map = isolate_->factory()->GetElementsTransitionMap(array, 9365 DICTIONARY_ELEMENTS); 9366 } 9367 array->set_map(*map); 9368 array->set_length(*length); 9369 array->set_elements(*storage_); 9370 return array; 9371 } 9372 9373 private: 9374 // Convert storage to dictionary mode. 9375 void SetDictionaryMode(uint32_t index) { 9376 ASSERT(fast_elements_); 9377 Handle<FixedArray> current_storage(*storage_); 9378 Handle<SeededNumberDictionary> slow_storage( 9379 isolate_->factory()->NewSeededNumberDictionary( 9380 current_storage->length())); 9381 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 9382 for (uint32_t i = 0; i < current_length; i++) { 9383 HandleScope loop_scope; 9384 Handle<Object> element(current_storage->get(i)); 9385 if (!element->IsTheHole()) { 9386 Handle<SeededNumberDictionary> new_storage = 9387 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); 9388 if (!new_storage.is_identical_to(slow_storage)) { 9389 slow_storage = loop_scope.CloseAndEscape(new_storage); 9390 } 9391 } 9392 } 9393 clear_storage(); 9394 set_storage(*slow_storage); 9395 fast_elements_ = false; 9396 } 9397 9398 inline void clear_storage() { 9399 isolate_->global_handles()->Destroy( 9400 Handle<Object>::cast(storage_).location()); 9401 } 9402 9403 inline void set_storage(FixedArray* storage) { 9404 storage_ = Handle<FixedArray>::cast( 9405 isolate_->global_handles()->Create(storage)); 9406 } 9407 9408 Isolate* isolate_; 9409 Handle<FixedArray> storage_; // Always a global handle. 9410 // Index after last seen index. Always less than or equal to 9411 // JSObject::kMaxElementCount. 9412 uint32_t index_offset_; 9413 bool fast_elements_; 9414 }; 9415 9416 9417 static uint32_t EstimateElementCount(Handle<JSArray> array) { 9418 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 9419 int element_count = 0; 9420 switch (array->GetElementsKind()) { 9421 case FAST_SMI_ONLY_ELEMENTS: 9422 case FAST_ELEMENTS: { 9423 // Fast elements can't have lengths that are not representable by 9424 // a 32-bit signed integer. 9425 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); 9426 int fast_length = static_cast<int>(length); 9427 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 9428 for (int i = 0; i < fast_length; i++) { 9429 if (!elements->get(i)->IsTheHole()) element_count++; 9430 } 9431 break; 9432 } 9433 case FAST_DOUBLE_ELEMENTS: 9434 // TODO(1810): Decide if it's worthwhile to implement this. 9435 UNREACHABLE(); 9436 break; 9437 case DICTIONARY_ELEMENTS: { 9438 Handle<SeededNumberDictionary> dictionary( 9439 SeededNumberDictionary::cast(array->elements())); 9440 int capacity = dictionary->Capacity(); 9441 for (int i = 0; i < capacity; i++) { 9442 Handle<Object> key(dictionary->KeyAt(i)); 9443 if (dictionary->IsKey(*key)) { 9444 element_count++; 9445 } 9446 } 9447 break; 9448 } 9449 case NON_STRICT_ARGUMENTS_ELEMENTS: 9450 case EXTERNAL_BYTE_ELEMENTS: 9451 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 9452 case EXTERNAL_SHORT_ELEMENTS: 9453 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 9454 case EXTERNAL_INT_ELEMENTS: 9455 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 9456 case EXTERNAL_FLOAT_ELEMENTS: 9457 case EXTERNAL_DOUBLE_ELEMENTS: 9458 case EXTERNAL_PIXEL_ELEMENTS: 9459 // External arrays are always dense. 9460 return length; 9461 } 9462 // As an estimate, we assume that the prototype doesn't contain any 9463 // inherited elements. 9464 return element_count; 9465 } 9466 9467 9468 9469 template<class ExternalArrayClass, class ElementType> 9470 static void IterateExternalArrayElements(Isolate* isolate, 9471 Handle<JSObject> receiver, 9472 bool elements_are_ints, 9473 bool elements_are_guaranteed_smis, 9474 ArrayConcatVisitor* visitor) { 9475 Handle<ExternalArrayClass> array( 9476 ExternalArrayClass::cast(receiver->elements())); 9477 uint32_t len = static_cast<uint32_t>(array->length()); 9478 9479 ASSERT(visitor != NULL); 9480 if (elements_are_ints) { 9481 if (elements_are_guaranteed_smis) { 9482 for (uint32_t j = 0; j < len; j++) { 9483 HandleScope loop_scope; 9484 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j)))); 9485 visitor->visit(j, e); 9486 } 9487 } else { 9488 for (uint32_t j = 0; j < len; j++) { 9489 HandleScope loop_scope; 9490 int64_t val = static_cast<int64_t>(array->get_scalar(j)); 9491 if (Smi::IsValid(static_cast<intptr_t>(val))) { 9492 Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); 9493 visitor->visit(j, e); 9494 } else { 9495 Handle<Object> e = 9496 isolate->factory()->NewNumber(static_cast<ElementType>(val)); 9497 visitor->visit(j, e); 9498 } 9499 } 9500 } 9501 } else { 9502 for (uint32_t j = 0; j < len; j++) { 9503 HandleScope loop_scope(isolate); 9504 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); 9505 visitor->visit(j, e); 9506 } 9507 } 9508 } 9509 9510 9511 // Used for sorting indices in a List<uint32_t>. 9512 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 9513 uint32_t a = *ap; 9514 uint32_t b = *bp; 9515 return (a == b) ? 0 : (a < b) ? -1 : 1; 9516 } 9517 9518 9519 static void CollectElementIndices(Handle<JSObject> object, 9520 uint32_t range, 9521 List<uint32_t>* indices) { 9522 ElementsKind kind = object->GetElementsKind(); 9523 switch (kind) { 9524 case FAST_SMI_ONLY_ELEMENTS: 9525 case FAST_ELEMENTS: { 9526 Handle<FixedArray> elements(FixedArray::cast(object->elements())); 9527 uint32_t length = static_cast<uint32_t>(elements->length()); 9528 if (range < length) length = range; 9529 for (uint32_t i = 0; i < length; i++) { 9530 if (!elements->get(i)->IsTheHole()) { 9531 indices->Add(i); 9532 } 9533 } 9534 break; 9535 } 9536 case FAST_DOUBLE_ELEMENTS: { 9537 // TODO(1810): Decide if it's worthwhile to implement this. 9538 UNREACHABLE(); 9539 break; 9540 } 9541 case DICTIONARY_ELEMENTS: { 9542 Handle<SeededNumberDictionary> dict( 9543 SeededNumberDictionary::cast(object->elements())); 9544 uint32_t capacity = dict->Capacity(); 9545 for (uint32_t j = 0; j < capacity; j++) { 9546 HandleScope loop_scope; 9547 Handle<Object> k(dict->KeyAt(j)); 9548 if (dict->IsKey(*k)) { 9549 ASSERT(k->IsNumber()); 9550 uint32_t index = static_cast<uint32_t>(k->Number()); 9551 if (index < range) { 9552 indices->Add(index); 9553 } 9554 } 9555 } 9556 break; 9557 } 9558 default: { 9559 int dense_elements_length; 9560 switch (kind) { 9561 case EXTERNAL_PIXEL_ELEMENTS: { 9562 dense_elements_length = 9563 ExternalPixelArray::cast(object->elements())->length(); 9564 break; 9565 } 9566 case EXTERNAL_BYTE_ELEMENTS: { 9567 dense_elements_length = 9568 ExternalByteArray::cast(object->elements())->length(); 9569 break; 9570 } 9571 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 9572 dense_elements_length = 9573 ExternalUnsignedByteArray::cast(object->elements())->length(); 9574 break; 9575 } 9576 case EXTERNAL_SHORT_ELEMENTS: { 9577 dense_elements_length = 9578 ExternalShortArray::cast(object->elements())->length(); 9579 break; 9580 } 9581 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 9582 dense_elements_length = 9583 ExternalUnsignedShortArray::cast(object->elements())->length(); 9584 break; 9585 } 9586 case EXTERNAL_INT_ELEMENTS: { 9587 dense_elements_length = 9588 ExternalIntArray::cast(object->elements())->length(); 9589 break; 9590 } 9591 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 9592 dense_elements_length = 9593 ExternalUnsignedIntArray::cast(object->elements())->length(); 9594 break; 9595 } 9596 case EXTERNAL_FLOAT_ELEMENTS: { 9597 dense_elements_length = 9598 ExternalFloatArray::cast(object->elements())->length(); 9599 break; 9600 } 9601 case EXTERNAL_DOUBLE_ELEMENTS: { 9602 dense_elements_length = 9603 ExternalDoubleArray::cast(object->elements())->length(); 9604 break; 9605 } 9606 default: 9607 UNREACHABLE(); 9608 dense_elements_length = 0; 9609 break; 9610 } 9611 uint32_t length = static_cast<uint32_t>(dense_elements_length); 9612 if (range <= length) { 9613 length = range; 9614 // We will add all indices, so we might as well clear it first 9615 // and avoid duplicates. 9616 indices->Clear(); 9617 } 9618 for (uint32_t i = 0; i < length; i++) { 9619 indices->Add(i); 9620 } 9621 if (length == range) return; // All indices accounted for already. 9622 break; 9623 } 9624 } 9625 9626 Handle<Object> prototype(object->GetPrototype()); 9627 if (prototype->IsJSObject()) { 9628 // The prototype will usually have no inherited element indices, 9629 // but we have to check. 9630 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); 9631 } 9632 } 9633 9634 9635 /** 9636 * A helper function that visits elements of a JSArray in numerical 9637 * order. 9638 * 9639 * The visitor argument called for each existing element in the array 9640 * with the element index and the element's value. 9641 * Afterwards it increments the base-index of the visitor by the array 9642 * length. 9643 * Returns false if any access threw an exception, otherwise true. 9644 */ 9645 static bool IterateElements(Isolate* isolate, 9646 Handle<JSArray> receiver, 9647 ArrayConcatVisitor* visitor) { 9648 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); 9649 switch (receiver->GetElementsKind()) { 9650 case FAST_SMI_ONLY_ELEMENTS: 9651 case FAST_ELEMENTS: { 9652 // Run through the elements FixedArray and use HasElement and GetElement 9653 // to check the prototype for missing elements. 9654 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 9655 int fast_length = static_cast<int>(length); 9656 ASSERT(fast_length <= elements->length()); 9657 for (int j = 0; j < fast_length; j++) { 9658 HandleScope loop_scope(isolate); 9659 Handle<Object> element_value(elements->get(j), isolate); 9660 if (!element_value->IsTheHole()) { 9661 visitor->visit(j, element_value); 9662 } else if (receiver->HasElement(j)) { 9663 // Call GetElement on receiver, not its prototype, or getters won't 9664 // have the correct receiver. 9665 element_value = Object::GetElement(receiver, j); 9666 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); 9667 visitor->visit(j, element_value); 9668 } 9669 } 9670 break; 9671 } 9672 case FAST_DOUBLE_ELEMENTS: { 9673 // TODO(1810): Decide if it's worthwhile to implement this. 9674 UNREACHABLE(); 9675 break; 9676 } 9677 case DICTIONARY_ELEMENTS: { 9678 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); 9679 List<uint32_t> indices(dict->Capacity() / 2); 9680 // Collect all indices in the object and the prototypes less 9681 // than length. This might introduce duplicates in the indices list. 9682 CollectElementIndices(receiver, length, &indices); 9683 indices.Sort(&compareUInt32); 9684 int j = 0; 9685 int n = indices.length(); 9686 while (j < n) { 9687 HandleScope loop_scope; 9688 uint32_t index = indices[j]; 9689 Handle<Object> element = Object::GetElement(receiver, index); 9690 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false); 9691 visitor->visit(index, element); 9692 // Skip to next different index (i.e., omit duplicates). 9693 do { 9694 j++; 9695 } while (j < n && indices[j] == index); 9696 } 9697 break; 9698 } 9699 case EXTERNAL_PIXEL_ELEMENTS: { 9700 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast( 9701 receiver->elements())); 9702 for (uint32_t j = 0; j < length; j++) { 9703 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j))); 9704 visitor->visit(j, e); 9705 } 9706 break; 9707 } 9708 case EXTERNAL_BYTE_ELEMENTS: { 9709 IterateExternalArrayElements<ExternalByteArray, int8_t>( 9710 isolate, receiver, true, true, visitor); 9711 break; 9712 } 9713 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 9714 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( 9715 isolate, receiver, true, true, visitor); 9716 break; 9717 } 9718 case EXTERNAL_SHORT_ELEMENTS: { 9719 IterateExternalArrayElements<ExternalShortArray, int16_t>( 9720 isolate, receiver, true, true, visitor); 9721 break; 9722 } 9723 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 9724 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( 9725 isolate, receiver, true, true, visitor); 9726 break; 9727 } 9728 case EXTERNAL_INT_ELEMENTS: { 9729 IterateExternalArrayElements<ExternalIntArray, int32_t>( 9730 isolate, receiver, true, false, visitor); 9731 break; 9732 } 9733 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 9734 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( 9735 isolate, receiver, true, false, visitor); 9736 break; 9737 } 9738 case EXTERNAL_FLOAT_ELEMENTS: { 9739 IterateExternalArrayElements<ExternalFloatArray, float>( 9740 isolate, receiver, false, false, visitor); 9741 break; 9742 } 9743 case EXTERNAL_DOUBLE_ELEMENTS: { 9744 IterateExternalArrayElements<ExternalDoubleArray, double>( 9745 isolate, receiver, false, false, visitor); 9746 break; 9747 } 9748 default: 9749 UNREACHABLE(); 9750 break; 9751 } 9752 visitor->increase_index_offset(length); 9753 return true; 9754 } 9755 9756 9757 /** 9758 * Array::concat implementation. 9759 * See ECMAScript 262, 15.4.4.4. 9760 * TODO(581): Fix non-compliance for very large concatenations and update to 9761 * following the ECMAScript 5 specification. 9762 */ 9763 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { 9764 ASSERT(args.length() == 1); 9765 HandleScope handle_scope(isolate); 9766 9767 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); 9768 int argument_count = static_cast<int>(arguments->length()->Number()); 9769 RUNTIME_ASSERT(arguments->HasFastElements()); 9770 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); 9771 9772 // Pass 1: estimate the length and number of elements of the result. 9773 // The actual length can be larger if any of the arguments have getters 9774 // that mutate other arguments (but will otherwise be precise). 9775 // The number of elements is precise if there are no inherited elements. 9776 9777 uint32_t estimate_result_length = 0; 9778 uint32_t estimate_nof_elements = 0; 9779 { 9780 for (int i = 0; i < argument_count; i++) { 9781 HandleScope loop_scope; 9782 Handle<Object> obj(elements->get(i)); 9783 uint32_t length_estimate; 9784 uint32_t element_estimate; 9785 if (obj->IsJSArray()) { 9786 Handle<JSArray> array(Handle<JSArray>::cast(obj)); 9787 // TODO(1810): Find out if it's worthwhile to properly support 9788 // arbitrary ElementsKinds. For now, pessimistically transition to 9789 // FAST_ELEMENTS. 9790 if (array->HasFastDoubleElements()) { 9791 array = Handle<JSArray>::cast( 9792 JSObject::TransitionElementsKind(array, FAST_ELEMENTS)); 9793 } 9794 length_estimate = 9795 static_cast<uint32_t>(array->length()->Number()); 9796 element_estimate = 9797 EstimateElementCount(array); 9798 } else { 9799 length_estimate = 1; 9800 element_estimate = 1; 9801 } 9802 // Avoid overflows by capping at kMaxElementCount. 9803 if (JSObject::kMaxElementCount - estimate_result_length < 9804 length_estimate) { 9805 estimate_result_length = JSObject::kMaxElementCount; 9806 } else { 9807 estimate_result_length += length_estimate; 9808 } 9809 if (JSObject::kMaxElementCount - estimate_nof_elements < 9810 element_estimate) { 9811 estimate_nof_elements = JSObject::kMaxElementCount; 9812 } else { 9813 estimate_nof_elements += element_estimate; 9814 } 9815 } 9816 } 9817 9818 // If estimated number of elements is more than half of length, a 9819 // fixed array (fast case) is more time and space-efficient than a 9820 // dictionary. 9821 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; 9822 9823 Handle<FixedArray> storage; 9824 if (fast_case) { 9825 // The backing storage array must have non-existing elements to 9826 // preserve holes across concat operations. 9827 storage = isolate->factory()->NewFixedArrayWithHoles( 9828 estimate_result_length); 9829 } else { 9830 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 9831 uint32_t at_least_space_for = estimate_nof_elements + 9832 (estimate_nof_elements >> 2); 9833 storage = Handle<FixedArray>::cast( 9834 isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); 9835 } 9836 9837 ArrayConcatVisitor visitor(isolate, storage, fast_case); 9838 9839 for (int i = 0; i < argument_count; i++) { 9840 Handle<Object> obj(elements->get(i)); 9841 if (obj->IsJSArray()) { 9842 Handle<JSArray> array = Handle<JSArray>::cast(obj); 9843 if (!IterateElements(isolate, array, &visitor)) { 9844 return Failure::Exception(); 9845 } 9846 } else { 9847 visitor.visit(0, obj); 9848 visitor.increase_index_offset(1); 9849 } 9850 } 9851 9852 return *visitor.ToArray(); 9853 } 9854 9855 9856 // This will not allocate (flatten the string), but it may run 9857 // very slowly for very deeply nested ConsStrings. For debugging use only. 9858 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { 9859 NoHandleAllocation ha; 9860 ASSERT(args.length() == 1); 9861 9862 CONVERT_ARG_CHECKED(String, string, 0); 9863 StringInputBuffer buffer(string); 9864 while (buffer.has_more()) { 9865 uint16_t character = buffer.GetNext(); 9866 PrintF("%c", character); 9867 } 9868 return string; 9869 } 9870 9871 // Moves all own elements of an object, that are below a limit, to positions 9872 // starting at zero. All undefined values are placed after non-undefined values, 9873 // and are followed by non-existing element. Does not change the length 9874 // property. 9875 // Returns the number of non-undefined elements collected. 9876 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { 9877 ASSERT(args.length() == 2); 9878 CONVERT_ARG_CHECKED(JSObject, object, 0); 9879 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 9880 return object->PrepareElementsForSort(limit); 9881 } 9882 9883 9884 // Move contents of argument 0 (an array) to argument 1 (an array) 9885 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { 9886 ASSERT(args.length() == 2); 9887 CONVERT_ARG_CHECKED(JSArray, from, 0); 9888 CONVERT_ARG_CHECKED(JSArray, to, 1); 9889 FixedArrayBase* new_elements = from->elements(); 9890 MaybeObject* maybe_new_map; 9891 ElementsKind elements_kind; 9892 if (new_elements->map() == isolate->heap()->fixed_array_map() || 9893 new_elements->map() == isolate->heap()->fixed_cow_array_map()) { 9894 elements_kind = FAST_ELEMENTS; 9895 } else if (new_elements->map() == 9896 isolate->heap()->fixed_double_array_map()) { 9897 elements_kind = FAST_DOUBLE_ELEMENTS; 9898 } else { 9899 elements_kind = DICTIONARY_ELEMENTS; 9900 } 9901 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind); 9902 Object* new_map; 9903 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 9904 to->set_map(Map::cast(new_map)); 9905 to->set_elements(new_elements); 9906 to->set_length(from->length()); 9907 Object* obj; 9908 { MaybeObject* maybe_obj = from->ResetElements(); 9909 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9910 } 9911 from->set_length(Smi::FromInt(0)); 9912 return to; 9913 } 9914 9915 9916 // How many elements does this object/array have? 9917 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { 9918 ASSERT(args.length() == 1); 9919 CONVERT_ARG_CHECKED(JSObject, object, 0); 9920 HeapObject* elements = object->elements(); 9921 if (elements->IsDictionary()) { 9922 int result = SeededNumberDictionary::cast(elements)->NumberOfElements(); 9923 return Smi::FromInt(result); 9924 } else if (object->IsJSArray()) { 9925 return JSArray::cast(object)->length(); 9926 } else { 9927 return Smi::FromInt(FixedArray::cast(elements)->length()); 9928 } 9929 } 9930 9931 9932 // Returns an array that tells you where in the [0, length) interval an array 9933 // might have elements. Can either return keys (positive integers) or 9934 // intervals (pair of a negative integer (-start-1) followed by a 9935 // positive (length)) or undefined values. 9936 // Intervals can span over some keys that are not in the object. 9937 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { 9938 ASSERT(args.length() == 2); 9939 HandleScope scope(isolate); 9940 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); 9941 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 9942 if (array->elements()->IsDictionary()) { 9943 // Create an array and get all the keys into it, then remove all the 9944 // keys that are not integers in the range 0 to length-1. 9945 bool threw = false; 9946 Handle<FixedArray> keys = 9947 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw); 9948 if (threw) return Failure::Exception(); 9949 9950 int keys_length = keys->length(); 9951 for (int i = 0; i < keys_length; i++) { 9952 Object* key = keys->get(i); 9953 uint32_t index = 0; 9954 if (!key->ToArrayIndex(&index) || index >= length) { 9955 // Zap invalid keys. 9956 keys->set_undefined(i); 9957 } 9958 } 9959 return *isolate->factory()->NewJSArrayWithElements(keys); 9960 } else { 9961 ASSERT(array->HasFastElements() || 9962 array->HasFastSmiOnlyElements() || 9963 array->HasFastDoubleElements()); 9964 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2); 9965 // -1 means start of array. 9966 single_interval->set(0, Smi::FromInt(-1)); 9967 FixedArrayBase* elements = FixedArrayBase::cast(array->elements()); 9968 uint32_t actual_length = 9969 static_cast<uint32_t>(elements->length()); 9970 uint32_t min_length = actual_length < length ? actual_length : length; 9971 Handle<Object> length_object = 9972 isolate->factory()->NewNumber(static_cast<double>(min_length)); 9973 single_interval->set(1, *length_object); 9974 return *isolate->factory()->NewJSArrayWithElements(single_interval); 9975 } 9976 } 9977 9978 9979 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { 9980 ASSERT(args.length() == 3); 9981 CONVERT_ARG_CHECKED(JSObject, obj, 0); 9982 CONVERT_ARG_CHECKED(String, name, 1); 9983 CONVERT_SMI_ARG_CHECKED(flag, 2); 9984 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; 9985 return obj->LookupAccessor(name, component); 9986 } 9987 9988 9989 #ifdef ENABLE_DEBUGGER_SUPPORT 9990 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) { 9991 ASSERT(args.length() == 0); 9992 return Execution::DebugBreakHelper(); 9993 } 9994 9995 9996 // Helper functions for wrapping and unwrapping stack frame ids. 9997 static Smi* WrapFrameId(StackFrame::Id id) { 9998 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 9999 return Smi::FromInt(id >> 2); 10000 } 10001 10002 10003 static StackFrame::Id UnwrapFrameId(int wrapped) { 10004 return static_cast<StackFrame::Id>(wrapped << 2); 10005 } 10006 10007 10008 // Adds a JavaScript function as a debug event listener. 10009 // args[0]: debug event listener function to set or null or undefined for 10010 // clearing the event listener function 10011 // args[1]: object supplied during callback 10012 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) { 10013 ASSERT(args.length() == 2); 10014 RUNTIME_ASSERT(args[0]->IsJSFunction() || 10015 args[0]->IsUndefined() || 10016 args[0]->IsNull()); 10017 Handle<Object> callback = args.at<Object>(0); 10018 Handle<Object> data = args.at<Object>(1); 10019 isolate->debugger()->SetEventListener(callback, data); 10020 10021 return isolate->heap()->undefined_value(); 10022 } 10023 10024 10025 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) { 10026 ASSERT(args.length() == 0); 10027 isolate->stack_guard()->DebugBreak(); 10028 return isolate->heap()->undefined_value(); 10029 } 10030 10031 10032 static MaybeObject* DebugLookupResultValue(Heap* heap, 10033 Object* receiver, 10034 String* name, 10035 LookupResult* result, 10036 bool* caught_exception) { 10037 Object* value; 10038 switch (result->type()) { 10039 case NORMAL: 10040 value = result->holder()->GetNormalizedProperty(result); 10041 if (value->IsTheHole()) { 10042 return heap->undefined_value(); 10043 } 10044 return value; 10045 case FIELD: 10046 value = 10047 JSObject::cast( 10048 result->holder())->FastPropertyAt(result->GetFieldIndex()); 10049 if (value->IsTheHole()) { 10050 return heap->undefined_value(); 10051 } 10052 return value; 10053 case CONSTANT_FUNCTION: 10054 return result->GetConstantFunction(); 10055 case CALLBACKS: { 10056 Object* structure = result->GetCallbackObject(); 10057 if (structure->IsForeign() || structure->IsAccessorInfo()) { 10058 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback( 10059 receiver, structure, name); 10060 if (!maybe_value->ToObject(&value)) { 10061 if (maybe_value->IsRetryAfterGC()) return maybe_value; 10062 ASSERT(maybe_value->IsException()); 10063 maybe_value = heap->isolate()->pending_exception(); 10064 heap->isolate()->clear_pending_exception(); 10065 if (caught_exception != NULL) { 10066 *caught_exception = true; 10067 } 10068 return maybe_value; 10069 } 10070 return value; 10071 } else { 10072 return heap->undefined_value(); 10073 } 10074 } 10075 case INTERCEPTOR: 10076 case MAP_TRANSITION: 10077 case ELEMENTS_TRANSITION: 10078 case CONSTANT_TRANSITION: 10079 case NULL_DESCRIPTOR: 10080 return heap->undefined_value(); 10081 case HANDLER: 10082 UNREACHABLE(); 10083 return heap->undefined_value(); 10084 } 10085 UNREACHABLE(); // keep the compiler happy 10086 return heap->undefined_value(); 10087 } 10088 10089 10090 // Get debugger related details for an object property. 10091 // args[0]: object holding property 10092 // args[1]: name of the property 10093 // 10094 // The array returned contains the following information: 10095 // 0: Property value 10096 // 1: Property details 10097 // 2: Property value is exception 10098 // 3: Getter function if defined 10099 // 4: Setter function if defined 10100 // Items 2-4 are only filled if the property has either a getter or a setter 10101 // defined through __defineGetter__ and/or __defineSetter__. 10102 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { 10103 HandleScope scope(isolate); 10104 10105 ASSERT(args.length() == 2); 10106 10107 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10108 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 10109 10110 // Make sure to set the current context to the context before the debugger was 10111 // entered (if the debugger is entered). The reason for switching context here 10112 // is that for some property lookups (accessors and interceptors) callbacks 10113 // into the embedding application can occour, and the embedding application 10114 // could have the assumption that its own global context is the current 10115 // context and not some internal debugger context. 10116 SaveContext save(isolate); 10117 if (isolate->debug()->InDebugger()) { 10118 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 10119 } 10120 10121 // Skip the global proxy as it has no properties and always delegates to the 10122 // real global object. 10123 if (obj->IsJSGlobalProxy()) { 10124 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 10125 } 10126 10127 10128 // Check if the name is trivially convertible to an index and get the element 10129 // if so. 10130 uint32_t index; 10131 if (name->AsArrayIndex(&index)) { 10132 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 10133 Object* element_or_char; 10134 { MaybeObject* maybe_element_or_char = 10135 Runtime::GetElementOrCharAt(isolate, obj, index); 10136 if (!maybe_element_or_char->ToObject(&element_or_char)) { 10137 return maybe_element_or_char; 10138 } 10139 } 10140 details->set(0, element_or_char); 10141 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi()); 10142 return *isolate->factory()->NewJSArrayWithElements(details); 10143 } 10144 10145 // Find the number of objects making up this. 10146 int length = LocalPrototypeChainLength(*obj); 10147 10148 // Try local lookup on each of the objects. 10149 Handle<JSObject> jsproto = obj; 10150 for (int i = 0; i < length; i++) { 10151 LookupResult result(isolate); 10152 jsproto->LocalLookup(*name, &result); 10153 if (result.IsProperty()) { 10154 // LookupResult is not GC safe as it holds raw object pointers. 10155 // GC can happen later in this code so put the required fields into 10156 // local variables using handles when required for later use. 10157 PropertyType result_type = result.type(); 10158 Handle<Object> result_callback_obj; 10159 if (result_type == CALLBACKS) { 10160 result_callback_obj = Handle<Object>(result.GetCallbackObject(), 10161 isolate); 10162 } 10163 Smi* property_details = result.GetPropertyDetails().AsSmi(); 10164 // DebugLookupResultValue can cause GC so details from LookupResult needs 10165 // to be copied to handles before this. 10166 bool caught_exception = false; 10167 Object* raw_value; 10168 { MaybeObject* maybe_raw_value = 10169 DebugLookupResultValue(isolate->heap(), *obj, *name, 10170 &result, &caught_exception); 10171 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value; 10172 } 10173 Handle<Object> value(raw_value, isolate); 10174 10175 // If the callback object is a fixed array then it contains JavaScript 10176 // getter and/or setter. 10177 bool hasJavaScriptAccessors = result_type == CALLBACKS && 10178 result_callback_obj->IsAccessorPair(); 10179 Handle<FixedArray> details = 10180 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2); 10181 details->set(0, *value); 10182 details->set(1, property_details); 10183 if (hasJavaScriptAccessors) { 10184 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj); 10185 details->set(2, isolate->heap()->ToBoolean(caught_exception)); 10186 details->set(3, accessors->GetComponent(ACCESSOR_GETTER)); 10187 details->set(4, accessors->GetComponent(ACCESSOR_SETTER)); 10188 } 10189 10190 return *isolate->factory()->NewJSArrayWithElements(details); 10191 } 10192 if (i < length - 1) { 10193 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 10194 } 10195 } 10196 10197 return isolate->heap()->undefined_value(); 10198 } 10199 10200 10201 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { 10202 HandleScope scope(isolate); 10203 10204 ASSERT(args.length() == 2); 10205 10206 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10207 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 10208 10209 LookupResult result(isolate); 10210 obj->Lookup(*name, &result); 10211 if (result.IsProperty()) { 10212 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL); 10213 } 10214 return isolate->heap()->undefined_value(); 10215 } 10216 10217 10218 // Return the property type calculated from the property details. 10219 // args[0]: smi with property details. 10220 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { 10221 ASSERT(args.length() == 1); 10222 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10223 return Smi::FromInt(static_cast<int>(details.type())); 10224 } 10225 10226 10227 // Return the property attribute calculated from the property details. 10228 // args[0]: smi with property details. 10229 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { 10230 ASSERT(args.length() == 1); 10231 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10232 return Smi::FromInt(static_cast<int>(details.attributes())); 10233 } 10234 10235 10236 // Return the property insertion index calculated from the property details. 10237 // args[0]: smi with property details. 10238 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { 10239 ASSERT(args.length() == 1); 10240 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10241 return Smi::FromInt(details.index()); 10242 } 10243 10244 10245 // Return property value from named interceptor. 10246 // args[0]: object 10247 // args[1]: property name 10248 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { 10249 HandleScope scope(isolate); 10250 ASSERT(args.length() == 2); 10251 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10252 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 10253 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 10254 10255 PropertyAttributes attributes; 10256 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); 10257 } 10258 10259 10260 // Return element value from indexed interceptor. 10261 // args[0]: object 10262 // args[1]: index 10263 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) { 10264 HandleScope scope(isolate); 10265 ASSERT(args.length() == 2); 10266 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10267 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 10268 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 10269 10270 return obj->GetElementWithInterceptor(*obj, index); 10271 } 10272 10273 10274 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) { 10275 ASSERT(args.length() >= 1); 10276 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 10277 // Check that the break id is valid. 10278 if (isolate->debug()->break_id() == 0 || 10279 break_id != isolate->debug()->break_id()) { 10280 return isolate->Throw( 10281 isolate->heap()->illegal_execution_state_symbol()); 10282 } 10283 10284 return isolate->heap()->true_value(); 10285 } 10286 10287 10288 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) { 10289 HandleScope scope(isolate); 10290 ASSERT(args.length() == 1); 10291 10292 // Check arguments. 10293 Object* result; 10294 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 10295 RUNTIME_ARGUMENTS(isolate, args)); 10296 if (!maybe_result->ToObject(&result)) return maybe_result; 10297 } 10298 10299 // Count all frames which are relevant to debugging stack trace. 10300 int n = 0; 10301 StackFrame::Id id = isolate->debug()->break_frame_id(); 10302 if (id == StackFrame::NO_ID) { 10303 // If there is no JavaScript stack frame count is 0. 10304 return Smi::FromInt(0); 10305 } 10306 10307 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { 10308 n += it.frame()->GetInlineCount(); 10309 } 10310 return Smi::FromInt(n); 10311 } 10312 10313 10314 class FrameInspector { 10315 public: 10316 FrameInspector(JavaScriptFrame* frame, 10317 int inlined_jsframe_index, 10318 Isolate* isolate) 10319 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { 10320 // Calculate the deoptimized frame. 10321 if (frame->is_optimized()) { 10322 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( 10323 frame, inlined_jsframe_index, isolate); 10324 } 10325 has_adapted_arguments_ = frame_->has_adapted_arguments(); 10326 is_bottommost_ = inlined_jsframe_index == 0; 10327 is_optimized_ = frame_->is_optimized(); 10328 } 10329 10330 ~FrameInspector() { 10331 // Get rid of the calculated deoptimized frame if any. 10332 if (deoptimized_frame_ != NULL) { 10333 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, 10334 isolate_); 10335 } 10336 } 10337 10338 int GetParametersCount() { 10339 return is_optimized_ 10340 ? deoptimized_frame_->parameters_count() 10341 : frame_->ComputeParametersCount(); 10342 } 10343 int expression_count() { return deoptimized_frame_->expression_count(); } 10344 Object* GetFunction() { 10345 return is_optimized_ 10346 ? deoptimized_frame_->GetFunction() 10347 : frame_->function(); 10348 } 10349 Object* GetParameter(int index) { 10350 return is_optimized_ 10351 ? deoptimized_frame_->GetParameter(index) 10352 : frame_->GetParameter(index); 10353 } 10354 Object* GetExpression(int index) { 10355 return is_optimized_ 10356 ? deoptimized_frame_->GetExpression(index) 10357 : frame_->GetExpression(index); 10358 } 10359 int GetSourcePosition() { 10360 return is_optimized_ 10361 ? deoptimized_frame_->GetSourcePosition() 10362 : frame_->LookupCode()->SourcePosition(frame_->pc()); 10363 } 10364 bool IsConstructor() { 10365 return is_optimized_ && !is_bottommost_ 10366 ? deoptimized_frame_->HasConstructStub() 10367 : frame_->IsConstructor(); 10368 } 10369 10370 // To inspect all the provided arguments the frame might need to be 10371 // replaced with the arguments frame. 10372 void SetArgumentsFrame(JavaScriptFrame* frame) { 10373 ASSERT(has_adapted_arguments_); 10374 frame_ = frame; 10375 is_optimized_ = frame_->is_optimized(); 10376 ASSERT(!is_optimized_); 10377 } 10378 10379 private: 10380 JavaScriptFrame* frame_; 10381 DeoptimizedFrameInfo* deoptimized_frame_; 10382 Isolate* isolate_; 10383 bool is_optimized_; 10384 bool is_bottommost_; 10385 bool has_adapted_arguments_; 10386 10387 DISALLOW_COPY_AND_ASSIGN(FrameInspector); 10388 }; 10389 10390 10391 static const int kFrameDetailsFrameIdIndex = 0; 10392 static const int kFrameDetailsReceiverIndex = 1; 10393 static const int kFrameDetailsFunctionIndex = 2; 10394 static const int kFrameDetailsArgumentCountIndex = 3; 10395 static const int kFrameDetailsLocalCountIndex = 4; 10396 static const int kFrameDetailsSourcePositionIndex = 5; 10397 static const int kFrameDetailsConstructCallIndex = 6; 10398 static const int kFrameDetailsAtReturnIndex = 7; 10399 static const int kFrameDetailsFlagsIndex = 8; 10400 static const int kFrameDetailsFirstDynamicIndex = 9; 10401 10402 10403 static SaveContext* FindSavedContextForFrame(Isolate* isolate, 10404 JavaScriptFrame* frame) { 10405 SaveContext* save = isolate->save_context(); 10406 while (save != NULL && !save->IsBelowFrame(frame)) { 10407 save = save->prev(); 10408 } 10409 ASSERT(save != NULL); 10410 return save; 10411 } 10412 10413 10414 // Return an array with frame details 10415 // args[0]: number: break id 10416 // args[1]: number: frame index 10417 // 10418 // The array returned contains the following information: 10419 // 0: Frame id 10420 // 1: Receiver 10421 // 2: Function 10422 // 3: Argument count 10423 // 4: Local count 10424 // 5: Source position 10425 // 6: Constructor call 10426 // 7: Is at return 10427 // 8: Flags 10428 // Arguments name, value 10429 // Locals name, value 10430 // Return value if any 10431 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { 10432 HandleScope scope(isolate); 10433 ASSERT(args.length() == 2); 10434 10435 // Check arguments. 10436 Object* check; 10437 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 10438 RUNTIME_ARGUMENTS(isolate, args)); 10439 if (!maybe_check->ToObject(&check)) return maybe_check; 10440 } 10441 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 10442 Heap* heap = isolate->heap(); 10443 10444 // Find the relevant frame with the requested index. 10445 StackFrame::Id id = isolate->debug()->break_frame_id(); 10446 if (id == StackFrame::NO_ID) { 10447 // If there are no JavaScript stack frames return undefined. 10448 return heap->undefined_value(); 10449 } 10450 10451 int count = 0; 10452 JavaScriptFrameIterator it(isolate, id); 10453 for (; !it.done(); it.Advance()) { 10454 if (index < count + it.frame()->GetInlineCount()) break; 10455 count += it.frame()->GetInlineCount(); 10456 } 10457 if (it.done()) return heap->undefined_value(); 10458 10459 bool is_optimized = it.frame()->is_optimized(); 10460 10461 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame. 10462 if (is_optimized) { 10463 inlined_jsframe_index = 10464 it.frame()->GetInlineCount() - (index - count) - 1; 10465 } 10466 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); 10467 10468 // Traverse the saved contexts chain to find the active context for the 10469 // selected frame. 10470 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); 10471 10472 // Get the frame id. 10473 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); 10474 10475 // Find source position in unoptimized code. 10476 int position = frame_inspector.GetSourcePosition(); 10477 10478 // Check for constructor frame. 10479 bool constructor = frame_inspector.IsConstructor(); 10480 10481 // Get scope info and read from it for local variable information. 10482 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 10483 Handle<SharedFunctionInfo> shared(function->shared()); 10484 Handle<ScopeInfo> scope_info(shared->scope_info()); 10485 ASSERT(*scope_info != ScopeInfo::Empty()); 10486 10487 // Get the locals names and values into a temporary array. 10488 // 10489 // TODO(1240907): Hide compiler-introduced stack variables 10490 // (e.g. .result)? For users of the debugger, they will probably be 10491 // confusing. 10492 Handle<FixedArray> locals = 10493 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2); 10494 10495 // Fill in the values of the locals. 10496 int i = 0; 10497 for (; i < scope_info->StackLocalCount(); ++i) { 10498 // Use the value from the stack. 10499 locals->set(i * 2, scope_info->LocalName(i)); 10500 locals->set(i * 2 + 1, frame_inspector.GetExpression(i)); 10501 } 10502 if (i < scope_info->LocalCount()) { 10503 // Get the context containing declarations. 10504 Handle<Context> context( 10505 Context::cast(it.frame()->context())->declaration_context()); 10506 for (; i < scope_info->LocalCount(); ++i) { 10507 Handle<String> name(scope_info->LocalName(i)); 10508 VariableMode mode; 10509 InitializationFlag init_flag; 10510 locals->set(i * 2, *name); 10511 locals->set(i * 2 + 1, context->get( 10512 scope_info->ContextSlotIndex(*name, &mode, &init_flag))); 10513 } 10514 } 10515 10516 // Check whether this frame is positioned at return. If not top 10517 // frame or if the frame is optimized it cannot be at a return. 10518 bool at_return = false; 10519 if (!is_optimized && index == 0) { 10520 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); 10521 } 10522 10523 // If positioned just before return find the value to be returned and add it 10524 // to the frame information. 10525 Handle<Object> return_value = isolate->factory()->undefined_value(); 10526 if (at_return) { 10527 StackFrameIterator it2(isolate); 10528 Address internal_frame_sp = NULL; 10529 while (!it2.done()) { 10530 if (it2.frame()->is_internal()) { 10531 internal_frame_sp = it2.frame()->sp(); 10532 } else { 10533 if (it2.frame()->is_java_script()) { 10534 if (it2.frame()->id() == it.frame()->id()) { 10535 // The internal frame just before the JavaScript frame contains the 10536 // value to return on top. A debug break at return will create an 10537 // internal frame to store the return value (eax/rax/r0) before 10538 // entering the debug break exit frame. 10539 if (internal_frame_sp != NULL) { 10540 return_value = 10541 Handle<Object>(Memory::Object_at(internal_frame_sp), 10542 isolate); 10543 break; 10544 } 10545 } 10546 } 10547 10548 // Indicate that the previous frame was not an internal frame. 10549 internal_frame_sp = NULL; 10550 } 10551 it2.Advance(); 10552 } 10553 } 10554 10555 // Now advance to the arguments adapter frame (if any). It contains all 10556 // the provided parameters whereas the function frame always have the number 10557 // of arguments matching the functions parameters. The rest of the 10558 // information (except for what is collected above) is the same. 10559 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { 10560 it.AdvanceToArgumentsFrame(); 10561 frame_inspector.SetArgumentsFrame(it.frame()); 10562 } 10563 10564 // Find the number of arguments to fill. At least fill the number of 10565 // parameters for the function and fill more if more parameters are provided. 10566 int argument_count = scope_info->ParameterCount(); 10567 if (argument_count < frame_inspector.GetParametersCount()) { 10568 argument_count = frame_inspector.GetParametersCount(); 10569 } 10570 10571 // Calculate the size of the result. 10572 int details_size = kFrameDetailsFirstDynamicIndex + 10573 2 * (argument_count + scope_info->LocalCount()) + 10574 (at_return ? 1 : 0); 10575 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 10576 10577 // Add the frame id. 10578 details->set(kFrameDetailsFrameIdIndex, *frame_id); 10579 10580 // Add the function (same as in function frame). 10581 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); 10582 10583 // Add the arguments count. 10584 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 10585 10586 // Add the locals count 10587 details->set(kFrameDetailsLocalCountIndex, 10588 Smi::FromInt(scope_info->LocalCount())); 10589 10590 // Add the source position. 10591 if (position != RelocInfo::kNoPosition) { 10592 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 10593 } else { 10594 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 10595 } 10596 10597 // Add the constructor information. 10598 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 10599 10600 // Add the at return information. 10601 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 10602 10603 // Add flags to indicate information on whether this frame is 10604 // bit 0: invoked in the debugger context. 10605 // bit 1: optimized frame. 10606 // bit 2: inlined in optimized frame 10607 int flags = 0; 10608 if (*save->context() == *isolate->debug()->debug_context()) { 10609 flags |= 1 << 0; 10610 } 10611 if (is_optimized) { 10612 flags |= 1 << 1; 10613 flags |= inlined_jsframe_index << 2; 10614 } 10615 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 10616 10617 // Fill the dynamic part. 10618 int details_index = kFrameDetailsFirstDynamicIndex; 10619 10620 // Add arguments name and value. 10621 for (int i = 0; i < argument_count; i++) { 10622 // Name of the argument. 10623 if (i < scope_info->ParameterCount()) { 10624 details->set(details_index++, scope_info->ParameterName(i)); 10625 } else { 10626 details->set(details_index++, heap->undefined_value()); 10627 } 10628 10629 // Parameter value. 10630 if (i < frame_inspector.GetParametersCount()) { 10631 // Get the value from the stack. 10632 details->set(details_index++, frame_inspector.GetParameter(i)); 10633 } else { 10634 details->set(details_index++, heap->undefined_value()); 10635 } 10636 } 10637 10638 // Add locals name and value from the temporary copy from the function frame. 10639 for (int i = 0; i < scope_info->LocalCount() * 2; i++) { 10640 details->set(details_index++, locals->get(i)); 10641 } 10642 10643 // Add the value being returned. 10644 if (at_return) { 10645 details->set(details_index++, *return_value); 10646 } 10647 10648 // Add the receiver (same as in function frame). 10649 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 10650 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 10651 Handle<Object> receiver(it.frame()->receiver(), isolate); 10652 if (!receiver->IsJSObject() && 10653 shared->is_classic_mode() && 10654 !shared->native()) { 10655 // If the receiver is not a JSObject and the function is not a 10656 // builtin or strict-mode we have hit an optimization where a 10657 // value object is not converted into a wrapped JS objects. To 10658 // hide this optimization from the debugger, we wrap the receiver 10659 // by creating correct wrapper object based on the calling frame's 10660 // global context. 10661 it.Advance(); 10662 Handle<Context> calling_frames_global_context( 10663 Context::cast(Context::cast(it.frame()->context())->global_context())); 10664 receiver = 10665 isolate->factory()->ToObject(receiver, calling_frames_global_context); 10666 } 10667 details->set(kFrameDetailsReceiverIndex, *receiver); 10668 10669 ASSERT_EQ(details_size, details_index); 10670 return *isolate->factory()->NewJSArrayWithElements(details); 10671 } 10672 10673 10674 // Copy all the context locals into an object used to materialize a scope. 10675 static bool CopyContextLocalsToScopeObject( 10676 Isolate* isolate, 10677 Handle<ScopeInfo> scope_info, 10678 Handle<Context> context, 10679 Handle<JSObject> scope_object) { 10680 // Fill all context locals to the context extension. 10681 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { 10682 VariableMode mode; 10683 InitializationFlag init_flag; 10684 int context_index = scope_info->ContextSlotIndex( 10685 scope_info->ContextLocalName(i), &mode, &init_flag); 10686 10687 RETURN_IF_EMPTY_HANDLE_VALUE( 10688 isolate, 10689 SetProperty(scope_object, 10690 Handle<String>(scope_info->ContextLocalName(i)), 10691 Handle<Object>(context->get(context_index), isolate), 10692 NONE, 10693 kNonStrictMode), 10694 false); 10695 } 10696 10697 return true; 10698 } 10699 10700 10701 // Create a plain JSObject which materializes the local scope for the specified 10702 // frame. 10703 static Handle<JSObject> MaterializeLocalScopeWithFrameInspector( 10704 Isolate* isolate, 10705 JavaScriptFrame* frame, 10706 FrameInspector* frame_inspector) { 10707 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction())); 10708 Handle<SharedFunctionInfo> shared(function->shared()); 10709 Handle<ScopeInfo> scope_info(shared->scope_info()); 10710 10711 // Allocate and initialize a JSObject with all the arguments, stack locals 10712 // heap locals and extension properties of the debugged function. 10713 Handle<JSObject> local_scope = 10714 isolate->factory()->NewJSObject(isolate->object_function()); 10715 10716 // First fill all parameters. 10717 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 10718 Handle<Object> value( 10719 i < frame_inspector->GetParametersCount() ? 10720 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value()); 10721 10722 RETURN_IF_EMPTY_HANDLE_VALUE( 10723 isolate, 10724 SetProperty(local_scope, 10725 Handle<String>(scope_info->ParameterName(i)), 10726 value, 10727 NONE, 10728 kNonStrictMode), 10729 Handle<JSObject>()); 10730 } 10731 10732 // Second fill all stack locals. 10733 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 10734 RETURN_IF_EMPTY_HANDLE_VALUE( 10735 isolate, 10736 SetProperty(local_scope, 10737 Handle<String>(scope_info->StackLocalName(i)), 10738 Handle<Object>(frame_inspector->GetExpression(i)), 10739 NONE, 10740 kNonStrictMode), 10741 Handle<JSObject>()); 10742 } 10743 10744 if (scope_info->HasContext()) { 10745 // Third fill all context locals. 10746 Handle<Context> frame_context(Context::cast(frame->context())); 10747 Handle<Context> function_context(frame_context->declaration_context()); 10748 if (!CopyContextLocalsToScopeObject( 10749 isolate, scope_info, function_context, local_scope)) { 10750 return Handle<JSObject>(); 10751 } 10752 10753 // Finally copy any properties from the function context extension. 10754 // These will be variables introduced by eval. 10755 if (function_context->closure() == *function) { 10756 if (function_context->has_extension() && 10757 !function_context->IsGlobalContext()) { 10758 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 10759 bool threw = false; 10760 Handle<FixedArray> keys = 10761 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 10762 if (threw) return Handle<JSObject>(); 10763 10764 for (int i = 0; i < keys->length(); i++) { 10765 // Names of variables introduced by eval are strings. 10766 ASSERT(keys->get(i)->IsString()); 10767 Handle<String> key(String::cast(keys->get(i))); 10768 RETURN_IF_EMPTY_HANDLE_VALUE( 10769 isolate, 10770 SetProperty(local_scope, 10771 key, 10772 GetProperty(ext, key), 10773 NONE, 10774 kNonStrictMode), 10775 Handle<JSObject>()); 10776 } 10777 } 10778 } 10779 } 10780 10781 return local_scope; 10782 } 10783 10784 10785 static Handle<JSObject> MaterializeLocalScope( 10786 Isolate* isolate, 10787 JavaScriptFrame* frame, 10788 int inlined_jsframe_index) { 10789 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 10790 return MaterializeLocalScopeWithFrameInspector(isolate, 10791 frame, 10792 &frame_inspector); 10793 } 10794 10795 10796 // Create a plain JSObject which materializes the closure content for the 10797 // context. 10798 static Handle<JSObject> MaterializeClosure(Isolate* isolate, 10799 Handle<Context> context) { 10800 ASSERT(context->IsFunctionContext()); 10801 10802 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 10803 Handle<ScopeInfo> scope_info(shared->scope_info()); 10804 10805 // Allocate and initialize a JSObject with all the content of this function 10806 // closure. 10807 Handle<JSObject> closure_scope = 10808 isolate->factory()->NewJSObject(isolate->object_function()); 10809 10810 // Fill all context locals to the context extension. 10811 if (!CopyContextLocalsToScopeObject( 10812 isolate, scope_info, context, closure_scope)) { 10813 return Handle<JSObject>(); 10814 } 10815 10816 // Finally copy any properties from the function context extension. This will 10817 // be variables introduced by eval. 10818 if (context->has_extension()) { 10819 Handle<JSObject> ext(JSObject::cast(context->extension())); 10820 bool threw = false; 10821 Handle<FixedArray> keys = 10822 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 10823 if (threw) return Handle<JSObject>(); 10824 10825 for (int i = 0; i < keys->length(); i++) { 10826 // Names of variables introduced by eval are strings. 10827 ASSERT(keys->get(i)->IsString()); 10828 Handle<String> key(String::cast(keys->get(i))); 10829 RETURN_IF_EMPTY_HANDLE_VALUE( 10830 isolate, 10831 SetProperty(closure_scope, 10832 key, 10833 GetProperty(ext, key), 10834 NONE, 10835 kNonStrictMode), 10836 Handle<JSObject>()); 10837 } 10838 } 10839 10840 return closure_scope; 10841 } 10842 10843 10844 // Create a plain JSObject which materializes the scope for the specified 10845 // catch context. 10846 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, 10847 Handle<Context> context) { 10848 ASSERT(context->IsCatchContext()); 10849 Handle<String> name(String::cast(context->extension())); 10850 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX)); 10851 Handle<JSObject> catch_scope = 10852 isolate->factory()->NewJSObject(isolate->object_function()); 10853 RETURN_IF_EMPTY_HANDLE_VALUE( 10854 isolate, 10855 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode), 10856 Handle<JSObject>()); 10857 return catch_scope; 10858 } 10859 10860 10861 // Create a plain JSObject which materializes the block scope for the specified 10862 // block context. 10863 static Handle<JSObject> MaterializeBlockScope( 10864 Isolate* isolate, 10865 Handle<Context> context) { 10866 ASSERT(context->IsBlockContext()); 10867 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 10868 10869 // Allocate and initialize a JSObject with all the arguments, stack locals 10870 // heap locals and extension properties of the debugged function. 10871 Handle<JSObject> block_scope = 10872 isolate->factory()->NewJSObject(isolate->object_function()); 10873 10874 // Fill all context locals. 10875 if (!CopyContextLocalsToScopeObject( 10876 isolate, scope_info, context, block_scope)) { 10877 return Handle<JSObject>(); 10878 } 10879 10880 return block_scope; 10881 } 10882 10883 10884 // Create a plain JSObject which materializes the module scope for the specified 10885 // module context. 10886 static Handle<JSObject> MaterializeModuleScope( 10887 Isolate* isolate, 10888 Handle<Context> context) { 10889 ASSERT(context->IsModuleContext()); 10890 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 10891 10892 // Allocate and initialize a JSObject with all the members of the debugged 10893 // module. 10894 Handle<JSObject> module_scope = 10895 isolate->factory()->NewJSObject(isolate->object_function()); 10896 10897 // Fill all context locals. 10898 if (!CopyContextLocalsToScopeObject( 10899 isolate, scope_info, context, module_scope)) { 10900 return Handle<JSObject>(); 10901 } 10902 10903 return module_scope; 10904 } 10905 10906 10907 // Iterate over the actual scopes visible from a stack frame. The iteration 10908 // proceeds from the innermost visible nested scope outwards. All scopes are 10909 // backed by an actual context except the local scope, which is inserted 10910 // "artificially" in the context chain. 10911 class ScopeIterator { 10912 public: 10913 enum ScopeType { 10914 ScopeTypeGlobal = 0, 10915 ScopeTypeLocal, 10916 ScopeTypeWith, 10917 ScopeTypeClosure, 10918 ScopeTypeCatch, 10919 ScopeTypeBlock, 10920 ScopeTypeModule 10921 }; 10922 10923 ScopeIterator(Isolate* isolate, 10924 JavaScriptFrame* frame, 10925 int inlined_jsframe_index) 10926 : isolate_(isolate), 10927 frame_(frame), 10928 inlined_jsframe_index_(inlined_jsframe_index), 10929 function_(JSFunction::cast(frame->function())), 10930 context_(Context::cast(frame->context())), 10931 nested_scope_chain_(4) { 10932 10933 // Catch the case when the debugger stops in an internal function. 10934 Handle<SharedFunctionInfo> shared_info(function_->shared()); 10935 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 10936 if (shared_info->script() == isolate->heap()->undefined_value()) { 10937 while (context_->closure() == *function_) { 10938 context_ = Handle<Context>(context_->previous(), isolate_); 10939 } 10940 return; 10941 } 10942 10943 // Get the debug info (create it if it does not exist). 10944 if (!isolate->debug()->EnsureDebugInfo(shared_info)) { 10945 // Return if ensuring debug info failed. 10946 return; 10947 } 10948 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); 10949 10950 // Find the break point where execution has stopped. 10951 BreakLocationIterator break_location_iterator(debug_info, 10952 ALL_BREAK_LOCATIONS); 10953 break_location_iterator.FindBreakLocationFromAddress(frame->pc()); 10954 if (break_location_iterator.IsExit()) { 10955 // We are within the return sequence. At the momemt it is not possible to 10956 // get a source position which is consistent with the current scope chain. 10957 // Thus all nested with, catch and block contexts are skipped and we only 10958 // provide the function scope. 10959 if (scope_info->HasContext()) { 10960 context_ = Handle<Context>(context_->declaration_context(), isolate_); 10961 } else { 10962 while (context_->closure() == *function_) { 10963 context_ = Handle<Context>(context_->previous(), isolate_); 10964 } 10965 } 10966 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info); 10967 } else { 10968 // Reparse the code and analyze the scopes. 10969 ZoneScope zone_scope(isolate, DELETE_ON_EXIT); 10970 Handle<Script> script(Script::cast(shared_info->script())); 10971 Scope* scope = NULL; 10972 10973 // Check whether we are in global, eval or function code. 10974 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 10975 if (scope_info->Type() != FUNCTION_SCOPE) { 10976 // Global or eval code. 10977 CompilationInfo info(script); 10978 if (scope_info->Type() == GLOBAL_SCOPE) { 10979 info.MarkAsGlobal(); 10980 } else { 10981 ASSERT(scope_info->Type() == EVAL_SCOPE); 10982 info.MarkAsEval(); 10983 info.SetCallingContext(Handle<Context>(function_->context())); 10984 } 10985 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) { 10986 scope = info.function()->scope(); 10987 } 10988 } else { 10989 // Function code 10990 CompilationInfo info(shared_info); 10991 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) { 10992 scope = info.function()->scope(); 10993 } 10994 } 10995 10996 // Retrieve the scope chain for the current position. 10997 if (scope != NULL) { 10998 int source_position = shared_info->code()->SourcePosition(frame_->pc()); 10999 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); 11000 } else { 11001 // A failed reparse indicates that the preparser has diverged from the 11002 // parser or that the preparse data given to the initial parse has been 11003 // faulty. We fail in debug mode but in release mode we only provide the 11004 // information we get from the context chain but nothing about 11005 // completely stack allocated scopes or stack allocated locals. 11006 UNREACHABLE(); 11007 } 11008 } 11009 } 11010 11011 // More scopes? 11012 bool Done() { return context_.is_null(); } 11013 11014 // Move to the next scope. 11015 void Next() { 11016 ScopeType scope_type = Type(); 11017 if (scope_type == ScopeTypeGlobal) { 11018 // The global scope is always the last in the chain. 11019 ASSERT(context_->IsGlobalContext()); 11020 context_ = Handle<Context>(); 11021 return; 11022 } 11023 if (nested_scope_chain_.is_empty()) { 11024 context_ = Handle<Context>(context_->previous(), isolate_); 11025 } else { 11026 if (nested_scope_chain_.last()->HasContext()) { 11027 ASSERT(context_->previous() != NULL); 11028 context_ = Handle<Context>(context_->previous(), isolate_); 11029 } 11030 nested_scope_chain_.RemoveLast(); 11031 } 11032 } 11033 11034 // Return the type of the current scope. 11035 ScopeType Type() { 11036 if (!nested_scope_chain_.is_empty()) { 11037 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); 11038 switch (scope_info->Type()) { 11039 case FUNCTION_SCOPE: 11040 ASSERT(context_->IsFunctionContext() || 11041 !scope_info->HasContext()); 11042 return ScopeTypeLocal; 11043 case MODULE_SCOPE: 11044 ASSERT(context_->IsModuleContext()); 11045 return ScopeTypeModule; 11046 case GLOBAL_SCOPE: 11047 ASSERT(context_->IsGlobalContext()); 11048 return ScopeTypeGlobal; 11049 case WITH_SCOPE: 11050 ASSERT(context_->IsWithContext()); 11051 return ScopeTypeWith; 11052 case CATCH_SCOPE: 11053 ASSERT(context_->IsCatchContext()); 11054 return ScopeTypeCatch; 11055 case BLOCK_SCOPE: 11056 ASSERT(!scope_info->HasContext() || 11057 context_->IsBlockContext()); 11058 return ScopeTypeBlock; 11059 case EVAL_SCOPE: 11060 UNREACHABLE(); 11061 } 11062 } 11063 if (context_->IsGlobalContext()) { 11064 ASSERT(context_->global()->IsGlobalObject()); 11065 return ScopeTypeGlobal; 11066 } 11067 if (context_->IsFunctionContext()) { 11068 return ScopeTypeClosure; 11069 } 11070 if (context_->IsCatchContext()) { 11071 return ScopeTypeCatch; 11072 } 11073 if (context_->IsBlockContext()) { 11074 return ScopeTypeBlock; 11075 } 11076 if (context_->IsModuleContext()) { 11077 return ScopeTypeModule; 11078 } 11079 ASSERT(context_->IsWithContext()); 11080 return ScopeTypeWith; 11081 } 11082 11083 // Return the JavaScript object with the content of the current scope. 11084 Handle<JSObject> ScopeObject() { 11085 switch (Type()) { 11086 case ScopeIterator::ScopeTypeGlobal: 11087 return Handle<JSObject>(CurrentContext()->global()); 11088 case ScopeIterator::ScopeTypeLocal: 11089 // Materialize the content of the local scope into a JSObject. 11090 ASSERT(nested_scope_chain_.length() == 1); 11091 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); 11092 case ScopeIterator::ScopeTypeWith: 11093 // Return the with object. 11094 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); 11095 case ScopeIterator::ScopeTypeCatch: 11096 return MaterializeCatchScope(isolate_, CurrentContext()); 11097 case ScopeIterator::ScopeTypeClosure: 11098 // Materialize the content of the closure scope into a JSObject. 11099 return MaterializeClosure(isolate_, CurrentContext()); 11100 case ScopeIterator::ScopeTypeBlock: 11101 return MaterializeBlockScope(isolate_, CurrentContext()); 11102 case ScopeIterator::ScopeTypeModule: 11103 return MaterializeModuleScope(isolate_, CurrentContext()); 11104 } 11105 UNREACHABLE(); 11106 return Handle<JSObject>(); 11107 } 11108 11109 Handle<ScopeInfo> CurrentScopeInfo() { 11110 if (!nested_scope_chain_.is_empty()) { 11111 return nested_scope_chain_.last(); 11112 } else if (context_->IsBlockContext()) { 11113 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); 11114 } else if (context_->IsFunctionContext()) { 11115 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); 11116 } 11117 return Handle<ScopeInfo>::null(); 11118 } 11119 11120 // Return the context for this scope. For the local context there might not 11121 // be an actual context. 11122 Handle<Context> CurrentContext() { 11123 if (Type() == ScopeTypeGlobal || 11124 nested_scope_chain_.is_empty()) { 11125 return context_; 11126 } else if (nested_scope_chain_.last()->HasContext()) { 11127 return context_; 11128 } else { 11129 return Handle<Context>(); 11130 } 11131 } 11132 11133 #ifdef DEBUG 11134 // Debug print of the content of the current scope. 11135 void DebugPrint() { 11136 switch (Type()) { 11137 case ScopeIterator::ScopeTypeGlobal: 11138 PrintF("Global:\n"); 11139 CurrentContext()->Print(); 11140 break; 11141 11142 case ScopeIterator::ScopeTypeLocal: { 11143 PrintF("Local:\n"); 11144 function_->shared()->scope_info()->Print(); 11145 if (!CurrentContext().is_null()) { 11146 CurrentContext()->Print(); 11147 if (CurrentContext()->has_extension()) { 11148 Handle<Object> extension(CurrentContext()->extension()); 11149 if (extension->IsJSContextExtensionObject()) { 11150 extension->Print(); 11151 } 11152 } 11153 } 11154 break; 11155 } 11156 11157 case ScopeIterator::ScopeTypeWith: 11158 PrintF("With:\n"); 11159 CurrentContext()->extension()->Print(); 11160 break; 11161 11162 case ScopeIterator::ScopeTypeCatch: 11163 PrintF("Catch:\n"); 11164 CurrentContext()->extension()->Print(); 11165 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(); 11166 break; 11167 11168 case ScopeIterator::ScopeTypeClosure: 11169 PrintF("Closure:\n"); 11170 CurrentContext()->Print(); 11171 if (CurrentContext()->has_extension()) { 11172 Handle<Object> extension(CurrentContext()->extension()); 11173 if (extension->IsJSContextExtensionObject()) { 11174 extension->Print(); 11175 } 11176 } 11177 break; 11178 11179 default: 11180 UNREACHABLE(); 11181 } 11182 PrintF("\n"); 11183 } 11184 #endif 11185 11186 private: 11187 Isolate* isolate_; 11188 JavaScriptFrame* frame_; 11189 int inlined_jsframe_index_; 11190 Handle<JSFunction> function_; 11191 Handle<Context> context_; 11192 List<Handle<ScopeInfo> > nested_scope_chain_; 11193 11194 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 11195 }; 11196 11197 11198 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { 11199 HandleScope scope(isolate); 11200 ASSERT(args.length() == 2); 11201 11202 // Check arguments. 11203 Object* check; 11204 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11205 RUNTIME_ARGUMENTS(isolate, args)); 11206 if (!maybe_check->ToObject(&check)) return maybe_check; 11207 } 11208 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 11209 11210 // Get the frame where the debugging is performed. 11211 StackFrame::Id id = UnwrapFrameId(wrapped_id); 11212 JavaScriptFrameIterator it(isolate, id); 11213 JavaScriptFrame* frame = it.frame(); 11214 11215 // Count the visible scopes. 11216 int n = 0; 11217 for (ScopeIterator it(isolate, frame, 0); 11218 !it.Done(); 11219 it.Next()) { 11220 n++; 11221 } 11222 11223 return Smi::FromInt(n); 11224 } 11225 11226 11227 static const int kScopeDetailsTypeIndex = 0; 11228 static const int kScopeDetailsObjectIndex = 1; 11229 static const int kScopeDetailsSize = 2; 11230 11231 // Return an array with scope details 11232 // args[0]: number: break id 11233 // args[1]: number: frame index 11234 // args[2]: number: inlined frame index 11235 // args[3]: number: scope index 11236 // 11237 // The array returned contains the following information: 11238 // 0: Scope type 11239 // 1: Scope object 11240 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { 11241 HandleScope scope(isolate); 11242 ASSERT(args.length() == 4); 11243 11244 // Check arguments. 11245 Object* check; 11246 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11247 RUNTIME_ARGUMENTS(isolate, args)); 11248 if (!maybe_check->ToObject(&check)) return maybe_check; 11249 } 11250 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 11251 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 11252 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 11253 11254 // Get the frame where the debugging is performed. 11255 StackFrame::Id id = UnwrapFrameId(wrapped_id); 11256 JavaScriptFrameIterator frame_it(isolate, id); 11257 JavaScriptFrame* frame = frame_it.frame(); 11258 11259 // Find the requested scope. 11260 int n = 0; 11261 ScopeIterator it(isolate, frame, inlined_jsframe_index); 11262 for (; !it.Done() && n < index; it.Next()) { 11263 n++; 11264 } 11265 if (it.Done()) { 11266 return isolate->heap()->undefined_value(); 11267 } 11268 11269 // Calculate the size of the result. 11270 int details_size = kScopeDetailsSize; 11271 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 11272 11273 // Fill in scope details. 11274 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type())); 11275 Handle<JSObject> scope_object = it.ScopeObject(); 11276 RETURN_IF_EMPTY_HANDLE(isolate, scope_object); 11277 details->set(kScopeDetailsObjectIndex, *scope_object); 11278 11279 return *isolate->factory()->NewJSArrayWithElements(details); 11280 } 11281 11282 11283 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { 11284 HandleScope scope(isolate); 11285 ASSERT(args.length() == 0); 11286 11287 #ifdef DEBUG 11288 // Print the scopes for the top frame. 11289 StackFrameLocator locator; 11290 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 11291 for (ScopeIterator it(isolate, frame, 0); 11292 !it.Done(); 11293 it.Next()) { 11294 it.DebugPrint(); 11295 } 11296 #endif 11297 return isolate->heap()->undefined_value(); 11298 } 11299 11300 11301 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) { 11302 HandleScope scope(isolate); 11303 ASSERT(args.length() == 1); 11304 11305 // Check arguments. 11306 Object* result; 11307 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 11308 RUNTIME_ARGUMENTS(isolate, args)); 11309 if (!maybe_result->ToObject(&result)) return maybe_result; 11310 } 11311 11312 // Count all archived V8 threads. 11313 int n = 0; 11314 for (ThreadState* thread = 11315 isolate->thread_manager()->FirstThreadStateInUse(); 11316 thread != NULL; 11317 thread = thread->Next()) { 11318 n++; 11319 } 11320 11321 // Total number of threads is current thread and archived threads. 11322 return Smi::FromInt(n + 1); 11323 } 11324 11325 11326 static const int kThreadDetailsCurrentThreadIndex = 0; 11327 static const int kThreadDetailsThreadIdIndex = 1; 11328 static const int kThreadDetailsSize = 2; 11329 11330 // Return an array with thread details 11331 // args[0]: number: break id 11332 // args[1]: number: thread index 11333 // 11334 // The array returned contains the following information: 11335 // 0: Is current thread? 11336 // 1: Thread id 11337 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { 11338 HandleScope scope(isolate); 11339 ASSERT(args.length() == 2); 11340 11341 // Check arguments. 11342 Object* check; 11343 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11344 RUNTIME_ARGUMENTS(isolate, args)); 11345 if (!maybe_check->ToObject(&check)) return maybe_check; 11346 } 11347 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 11348 11349 // Allocate array for result. 11350 Handle<FixedArray> details = 11351 isolate->factory()->NewFixedArray(kThreadDetailsSize); 11352 11353 // Thread index 0 is current thread. 11354 if (index == 0) { 11355 // Fill the details. 11356 details->set(kThreadDetailsCurrentThreadIndex, 11357 isolate->heap()->true_value()); 11358 details->set(kThreadDetailsThreadIdIndex, 11359 Smi::FromInt(ThreadId::Current().ToInteger())); 11360 } else { 11361 // Find the thread with the requested index. 11362 int n = 1; 11363 ThreadState* thread = 11364 isolate->thread_manager()->FirstThreadStateInUse(); 11365 while (index != n && thread != NULL) { 11366 thread = thread->Next(); 11367 n++; 11368 } 11369 if (thread == NULL) { 11370 return isolate->heap()->undefined_value(); 11371 } 11372 11373 // Fill the details. 11374 details->set(kThreadDetailsCurrentThreadIndex, 11375 isolate->heap()->false_value()); 11376 details->set(kThreadDetailsThreadIdIndex, 11377 Smi::FromInt(thread->id().ToInteger())); 11378 } 11379 11380 // Convert to JS array and return. 11381 return *isolate->factory()->NewJSArrayWithElements(details); 11382 } 11383 11384 11385 // Sets the disable break state 11386 // args[0]: disable break state 11387 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) { 11388 HandleScope scope(isolate); 11389 ASSERT(args.length() == 1); 11390 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); 11391 isolate->debug()->set_disable_break(disable_break); 11392 return isolate->heap()->undefined_value(); 11393 } 11394 11395 11396 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { 11397 HandleScope scope(isolate); 11398 ASSERT(args.length() == 1); 11399 11400 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 11401 Handle<SharedFunctionInfo> shared(fun->shared()); 11402 // Find the number of break points 11403 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared); 11404 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); 11405 // Return array as JS array 11406 return *isolate->factory()->NewJSArrayWithElements( 11407 Handle<FixedArray>::cast(break_locations)); 11408 } 11409 11410 11411 // Set a break point in a function 11412 // args[0]: function 11413 // args[1]: number: break source position (within the function source) 11414 // args[2]: number: break point object 11415 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { 11416 HandleScope scope(isolate); 11417 ASSERT(args.length() == 3); 11418 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 11419 Handle<SharedFunctionInfo> shared(fun->shared()); 11420 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 11421 RUNTIME_ASSERT(source_position >= 0); 11422 Handle<Object> break_point_object_arg = args.at<Object>(2); 11423 11424 // Set break point. 11425 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, 11426 &source_position); 11427 11428 return Smi::FromInt(source_position); 11429 } 11430 11431 11432 Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate, 11433 Handle<Script> script, 11434 int position) { 11435 // Iterate the heap looking for SharedFunctionInfo generated from the 11436 // script. The inner most SharedFunctionInfo containing the source position 11437 // for the requested break point is found. 11438 // NOTE: This might require several heap iterations. If the SharedFunctionInfo 11439 // which is found is not compiled it is compiled and the heap is iterated 11440 // again as the compilation might create inner functions from the newly 11441 // compiled function and the actual requested break point might be in one of 11442 // these functions. 11443 bool done = false; 11444 // The current candidate for the source position: 11445 int target_start_position = RelocInfo::kNoPosition; 11446 Handle<SharedFunctionInfo> target; 11447 while (!done) { 11448 { // Extra scope for iterator and no-allocation. 11449 isolate->heap()->EnsureHeapIsIterable(); 11450 AssertNoAllocation no_alloc_during_heap_iteration; 11451 HeapIterator iterator; 11452 for (HeapObject* obj = iterator.next(); 11453 obj != NULL; obj = iterator.next()) { 11454 if (obj->IsSharedFunctionInfo()) { 11455 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj)); 11456 if (shared->script() == *script) { 11457 // If the SharedFunctionInfo found has the requested script data and 11458 // contains the source position it is a candidate. 11459 int start_position = shared->function_token_position(); 11460 if (start_position == RelocInfo::kNoPosition) { 11461 start_position = shared->start_position(); 11462 } 11463 if (start_position <= position && 11464 position <= shared->end_position()) { 11465 // If there is no candidate or this function is within the current 11466 // candidate this is the new candidate. 11467 if (target.is_null()) { 11468 target_start_position = start_position; 11469 target = shared; 11470 } else { 11471 if (target_start_position == start_position && 11472 shared->end_position() == target->end_position()) { 11473 // If a top-level function contain only one function 11474 // declartion the source for the top-level and the 11475 // function is the same. In that case prefer the non 11476 // top-level function. 11477 if (!shared->is_toplevel()) { 11478 target_start_position = start_position; 11479 target = shared; 11480 } 11481 } else if (target_start_position <= start_position && 11482 shared->end_position() <= target->end_position()) { 11483 // This containment check includes equality as a function 11484 // inside a top-level function can share either start or end 11485 // position with the top-level function. 11486 target_start_position = start_position; 11487 target = shared; 11488 } 11489 } 11490 } 11491 } 11492 } 11493 } // End for loop. 11494 } // End No allocation scope. 11495 11496 if (target.is_null()) { 11497 return isolate->heap()->undefined_value(); 11498 } 11499 11500 // If the candidate found is compiled we are done. NOTE: when lazy 11501 // compilation of inner functions is introduced some additional checking 11502 // needs to be done here to compile inner functions. 11503 done = target->is_compiled(); 11504 if (!done) { 11505 // If the candidate is not compiled compile it to reveal any inner 11506 // functions which might contain the requested source position. 11507 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION); 11508 } 11509 } // End while loop. 11510 11511 return *target; 11512 } 11513 11514 11515 // Changes the state of a break point in a script and returns source position 11516 // where break point was set. NOTE: Regarding performance see the NOTE for 11517 // GetScriptFromScriptData. 11518 // args[0]: script to set break point in 11519 // args[1]: number: break source position (within the script source) 11520 // args[2]: number: break point object 11521 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { 11522 HandleScope scope(isolate); 11523 ASSERT(args.length() == 3); 11524 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 11525 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 11526 RUNTIME_ASSERT(source_position >= 0); 11527 Handle<Object> break_point_object_arg = args.at<Object>(2); 11528 11529 // Get the script from the script wrapper. 11530 RUNTIME_ASSERT(wrapper->value()->IsScript()); 11531 Handle<Script> script(Script::cast(wrapper->value())); 11532 11533 Object* result = Runtime::FindSharedFunctionInfoInScript( 11534 isolate, script, source_position); 11535 if (!result->IsUndefined()) { 11536 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); 11537 // Find position within function. The script position might be before the 11538 // source position of the first function. 11539 int position; 11540 if (shared->start_position() > source_position) { 11541 position = 0; 11542 } else { 11543 position = source_position - shared->start_position(); 11544 } 11545 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position); 11546 position += shared->start_position(); 11547 return Smi::FromInt(position); 11548 } 11549 return isolate->heap()->undefined_value(); 11550 } 11551 11552 11553 // Clear a break point 11554 // args[0]: number: break point object 11555 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { 11556 HandleScope scope(isolate); 11557 ASSERT(args.length() == 1); 11558 Handle<Object> break_point_object_arg = args.at<Object>(0); 11559 11560 // Clear break point. 11561 isolate->debug()->ClearBreakPoint(break_point_object_arg); 11562 11563 return isolate->heap()->undefined_value(); 11564 } 11565 11566 11567 // Change the state of break on exceptions. 11568 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 11569 // args[1]: Boolean indicating on/off. 11570 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { 11571 HandleScope scope(isolate); 11572 ASSERT(args.length() == 2); 11573 RUNTIME_ASSERT(args[0]->IsNumber()); 11574 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 11575 11576 // If the number doesn't match an enum value, the ChangeBreakOnException 11577 // function will default to affecting caught exceptions. 11578 ExceptionBreakType type = 11579 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 11580 // Update break point state. 11581 isolate->debug()->ChangeBreakOnException(type, enable); 11582 return isolate->heap()->undefined_value(); 11583 } 11584 11585 11586 // Returns the state of break on exceptions 11587 // args[0]: boolean indicating uncaught exceptions 11588 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { 11589 HandleScope scope(isolate); 11590 ASSERT(args.length() == 1); 11591 RUNTIME_ASSERT(args[0]->IsNumber()); 11592 11593 ExceptionBreakType type = 11594 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 11595 bool result = isolate->debug()->IsBreakOnException(type); 11596 return Smi::FromInt(result); 11597 } 11598 11599 11600 // Prepare for stepping 11601 // args[0]: break id for checking execution state 11602 // args[1]: step action from the enumeration StepAction 11603 // args[2]: number of times to perform the step, for step out it is the number 11604 // of frames to step down. 11605 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { 11606 HandleScope scope(isolate); 11607 ASSERT(args.length() == 3); 11608 // Check arguments. 11609 Object* check; 11610 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11611 RUNTIME_ARGUMENTS(isolate, args)); 11612 if (!maybe_check->ToObject(&check)) return maybe_check; 11613 } 11614 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 11615 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 11616 } 11617 11618 // Get the step action and check validity. 11619 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 11620 if (step_action != StepIn && 11621 step_action != StepNext && 11622 step_action != StepOut && 11623 step_action != StepInMin && 11624 step_action != StepMin) { 11625 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 11626 } 11627 11628 // Get the number of steps. 11629 int step_count = NumberToInt32(args[2]); 11630 if (step_count < 1) { 11631 return isolate->Throw(isolate->heap()->illegal_argument_symbol()); 11632 } 11633 11634 // Clear all current stepping setup. 11635 isolate->debug()->ClearStepping(); 11636 11637 // Prepare step. 11638 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), 11639 step_count); 11640 return isolate->heap()->undefined_value(); 11641 } 11642 11643 11644 // Clear all stepping set by PrepareStep. 11645 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { 11646 HandleScope scope(isolate); 11647 ASSERT(args.length() == 0); 11648 isolate->debug()->ClearStepping(); 11649 return isolate->heap()->undefined_value(); 11650 } 11651 11652 11653 // Creates a copy of the with context chain. The copy of the context chain is 11654 // is linked to the function context supplied. 11655 static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate, 11656 Handle<JSFunction> function, 11657 Handle<Context> base, 11658 JavaScriptFrame* frame, 11659 int inlined_jsframe_index) { 11660 HandleScope scope(isolate); 11661 List<Handle<ScopeInfo> > scope_chain; 11662 List<Handle<Context> > context_chain; 11663 11664 ScopeIterator it(isolate, frame, inlined_jsframe_index); 11665 for (; it.Type() != ScopeIterator::ScopeTypeGlobal && 11666 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) { 11667 ASSERT(!it.Done()); 11668 scope_chain.Add(it.CurrentScopeInfo()); 11669 context_chain.Add(it.CurrentContext()); 11670 } 11671 11672 // At the end of the chain. Return the base context to link to. 11673 Handle<Context> context = base; 11674 11675 // Iteratively copy and or materialize the nested contexts. 11676 while (!scope_chain.is_empty()) { 11677 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast(); 11678 Handle<Context> current = context_chain.RemoveLast(); 11679 ASSERT(!(scope_info->HasContext() & current.is_null())); 11680 11681 if (scope_info->Type() == CATCH_SCOPE) { 11682 Handle<String> name(String::cast(current->extension())); 11683 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX)); 11684 context = 11685 isolate->factory()->NewCatchContext(function, 11686 context, 11687 name, 11688 thrown_object); 11689 } else if (scope_info->Type() == BLOCK_SCOPE) { 11690 // Materialize the contents of the block scope into a JSObject. 11691 Handle<JSObject> block_scope_object = 11692 MaterializeBlockScope(isolate, current); 11693 if (block_scope_object.is_null()) { 11694 return Handle<Context>::null(); 11695 } 11696 // Allocate a new function context for the debug evaluation and set the 11697 // extension object. 11698 Handle<Context> new_context = 11699 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, 11700 function); 11701 new_context->set_extension(*block_scope_object); 11702 new_context->set_previous(*context); 11703 context = new_context; 11704 } else { 11705 ASSERT(scope_info->Type() == WITH_SCOPE); 11706 ASSERT(current->IsWithContext()); 11707 Handle<JSObject> extension(JSObject::cast(current->extension())); 11708 context = 11709 isolate->factory()->NewWithContext(function, context, extension); 11710 } 11711 } 11712 11713 return scope.CloseAndEscape(context); 11714 } 11715 11716 11717 // Helper function to find or create the arguments object for 11718 // Runtime_DebugEvaluate. 11719 static Handle<Object> GetArgumentsObject(Isolate* isolate, 11720 JavaScriptFrame* frame, 11721 FrameInspector* frame_inspector, 11722 Handle<ScopeInfo> scope_info, 11723 Handle<Context> function_context) { 11724 // Try to find the value of 'arguments' to pass as parameter. If it is not 11725 // found (that is the debugged function does not reference 'arguments' and 11726 // does not support eval) then create an 'arguments' object. 11727 int index; 11728 if (scope_info->StackLocalCount() > 0) { 11729 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol()); 11730 if (index != -1) { 11731 return Handle<Object>(frame->GetExpression(index), isolate); 11732 } 11733 } 11734 11735 if (scope_info->HasHeapAllocatedLocals()) { 11736 VariableMode mode; 11737 InitializationFlag init_flag; 11738 index = scope_info->ContextSlotIndex( 11739 isolate->heap()->arguments_symbol(), &mode, &init_flag); 11740 if (index != -1) { 11741 return Handle<Object>(function_context->get(index), isolate); 11742 } 11743 } 11744 11745 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction())); 11746 int length = frame_inspector->GetParametersCount(); 11747 Handle<JSObject> arguments = 11748 isolate->factory()->NewArgumentsObject(function, length); 11749 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); 11750 11751 AssertNoAllocation no_gc; 11752 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 11753 for (int i = 0; i < length; i++) { 11754 array->set(i, frame_inspector->GetParameter(i), mode); 11755 } 11756 arguments->set_elements(*array); 11757 return arguments; 11758 } 11759 11760 11761 static const char kSourceStr[] = 11762 "(function(arguments,__source__){return eval(__source__);})"; 11763 11764 11765 // Evaluate a piece of JavaScript in the context of a stack frame for 11766 // debugging. This is accomplished by creating a new context which in its 11767 // extension part has all the parameters and locals of the function on the 11768 // stack frame. A function which calls eval with the code to evaluate is then 11769 // compiled in this context and called in this context. As this context 11770 // replaces the context of the function on the stack frame a new (empty) 11771 // function is created as well to be used as the closure for the context. 11772 // This function and the context acts as replacements for the function on the 11773 // stack frame presenting the same view of the values of parameters and 11774 // local variables as if the piece of JavaScript was evaluated at the point 11775 // where the function on the stack frame is currently stopped. 11776 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { 11777 HandleScope scope(isolate); 11778 11779 // Check the execution state and decode arguments frame and source to be 11780 // evaluated. 11781 ASSERT(args.length() == 6); 11782 Object* check_result; 11783 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( 11784 RUNTIME_ARGUMENTS(isolate, args)); 11785 if (!maybe_check_result->ToObject(&check_result)) { 11786 return maybe_check_result; 11787 } 11788 } 11789 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 11790 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 11791 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 11792 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); 11793 Handle<Object> additional_context(args[5]); 11794 11795 // Handle the processing of break. 11796 DisableBreak disable_break_save(disable_break); 11797 11798 // Get the frame where the debugging is performed. 11799 StackFrame::Id id = UnwrapFrameId(wrapped_id); 11800 JavaScriptFrameIterator it(isolate, id); 11801 JavaScriptFrame* frame = it.frame(); 11802 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 11803 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11804 Handle<ScopeInfo> scope_info(function->shared()->scope_info()); 11805 11806 // Traverse the saved contexts chain to find the active context for the 11807 // selected frame. 11808 SaveContext* save = FindSavedContextForFrame(isolate, frame); 11809 11810 SaveContext savex(isolate); 11811 isolate->set_context(*(save->context())); 11812 11813 // Create the (empty) function replacing the function on the stack frame for 11814 // the purpose of evaluating in the context created below. It is important 11815 // that this function does not describe any parameters and local variables 11816 // in the context. If it does then this will cause problems with the lookup 11817 // in Context::Lookup, where context slots for parameters and local variables 11818 // are looked at before the extension object. 11819 Handle<JSFunction> go_between = 11820 isolate->factory()->NewFunction(isolate->factory()->empty_string(), 11821 isolate->factory()->undefined_value()); 11822 go_between->set_context(function->context()); 11823 #ifdef DEBUG 11824 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info()); 11825 ASSERT(go_between_scope_info->ParameterCount() == 0); 11826 ASSERT(go_between_scope_info->ContextLocalCount() == 0); 11827 #endif 11828 11829 // Materialize the content of the local scope into a JSObject. 11830 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector( 11831 isolate, frame, &frame_inspector); 11832 RETURN_IF_EMPTY_HANDLE(isolate, local_scope); 11833 11834 // Allocate a new context for the debug evaluation and set the extension 11835 // object build. 11836 Handle<Context> context = 11837 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS, 11838 go_between); 11839 context->set_extension(*local_scope); 11840 // Copy any with contexts present and chain them in front of this context. 11841 Handle<Context> frame_context(Context::cast(frame->context())); 11842 Handle<Context> function_context; 11843 // Get the function's context if it has one. 11844 if (scope_info->HasContext()) { 11845 function_context = Handle<Context>(frame_context->declaration_context()); 11846 } 11847 context = CopyNestedScopeContextChain(isolate, 11848 go_between, 11849 context, 11850 frame, 11851 inlined_jsframe_index); 11852 11853 if (additional_context->IsJSObject()) { 11854 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context); 11855 context = 11856 isolate->factory()->NewWithContext(go_between, context, extension); 11857 } 11858 11859 // Wrap the evaluation statement in a new function compiled in the newly 11860 // created context. The function has one parameter which has to be called 11861 // 'arguments'. This it to have access to what would have been 'arguments' in 11862 // the function being debugged. 11863 // function(arguments,__source__) {return eval(__source__);} 11864 11865 Handle<String> function_source = 11866 isolate->factory()->NewStringFromAscii( 11867 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1)); 11868 11869 // Currently, the eval code will be executed in non-strict mode, 11870 // even in the strict code context. 11871 Handle<SharedFunctionInfo> shared = 11872 Compiler::CompileEval(function_source, 11873 context, 11874 context->IsGlobalContext(), 11875 CLASSIC_MODE, 11876 RelocInfo::kNoPosition); 11877 if (shared.is_null()) return Failure::Exception(); 11878 Handle<JSFunction> compiled_function = 11879 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); 11880 11881 // Invoke the result of the compilation to get the evaluation function. 11882 bool has_pending_exception; 11883 Handle<Object> receiver(frame->receiver(), isolate); 11884 Handle<Object> evaluation_function = 11885 Execution::Call(compiled_function, receiver, 0, NULL, 11886 &has_pending_exception); 11887 if (has_pending_exception) return Failure::Exception(); 11888 11889 Handle<Object> arguments = GetArgumentsObject(isolate, 11890 frame, 11891 &frame_inspector, 11892 scope_info, 11893 function_context); 11894 11895 // Invoke the evaluation function and return the result. 11896 Handle<Object> argv[] = { arguments, source }; 11897 Handle<Object> result = 11898 Execution::Call(Handle<JSFunction>::cast(evaluation_function), 11899 receiver, 11900 ARRAY_SIZE(argv), 11901 argv, 11902 &has_pending_exception); 11903 if (has_pending_exception) return Failure::Exception(); 11904 11905 // Skip the global proxy as it has no properties and always delegates to the 11906 // real global object. 11907 if (result->IsJSGlobalProxy()) { 11908 result = Handle<JSObject>(JSObject::cast(result->GetPrototype())); 11909 } 11910 11911 return *result; 11912 } 11913 11914 11915 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { 11916 HandleScope scope(isolate); 11917 11918 // Check the execution state and decode arguments frame and source to be 11919 // evaluated. 11920 ASSERT(args.length() == 4); 11921 Object* check_result; 11922 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState( 11923 RUNTIME_ARGUMENTS(isolate, args)); 11924 if (!maybe_check_result->ToObject(&check_result)) { 11925 return maybe_check_result; 11926 } 11927 } 11928 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 11929 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); 11930 Handle<Object> additional_context(args[3]); 11931 11932 // Handle the processing of break. 11933 DisableBreak disable_break_save(disable_break); 11934 11935 // Enter the top context from before the debugger was invoked. 11936 SaveContext save(isolate); 11937 SaveContext* top = &save; 11938 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { 11939 top = top->prev(); 11940 } 11941 if (top != NULL) { 11942 isolate->set_context(*top->context()); 11943 } 11944 11945 // Get the global context now set to the top context from before the 11946 // debugger was invoked. 11947 Handle<Context> context = isolate->global_context(); 11948 11949 bool is_global = true; 11950 11951 if (additional_context->IsJSObject()) { 11952 // Create a new with context with the additional context information between 11953 // the context of the debugged function and the eval code to be executed. 11954 context = isolate->factory()->NewWithContext( 11955 Handle<JSFunction>(context->closure()), 11956 context, 11957 Handle<JSObject>::cast(additional_context)); 11958 is_global = false; 11959 } 11960 11961 // Compile the source to be evaluated. 11962 // Currently, the eval code will be executed in non-strict mode, 11963 // even in the strict code context. 11964 Handle<SharedFunctionInfo> shared = 11965 Compiler::CompileEval(source, 11966 context, 11967 is_global, 11968 CLASSIC_MODE, 11969 RelocInfo::kNoPosition); 11970 if (shared.is_null()) return Failure::Exception(); 11971 Handle<JSFunction> compiled_function = 11972 Handle<JSFunction>( 11973 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 11974 context)); 11975 11976 // Invoke the result of the compilation to get the evaluation function. 11977 bool has_pending_exception; 11978 Handle<Object> receiver = isolate->global(); 11979 Handle<Object> result = 11980 Execution::Call(compiled_function, receiver, 0, NULL, 11981 &has_pending_exception); 11982 // Clear the oneshot breakpoints so that the debugger does not step further. 11983 isolate->debug()->ClearStepping(); 11984 if (has_pending_exception) return Failure::Exception(); 11985 return *result; 11986 } 11987 11988 11989 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { 11990 HandleScope scope(isolate); 11991 ASSERT(args.length() == 0); 11992 11993 // Fill the script objects. 11994 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); 11995 11996 // Convert the script objects to proper JS objects. 11997 for (int i = 0; i < instances->length(); i++) { 11998 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 11999 // Get the script wrapper in a local handle before calling GetScriptWrapper, 12000 // because using 12001 // instances->set(i, *GetScriptWrapper(script)) 12002 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 12003 // already have dereferenced the instances handle. 12004 Handle<JSValue> wrapper = GetScriptWrapper(script); 12005 instances->set(i, *wrapper); 12006 } 12007 12008 // Return result as a JS array. 12009 Handle<JSObject> result = 12010 isolate->factory()->NewJSObject(isolate->array_function()); 12011 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances); 12012 return *result; 12013 } 12014 12015 12016 // Helper function used by Runtime_DebugReferencedBy below. 12017 static int DebugReferencedBy(HeapIterator* iterator, 12018 JSObject* target, 12019 Object* instance_filter, int max_references, 12020 FixedArray* instances, int instances_size, 12021 JSFunction* arguments_function) { 12022 NoHandleAllocation ha; 12023 AssertNoAllocation no_alloc; 12024 12025 // Iterate the heap. 12026 int count = 0; 12027 JSObject* last = NULL; 12028 HeapObject* heap_obj = NULL; 12029 while (((heap_obj = iterator->next()) != NULL) && 12030 (max_references == 0 || count < max_references)) { 12031 // Only look at all JSObjects. 12032 if (heap_obj->IsJSObject()) { 12033 // Skip context extension objects and argument arrays as these are 12034 // checked in the context of functions using them. 12035 JSObject* obj = JSObject::cast(heap_obj); 12036 if (obj->IsJSContextExtensionObject() || 12037 obj->map()->constructor() == arguments_function) { 12038 continue; 12039 } 12040 12041 // Check if the JS object has a reference to the object looked for. 12042 if (obj->ReferencesObject(target)) { 12043 // Check instance filter if supplied. This is normally used to avoid 12044 // references from mirror objects (see Runtime_IsInPrototypeChain). 12045 if (!instance_filter->IsUndefined()) { 12046 Object* V = obj; 12047 while (true) { 12048 Object* prototype = V->GetPrototype(); 12049 if (prototype->IsNull()) { 12050 break; 12051 } 12052 if (instance_filter == prototype) { 12053 obj = NULL; // Don't add this object. 12054 break; 12055 } 12056 V = prototype; 12057 } 12058 } 12059 12060 if (obj != NULL) { 12061 // Valid reference found add to instance array if supplied an update 12062 // count. 12063 if (instances != NULL && count < instances_size) { 12064 instances->set(count, obj); 12065 } 12066 last = obj; 12067 count++; 12068 } 12069 } 12070 } 12071 } 12072 12073 // Check for circular reference only. This can happen when the object is only 12074 // referenced from mirrors and has a circular reference in which case the 12075 // object is not really alive and would have been garbage collected if not 12076 // referenced from the mirror. 12077 if (count == 1 && last == target) { 12078 count = 0; 12079 } 12080 12081 // Return the number of referencing objects found. 12082 return count; 12083 } 12084 12085 12086 // Scan the heap for objects with direct references to an object 12087 // args[0]: the object to find references to 12088 // args[1]: constructor function for instances to exclude (Mirror) 12089 // args[2]: the the maximum number of objects to return 12090 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { 12091 ASSERT(args.length() == 3); 12092 12093 // First perform a full GC in order to avoid references from dead objects. 12094 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 12095 "%DebugReferencedBy"); 12096 // The heap iterator reserves the right to do a GC to make the heap iterable. 12097 // Due to the GC above we know it won't need to do that, but it seems cleaner 12098 // to get the heap iterator constructed before we start having unprotected 12099 // Object* locals that are not protected by handles. 12100 12101 // Check parameters. 12102 CONVERT_ARG_CHECKED(JSObject, target, 0); 12103 Object* instance_filter = args[1]; 12104 RUNTIME_ASSERT(instance_filter->IsUndefined() || 12105 instance_filter->IsJSObject()); 12106 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 12107 RUNTIME_ASSERT(max_references >= 0); 12108 12109 12110 // Get the constructor function for context extension and arguments array. 12111 JSObject* arguments_boilerplate = 12112 isolate->context()->global_context()->arguments_boilerplate(); 12113 JSFunction* arguments_function = 12114 JSFunction::cast(arguments_boilerplate->map()->constructor()); 12115 12116 // Get the number of referencing objects. 12117 int count; 12118 HeapIterator heap_iterator; 12119 count = DebugReferencedBy(&heap_iterator, 12120 target, instance_filter, max_references, 12121 NULL, 0, arguments_function); 12122 12123 // Allocate an array to hold the result. 12124 Object* object; 12125 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count); 12126 if (!maybe_object->ToObject(&object)) return maybe_object; 12127 } 12128 FixedArray* instances = FixedArray::cast(object); 12129 12130 // Fill the referencing objects. 12131 // AllocateFixedArray above does not make the heap non-iterable. 12132 ASSERT(HEAP->IsHeapIterable()); 12133 HeapIterator heap_iterator2; 12134 count = DebugReferencedBy(&heap_iterator2, 12135 target, instance_filter, max_references, 12136 instances, count, arguments_function); 12137 12138 // Return result as JS array. 12139 Object* result; 12140 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( 12141 isolate->context()->global_context()->array_function()); 12142 if (!maybe_result->ToObject(&result)) return maybe_result; 12143 return JSArray::cast(result)->SetContent(instances); 12144 } 12145 12146 12147 // Helper function used by Runtime_DebugConstructedBy below. 12148 static int DebugConstructedBy(HeapIterator* iterator, 12149 JSFunction* constructor, 12150 int max_references, 12151 FixedArray* instances, 12152 int instances_size) { 12153 AssertNoAllocation no_alloc; 12154 12155 // Iterate the heap. 12156 int count = 0; 12157 HeapObject* heap_obj = NULL; 12158 while (((heap_obj = iterator->next()) != NULL) && 12159 (max_references == 0 || count < max_references)) { 12160 // Only look at all JSObjects. 12161 if (heap_obj->IsJSObject()) { 12162 JSObject* obj = JSObject::cast(heap_obj); 12163 if (obj->map()->constructor() == constructor) { 12164 // Valid reference found add to instance array if supplied an update 12165 // count. 12166 if (instances != NULL && count < instances_size) { 12167 instances->set(count, obj); 12168 } 12169 count++; 12170 } 12171 } 12172 } 12173 12174 // Return the number of referencing objects found. 12175 return count; 12176 } 12177 12178 12179 // Scan the heap for objects constructed by a specific function. 12180 // args[0]: the constructor to find instances of 12181 // args[1]: the the maximum number of objects to return 12182 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) { 12183 ASSERT(args.length() == 2); 12184 12185 // First perform a full GC in order to avoid dead objects. 12186 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 12187 "%DebugConstructedBy"); 12188 12189 // Check parameters. 12190 CONVERT_ARG_CHECKED(JSFunction, constructor, 0); 12191 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 12192 RUNTIME_ASSERT(max_references >= 0); 12193 12194 // Get the number of referencing objects. 12195 int count; 12196 HeapIterator heap_iterator; 12197 count = DebugConstructedBy(&heap_iterator, 12198 constructor, 12199 max_references, 12200 NULL, 12201 0); 12202 12203 // Allocate an array to hold the result. 12204 Object* object; 12205 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count); 12206 if (!maybe_object->ToObject(&object)) return maybe_object; 12207 } 12208 FixedArray* instances = FixedArray::cast(object); 12209 12210 ASSERT(HEAP->IsHeapIterable()); 12211 // Fill the referencing objects. 12212 HeapIterator heap_iterator2; 12213 count = DebugConstructedBy(&heap_iterator2, 12214 constructor, 12215 max_references, 12216 instances, 12217 count); 12218 12219 // Return result as JS array. 12220 Object* result; 12221 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( 12222 isolate->context()->global_context()->array_function()); 12223 if (!maybe_result->ToObject(&result)) return maybe_result; 12224 } 12225 return JSArray::cast(result)->SetContent(instances); 12226 } 12227 12228 12229 // Find the effective prototype object as returned by __proto__. 12230 // args[0]: the object to find the prototype for. 12231 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) { 12232 ASSERT(args.length() == 1); 12233 12234 CONVERT_ARG_CHECKED(JSObject, obj, 0); 12235 12236 // Use the __proto__ accessor. 12237 return Accessors::ObjectPrototype.getter(obj, NULL); 12238 } 12239 12240 12241 // Patches script source (should be called upon BeforeCompile event). 12242 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { 12243 HandleScope scope(isolate); 12244 ASSERT(args.length() == 2); 12245 12246 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 12247 Handle<String> source(String::cast(args[1])); 12248 12249 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); 12250 Handle<Script> script(Script::cast(script_wrapper->value())); 12251 12252 int compilation_state = Smi::cast(script->compilation_state())->value(); 12253 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); 12254 script->set_source(*source); 12255 12256 return isolate->heap()->undefined_value(); 12257 } 12258 12259 12260 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { 12261 ASSERT(args.length() == 0); 12262 CPU::DebugBreak(); 12263 return isolate->heap()->undefined_value(); 12264 } 12265 12266 12267 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { 12268 #ifdef DEBUG 12269 HandleScope scope(isolate); 12270 ASSERT(args.length() == 1); 12271 // Get the function and make sure it is compiled. 12272 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 12273 Handle<SharedFunctionInfo> shared(func->shared()); 12274 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) { 12275 return Failure::Exception(); 12276 } 12277 func->code()->PrintLn(); 12278 #endif // DEBUG 12279 return isolate->heap()->undefined_value(); 12280 } 12281 12282 12283 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { 12284 #ifdef DEBUG 12285 HandleScope scope(isolate); 12286 ASSERT(args.length() == 1); 12287 // Get the function and make sure it is compiled. 12288 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 12289 Handle<SharedFunctionInfo> shared(func->shared()); 12290 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) { 12291 return Failure::Exception(); 12292 } 12293 shared->construct_stub()->PrintLn(); 12294 #endif // DEBUG 12295 return isolate->heap()->undefined_value(); 12296 } 12297 12298 12299 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) { 12300 NoHandleAllocation ha; 12301 ASSERT(args.length() == 1); 12302 12303 CONVERT_ARG_CHECKED(JSFunction, f, 0); 12304 return f->shared()->inferred_name(); 12305 } 12306 12307 12308 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, 12309 Script* script, 12310 FixedArray* buffer) { 12311 AssertNoAllocation no_allocations; 12312 int counter = 0; 12313 int buffer_size = buffer->length(); 12314 for (HeapObject* obj = iterator->next(); 12315 obj != NULL; 12316 obj = iterator->next()) { 12317 ASSERT(obj != NULL); 12318 if (!obj->IsSharedFunctionInfo()) { 12319 continue; 12320 } 12321 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 12322 if (shared->script() != script) { 12323 continue; 12324 } 12325 if (counter < buffer_size) { 12326 buffer->set(counter, shared); 12327 } 12328 counter++; 12329 } 12330 return counter; 12331 } 12332 12333 // For a script finds all SharedFunctionInfo's in the heap that points 12334 // to this script. Returns JSArray of SharedFunctionInfo wrapped 12335 // in OpaqueReferences. 12336 RUNTIME_FUNCTION(MaybeObject*, 12337 Runtime_LiveEditFindSharedFunctionInfosForScript) { 12338 ASSERT(args.length() == 1); 12339 HandleScope scope(isolate); 12340 CONVERT_ARG_CHECKED(JSValue, script_value, 0); 12341 12342 12343 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); 12344 12345 const int kBufferSize = 32; 12346 12347 Handle<FixedArray> array; 12348 array = isolate->factory()->NewFixedArray(kBufferSize); 12349 int number; 12350 { 12351 isolate->heap()->EnsureHeapIsIterable(); 12352 AssertNoAllocation no_allocations; 12353 HeapIterator heap_iterator; 12354 Script* scr = *script; 12355 FixedArray* arr = *array; 12356 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 12357 } 12358 if (number > kBufferSize) { 12359 array = isolate->factory()->NewFixedArray(number); 12360 isolate->heap()->EnsureHeapIsIterable(); 12361 AssertNoAllocation no_allocations; 12362 HeapIterator heap_iterator; 12363 Script* scr = *script; 12364 FixedArray* arr = *array; 12365 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 12366 } 12367 12368 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); 12369 result->set_length(Smi::FromInt(number)); 12370 12371 LiveEdit::WrapSharedFunctionInfos(result); 12372 12373 return *result; 12374 } 12375 12376 // For a script calculates compilation information about all its functions. 12377 // The script source is explicitly specified by the second argument. 12378 // The source of the actual script is not used, however it is important that 12379 // all generated code keeps references to this particular instance of script. 12380 // Returns a JSArray of compilation infos. The array is ordered so that 12381 // each function with all its descendant is always stored in a continues range 12382 // with the function itself going first. The root function is a script function. 12383 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { 12384 ASSERT(args.length() == 2); 12385 HandleScope scope(isolate); 12386 CONVERT_ARG_CHECKED(JSValue, script, 0); 12387 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 12388 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 12389 12390 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); 12391 12392 if (isolate->has_pending_exception()) { 12393 return Failure::Exception(); 12394 } 12395 12396 return result; 12397 } 12398 12399 // Changes the source of the script to a new_source. 12400 // If old_script_name is provided (i.e. is a String), also creates a copy of 12401 // the script with its original source and sends notification to debugger. 12402 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) { 12403 ASSERT(args.length() == 3); 12404 HandleScope scope(isolate); 12405 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); 12406 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); 12407 Handle<Object> old_script_name(args[2], isolate); 12408 12409 RUNTIME_ASSERT(original_script_value->value()->IsScript()); 12410 Handle<Script> original_script(Script::cast(original_script_value->value())); 12411 12412 Object* old_script = LiveEdit::ChangeScriptSource(original_script, 12413 new_source, 12414 old_script_name); 12415 12416 if (old_script->IsScript()) { 12417 Handle<Script> script_handle(Script::cast(old_script)); 12418 return *(GetScriptWrapper(script_handle)); 12419 } else { 12420 return isolate->heap()->null_value(); 12421 } 12422 } 12423 12424 12425 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) { 12426 ASSERT(args.length() == 1); 12427 HandleScope scope(isolate); 12428 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); 12429 return LiveEdit::FunctionSourceUpdated(shared_info); 12430 } 12431 12432 12433 // Replaces code of SharedFunctionInfo with a new one. 12434 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) { 12435 ASSERT(args.length() == 2); 12436 HandleScope scope(isolate); 12437 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); 12438 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); 12439 12440 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); 12441 } 12442 12443 // Connects SharedFunctionInfo to another script. 12444 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { 12445 ASSERT(args.length() == 2); 12446 HandleScope scope(isolate); 12447 Handle<Object> function_object(args[0], isolate); 12448 Handle<Object> script_object(args[1], isolate); 12449 12450 if (function_object->IsJSValue()) { 12451 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); 12452 if (script_object->IsJSValue()) { 12453 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); 12454 Script* script = Script::cast(JSValue::cast(*script_object)->value()); 12455 script_object = Handle<Object>(script, isolate); 12456 } 12457 12458 LiveEdit::SetFunctionScript(function_wrapper, script_object); 12459 } else { 12460 // Just ignore this. We may not have a SharedFunctionInfo for some functions 12461 // and we check it in this function. 12462 } 12463 12464 return isolate->heap()->undefined_value(); 12465 } 12466 12467 12468 // In a code of a parent function replaces original function as embedded object 12469 // with a substitution one. 12470 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { 12471 ASSERT(args.length() == 3); 12472 HandleScope scope(isolate); 12473 12474 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); 12475 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); 12476 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); 12477 12478 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, 12479 subst_wrapper); 12480 12481 return isolate->heap()->undefined_value(); 12482 } 12483 12484 12485 // Updates positions of a shared function info (first parameter) according 12486 // to script source change. Text change is described in second parameter as 12487 // array of groups of 3 numbers: 12488 // (change_begin, change_end, change_end_new_position). 12489 // Each group describes a change in text; groups are sorted by change_begin. 12490 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { 12491 ASSERT(args.length() == 2); 12492 HandleScope scope(isolate); 12493 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 12494 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); 12495 12496 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); 12497 } 12498 12499 12500 // For array of SharedFunctionInfo's (each wrapped in JSValue) 12501 // checks that none of them have activations on stacks (of any thread). 12502 // Returns array of the same length with corresponding results of 12503 // LiveEdit::FunctionPatchabilityStatus type. 12504 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { 12505 ASSERT(args.length() == 2); 12506 HandleScope scope(isolate); 12507 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 12508 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); 12509 12510 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); 12511 } 12512 12513 // Compares 2 strings line-by-line, then token-wise and returns diff in form 12514 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list 12515 // of diff chunks. 12516 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { 12517 ASSERT(args.length() == 2); 12518 HandleScope scope(isolate); 12519 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); 12520 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); 12521 12522 return *LiveEdit::CompareStrings(s1, s2); 12523 } 12524 12525 12526 // A testing entry. Returns statement position which is the closest to 12527 // source_position. 12528 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { 12529 ASSERT(args.length() == 2); 12530 HandleScope scope(isolate); 12531 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 12532 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12533 12534 Handle<Code> code(function->code(), isolate); 12535 12536 if (code->kind() != Code::FUNCTION && 12537 code->kind() != Code::OPTIMIZED_FUNCTION) { 12538 return isolate->heap()->undefined_value(); 12539 } 12540 12541 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); 12542 int closest_pc = 0; 12543 int distance = kMaxInt; 12544 while (!it.done()) { 12545 int statement_position = static_cast<int>(it.rinfo()->data()); 12546 // Check if this break point is closer that what was previously found. 12547 if (source_position <= statement_position && 12548 statement_position - source_position < distance) { 12549 closest_pc = 12550 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 12551 distance = statement_position - source_position; 12552 // Check whether we can't get any closer. 12553 if (distance == 0) break; 12554 } 12555 it.next(); 12556 } 12557 12558 return Smi::FromInt(closest_pc); 12559 } 12560 12561 12562 // Calls specified function with or without entering the debugger. 12563 // This is used in unit tests to run code as if debugger is entered or simply 12564 // to have a stack with C++ frame in the middle. 12565 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) { 12566 ASSERT(args.length() == 2); 12567 HandleScope scope(isolate); 12568 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 12569 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); 12570 12571 Handle<Object> result; 12572 bool pending_exception; 12573 { 12574 if (without_debugger) { 12575 result = Execution::Call(function, isolate->global(), 0, NULL, 12576 &pending_exception); 12577 } else { 12578 EnterDebugger enter_debugger; 12579 result = Execution::Call(function, isolate->global(), 0, NULL, 12580 &pending_exception); 12581 } 12582 } 12583 if (!pending_exception) { 12584 return *result; 12585 } else { 12586 return Failure::Exception(); 12587 } 12588 } 12589 12590 12591 // Sets a v8 flag. 12592 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) { 12593 CONVERT_ARG_CHECKED(String, arg, 0); 12594 SmartArrayPointer<char> flags = 12595 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 12596 FlagList::SetFlagsFromString(*flags, StrLength(*flags)); 12597 return isolate->heap()->undefined_value(); 12598 } 12599 12600 12601 // Performs a GC. 12602 // Presently, it only does a full GC. 12603 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) { 12604 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); 12605 return isolate->heap()->undefined_value(); 12606 } 12607 12608 12609 // Gets the current heap usage. 12610 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { 12611 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 12612 if (!Smi::IsValid(usage)) { 12613 return *isolate->factory()->NewNumberFromInt(usage); 12614 } 12615 return Smi::FromInt(usage); 12616 } 12617 12618 12619 // Captures a live object list from the present heap. 12620 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) { 12621 #ifdef LIVE_OBJECT_LIST 12622 return isolate->heap()->true_value(); 12623 #else 12624 return isolate->heap()->false_value(); 12625 #endif 12626 } 12627 12628 12629 // Captures a live object list from the present heap. 12630 RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) { 12631 #ifdef LIVE_OBJECT_LIST 12632 return LiveObjectList::Capture(); 12633 #else 12634 return isolate->heap()->undefined_value(); 12635 #endif 12636 } 12637 12638 12639 // Deletes the specified live object list. 12640 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) { 12641 #ifdef LIVE_OBJECT_LIST 12642 CONVERT_SMI_ARG_CHECKED(id, 0); 12643 bool success = LiveObjectList::Delete(id); 12644 return isolate->heap()->ToBoolean(success); 12645 #else 12646 return isolate->heap()->undefined_value(); 12647 #endif 12648 } 12649 12650 12651 // Generates the response to a debugger request for a dump of the objects 12652 // contained in the difference between the captured live object lists 12653 // specified by id1 and id2. 12654 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be 12655 // dumped. 12656 RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) { 12657 #ifdef LIVE_OBJECT_LIST 12658 HandleScope scope; 12659 CONVERT_SMI_ARG_CHECKED(id1, 0); 12660 CONVERT_SMI_ARG_CHECKED(id2, 1); 12661 CONVERT_SMI_ARG_CHECKED(start, 2); 12662 CONVERT_SMI_ARG_CHECKED(count, 3); 12663 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4); 12664 EnterDebugger enter_debugger; 12665 return LiveObjectList::Dump(id1, id2, start, count, filter_obj); 12666 #else 12667 return isolate->heap()->undefined_value(); 12668 #endif 12669 } 12670 12671 12672 // Gets the specified object as requested by the debugger. 12673 // This is only used for obj ids shown in live object lists. 12674 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) { 12675 #ifdef LIVE_OBJECT_LIST 12676 CONVERT_SMI_ARG_CHECKED(obj_id, 0); 12677 Object* result = LiveObjectList::GetObj(obj_id); 12678 return result; 12679 #else 12680 return isolate->heap()->undefined_value(); 12681 #endif 12682 } 12683 12684 12685 // Gets the obj id for the specified address if valid. 12686 // This is only used for obj ids shown in live object lists. 12687 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) { 12688 #ifdef LIVE_OBJECT_LIST 12689 HandleScope scope; 12690 CONVERT_ARG_HANDLE_CHECKED(String, address, 0); 12691 Object* result = LiveObjectList::GetObjId(address); 12692 return result; 12693 #else 12694 return isolate->heap()->undefined_value(); 12695 #endif 12696 } 12697 12698 12699 // Gets the retainers that references the specified object alive. 12700 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) { 12701 #ifdef LIVE_OBJECT_LIST 12702 HandleScope scope; 12703 CONVERT_SMI_ARG_CHECKED(obj_id, 0); 12704 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject()); 12705 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean()); 12706 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi()); 12707 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi()); 12708 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5); 12709 12710 Handle<JSObject> instance_filter; 12711 if (args[1]->IsJSObject()) { 12712 instance_filter = args.at<JSObject>(1); 12713 } 12714 bool verbose = false; 12715 if (args[2]->IsBoolean()) { 12716 verbose = args[2]->IsTrue(); 12717 } 12718 int start = 0; 12719 if (args[3]->IsSmi()) { 12720 start = args.smi_at(3); 12721 } 12722 int limit = Smi::kMaxValue; 12723 if (args[4]->IsSmi()) { 12724 limit = args.smi_at(4); 12725 } 12726 12727 return LiveObjectList::GetObjRetainers(obj_id, 12728 instance_filter, 12729 verbose, 12730 start, 12731 limit, 12732 filter_obj); 12733 #else 12734 return isolate->heap()->undefined_value(); 12735 #endif 12736 } 12737 12738 12739 // Gets the reference path between 2 objects. 12740 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) { 12741 #ifdef LIVE_OBJECT_LIST 12742 HandleScope scope; 12743 CONVERT_SMI_ARG_CHECKED(obj_id1, 0); 12744 CONVERT_SMI_ARG_CHECKED(obj_id2, 1); 12745 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject()); 12746 12747 Handle<JSObject> instance_filter; 12748 if (args[2]->IsJSObject()) { 12749 instance_filter = args.at<JSObject>(2); 12750 } 12751 12752 Object* result = 12753 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter); 12754 return result; 12755 #else 12756 return isolate->heap()->undefined_value(); 12757 #endif 12758 } 12759 12760 12761 // Generates the response to a debugger request for a list of all 12762 // previously captured live object lists. 12763 RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) { 12764 #ifdef LIVE_OBJECT_LIST 12765 CONVERT_SMI_ARG_CHECKED(start, 0); 12766 CONVERT_SMI_ARG_CHECKED(count, 1); 12767 return LiveObjectList::Info(start, count); 12768 #else 12769 return isolate->heap()->undefined_value(); 12770 #endif 12771 } 12772 12773 12774 // Gets a dump of the specified object as requested by the debugger. 12775 // This is only used for obj ids shown in live object lists. 12776 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) { 12777 #ifdef LIVE_OBJECT_LIST 12778 HandleScope scope; 12779 CONVERT_SMI_ARG_CHECKED(obj_id, 0); 12780 Object* result = LiveObjectList::PrintObj(obj_id); 12781 return result; 12782 #else 12783 return isolate->heap()->undefined_value(); 12784 #endif 12785 } 12786 12787 12788 // Resets and releases all previously captured live object lists. 12789 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) { 12790 #ifdef LIVE_OBJECT_LIST 12791 LiveObjectList::Reset(); 12792 return isolate->heap()->undefined_value(); 12793 #else 12794 return isolate->heap()->undefined_value(); 12795 #endif 12796 } 12797 12798 12799 // Generates the response to a debugger request for a summary of the types 12800 // of objects in the difference between the captured live object lists 12801 // specified by id1 and id2. 12802 // If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be 12803 // summarized. 12804 RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) { 12805 #ifdef LIVE_OBJECT_LIST 12806 HandleScope scope; 12807 CONVERT_SMI_ARG_CHECKED(id1, 0); 12808 CONVERT_SMI_ARG_CHECKED(id2, 1); 12809 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2); 12810 12811 EnterDebugger enter_debugger; 12812 return LiveObjectList::Summarize(id1, id2, filter_obj); 12813 #else 12814 return isolate->heap()->undefined_value(); 12815 #endif 12816 } 12817 12818 #endif // ENABLE_DEBUGGER_SUPPORT 12819 12820 12821 RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) { 12822 NoHandleAllocation ha; 12823 v8::V8::ResumeProfiler(); 12824 return isolate->heap()->undefined_value(); 12825 } 12826 12827 12828 RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) { 12829 NoHandleAllocation ha; 12830 v8::V8::PauseProfiler(); 12831 return isolate->heap()->undefined_value(); 12832 } 12833 12834 12835 // Finds the script object from the script data. NOTE: This operation uses 12836 // heap traversal to find the function generated for the source position 12837 // for the requested break point. For lazily compiled functions several heap 12838 // traversals might be required rendering this operation as a rather slow 12839 // operation. However for setting break points which is normally done through 12840 // some kind of user interaction the performance is not crucial. 12841 static Handle<Object> Runtime_GetScriptFromScriptName( 12842 Handle<String> script_name) { 12843 // Scan the heap for Script objects to find the script with the requested 12844 // script data. 12845 Handle<Script> script; 12846 script_name->GetHeap()->EnsureHeapIsIterable(); 12847 AssertNoAllocation no_allocation_during_heap_iteration; 12848 HeapIterator iterator; 12849 HeapObject* obj = NULL; 12850 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 12851 // If a script is found check if it has the script data requested. 12852 if (obj->IsScript()) { 12853 if (Script::cast(obj)->name()->IsString()) { 12854 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 12855 script = Handle<Script>(Script::cast(obj)); 12856 } 12857 } 12858 } 12859 } 12860 12861 // If no script with the requested script data is found return undefined. 12862 if (script.is_null()) return FACTORY->undefined_value(); 12863 12864 // Return the script found. 12865 return GetScriptWrapper(script); 12866 } 12867 12868 12869 // Get the script object from script data. NOTE: Regarding performance 12870 // see the NOTE for GetScriptFromScriptData. 12871 // args[0]: script data for the script to find the source for 12872 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { 12873 HandleScope scope(isolate); 12874 12875 ASSERT(args.length() == 1); 12876 12877 CONVERT_ARG_CHECKED(String, script_name, 0); 12878 12879 // Find the requested script. 12880 Handle<Object> result = 12881 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 12882 return *result; 12883 } 12884 12885 12886 // Determines whether the given stack frame should be displayed in 12887 // a stack trace. The caller is the error constructor that asked 12888 // for the stack trace to be collected. The first time a construct 12889 // call to this function is encountered it is skipped. The seen_caller 12890 // in/out parameter is used to remember if the caller has been seen 12891 // yet. 12892 static bool ShowFrameInStackTrace(StackFrame* raw_frame, 12893 Object* caller, 12894 bool* seen_caller) { 12895 // Only display JS frames. 12896 if (!raw_frame->is_java_script()) { 12897 return false; 12898 } 12899 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 12900 Object* raw_fun = frame->function(); 12901 // Not sure when this can happen but skip it just in case. 12902 if (!raw_fun->IsJSFunction()) { 12903 return false; 12904 } 12905 if ((raw_fun == caller) && !(*seen_caller)) { 12906 *seen_caller = true; 12907 return false; 12908 } 12909 // Skip all frames until we've seen the caller. 12910 if (!(*seen_caller)) return false; 12911 // Also, skip non-visible built-in functions and any call with the builtins 12912 // object as receiver, so as to not reveal either the builtins object or 12913 // an internal function. 12914 // The --builtins-in-stack-traces command line flag allows including 12915 // internal call sites in the stack trace for debugging purposes. 12916 if (!FLAG_builtins_in_stack_traces) { 12917 JSFunction* fun = JSFunction::cast(raw_fun); 12918 if (frame->receiver()->IsJSBuiltinsObject() || 12919 (fun->IsBuiltin() && !fun->shared()->native())) { 12920 return false; 12921 } 12922 } 12923 return true; 12924 } 12925 12926 12927 // Collect the raw data for a stack trace. Returns an array of 4 12928 // element segments each containing a receiver, function, code and 12929 // native code offset. 12930 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { 12931 ASSERT_EQ(args.length(), 3); 12932 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 12933 Handle<Object> caller = args.at<Object>(1); 12934 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); 12935 12936 HandleScope scope(isolate); 12937 Factory* factory = isolate->factory(); 12938 12939 limit = Max(limit, 0); // Ensure that limit is not negative. 12940 int initial_size = Min(limit, 10); 12941 Handle<FixedArray> elements = 12942 factory->NewFixedArrayWithHoles(initial_size * 4); 12943 12944 StackFrameIterator iter(isolate); 12945 // If the caller parameter is a function we skip frames until we're 12946 // under it before starting to collect. 12947 bool seen_caller = !caller->IsJSFunction(); 12948 int cursor = 0; 12949 int frames_seen = 0; 12950 while (!iter.done() && frames_seen < limit) { 12951 StackFrame* raw_frame = iter.frame(); 12952 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) { 12953 frames_seen++; 12954 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); 12955 // Set initial size to the maximum inlining level + 1 for the outermost 12956 // function. 12957 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); 12958 frame->Summarize(&frames); 12959 for (int i = frames.length() - 1; i >= 0; i--) { 12960 if (cursor + 4 > elements->length()) { 12961 int new_capacity = JSObject::NewElementsCapacity(elements->length()); 12962 Handle<FixedArray> new_elements = 12963 factory->NewFixedArrayWithHoles(new_capacity); 12964 for (int i = 0; i < cursor; i++) { 12965 new_elements->set(i, elements->get(i)); 12966 } 12967 elements = new_elements; 12968 } 12969 ASSERT(cursor + 4 <= elements->length()); 12970 12971 Handle<Object> recv = frames[i].receiver(); 12972 Handle<JSFunction> fun = frames[i].function(); 12973 Handle<Code> code = frames[i].code(); 12974 Handle<Smi> offset(Smi::FromInt(frames[i].offset())); 12975 elements->set(cursor++, *recv); 12976 elements->set(cursor++, *fun); 12977 elements->set(cursor++, *code); 12978 elements->set(cursor++, *offset); 12979 } 12980 } 12981 iter.Advance(); 12982 } 12983 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); 12984 // Capture and attach a more detailed stack trace if necessary. 12985 isolate->CaptureAndSetCurrentStackTraceFor(error_object); 12986 result->set_length(Smi::FromInt(cursor)); 12987 return *result; 12988 } 12989 12990 12991 // Returns V8 version as a string. 12992 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { 12993 ASSERT_EQ(args.length(), 0); 12994 12995 NoHandleAllocation ha; 12996 12997 const char* version_string = v8::V8::GetVersion(); 12998 12999 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string), 13000 NOT_TENURED); 13001 } 13002 13003 13004 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { 13005 ASSERT(args.length() == 2); 13006 OS::PrintError("abort: %s\n", 13007 reinterpret_cast<char*>(args[0]) + args.smi_at(1)); 13008 isolate->PrintStack(); 13009 OS::Abort(); 13010 UNREACHABLE(); 13011 return NULL; 13012 } 13013 13014 13015 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { 13016 // This is only called from codegen, so checks might be more lax. 13017 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); 13018 Object* key = args[1]; 13019 13020 int finger_index = cache->finger_index(); 13021 Object* o = cache->get(finger_index); 13022 if (o == key) { 13023 // The fastest case: hit the same place again. 13024 return cache->get(finger_index + 1); 13025 } 13026 13027 for (int i = finger_index - 2; 13028 i >= JSFunctionResultCache::kEntriesIndex; 13029 i -= 2) { 13030 o = cache->get(i); 13031 if (o == key) { 13032 cache->set_finger_index(i); 13033 return cache->get(i + 1); 13034 } 13035 } 13036 13037 int size = cache->size(); 13038 ASSERT(size <= cache->length()); 13039 13040 for (int i = size - 2; i > finger_index; i -= 2) { 13041 o = cache->get(i); 13042 if (o == key) { 13043 cache->set_finger_index(i); 13044 return cache->get(i + 1); 13045 } 13046 } 13047 13048 // There is no value in the cache. Invoke the function and cache result. 13049 HandleScope scope(isolate); 13050 13051 Handle<JSFunctionResultCache> cache_handle(cache); 13052 Handle<Object> key_handle(key); 13053 Handle<Object> value; 13054 { 13055 Handle<JSFunction> factory(JSFunction::cast( 13056 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); 13057 // TODO(antonm): consider passing a receiver when constructing a cache. 13058 Handle<Object> receiver(isolate->global_context()->global()); 13059 // This handle is nor shared, nor used later, so it's safe. 13060 Handle<Object> argv[] = { key_handle }; 13061 bool pending_exception; 13062 value = Execution::Call(factory, 13063 receiver, 13064 ARRAY_SIZE(argv), 13065 argv, 13066 &pending_exception); 13067 if (pending_exception) return Failure::Exception(); 13068 } 13069 13070 #ifdef DEBUG 13071 if (FLAG_verify_heap) { 13072 cache_handle->JSFunctionResultCacheVerify(); 13073 } 13074 #endif 13075 13076 // Function invocation may have cleared the cache. Reread all the data. 13077 finger_index = cache_handle->finger_index(); 13078 size = cache_handle->size(); 13079 13080 // If we have spare room, put new data into it, otherwise evict post finger 13081 // entry which is likely to be the least recently used. 13082 int index = -1; 13083 if (size < cache_handle->length()) { 13084 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); 13085 index = size; 13086 } else { 13087 index = finger_index + JSFunctionResultCache::kEntrySize; 13088 if (index == cache_handle->length()) { 13089 index = JSFunctionResultCache::kEntriesIndex; 13090 } 13091 } 13092 13093 ASSERT(index % 2 == 0); 13094 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); 13095 ASSERT(index < cache_handle->length()); 13096 13097 cache_handle->set(index, *key_handle); 13098 cache_handle->set(index + 1, *value); 13099 cache_handle->set_finger_index(index); 13100 13101 #ifdef DEBUG 13102 if (FLAG_verify_heap) { 13103 cache_handle->JSFunctionResultCacheVerify(); 13104 } 13105 #endif 13106 13107 return *value; 13108 } 13109 13110 13111 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) { 13112 HandleScope scope(isolate); 13113 CONVERT_ARG_HANDLE_CHECKED(String, type, 0); 13114 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1); 13115 return *isolate->factory()->NewJSMessageObject( 13116 type, 13117 arguments, 13118 0, 13119 0, 13120 isolate->factory()->undefined_value(), 13121 isolate->factory()->undefined_value(), 13122 isolate->factory()->undefined_value()); 13123 } 13124 13125 13126 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) { 13127 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 13128 return message->type(); 13129 } 13130 13131 13132 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) { 13133 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 13134 return message->arguments(); 13135 } 13136 13137 13138 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { 13139 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 13140 return Smi::FromInt(message->start_position()); 13141 } 13142 13143 13144 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { 13145 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 13146 return message->script(); 13147 } 13148 13149 13150 #ifdef DEBUG 13151 // ListNatives is ONLY used by the fuzz-natives.js in debug mode 13152 // Exclude the code in release mode. 13153 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { 13154 ASSERT(args.length() == 0); 13155 HandleScope scope; 13156 #define COUNT_ENTRY(Name, argc, ressize) + 1 13157 int entry_count = 0 13158 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) 13159 INLINE_FUNCTION_LIST(COUNT_ENTRY) 13160 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY); 13161 #undef COUNT_ENTRY 13162 Factory* factory = isolate->factory(); 13163 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); 13164 int index = 0; 13165 bool inline_runtime_functions = false; 13166 #define ADD_ENTRY(Name, argc, ressize) \ 13167 { \ 13168 HandleScope inner; \ 13169 Handle<String> name; \ 13170 /* Inline runtime functions have an underscore in front of the name. */ \ 13171 if (inline_runtime_functions) { \ 13172 name = factory->NewStringFromAscii( \ 13173 Vector<const char>("_" #Name, StrLength("_" #Name))); \ 13174 } else { \ 13175 name = factory->NewStringFromAscii( \ 13176 Vector<const char>(#Name, StrLength(#Name))); \ 13177 } \ 13178 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ 13179 pair_elements->set(0, *name); \ 13180 pair_elements->set(1, Smi::FromInt(argc)); \ 13181 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ 13182 elements->set(index++, *pair); \ 13183 } 13184 inline_runtime_functions = false; 13185 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 13186 inline_runtime_functions = true; 13187 INLINE_FUNCTION_LIST(ADD_ENTRY) 13188 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) 13189 #undef ADD_ENTRY 13190 ASSERT_EQ(index, entry_count); 13191 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); 13192 return *result; 13193 } 13194 #endif 13195 13196 13197 RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) { 13198 ASSERT(args.length() == 2); 13199 CONVERT_ARG_CHECKED(String, format, 0); 13200 CONVERT_ARG_CHECKED(JSArray, elms, 1); 13201 String::FlatContent format_content = format->GetFlatContent(); 13202 RUNTIME_ASSERT(format_content.IsAscii()); 13203 Vector<const char> chars = format_content.ToAsciiVector(); 13204 LOGGER->LogRuntime(chars, elms); 13205 return isolate->heap()->undefined_value(); 13206 } 13207 13208 13209 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) { 13210 UNREACHABLE(); // implemented as macro in the parser 13211 return NULL; 13212 } 13213 13214 13215 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 13216 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \ 13217 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 13218 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 13219 } 13220 13221 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements) 13222 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements) 13223 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 13224 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 13225 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements) 13226 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) 13227 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements) 13228 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements) 13229 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements) 13230 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements) 13231 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements) 13232 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements) 13233 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements) 13234 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements) 13235 13236 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 13237 13238 13239 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { 13240 ASSERT(args.length() == 2); 13241 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 13242 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 13243 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 13244 } 13245 13246 // ---------------------------------------------------------------------------- 13247 // Implementation of Runtime 13248 13249 #define F(name, number_of_args, result_size) \ 13250 { Runtime::k##name, Runtime::RUNTIME, #name, \ 13251 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, 13252 13253 13254 #define I(name, number_of_args, result_size) \ 13255 { Runtime::kInline##name, Runtime::INLINE, \ 13256 "_" #name, NULL, number_of_args, result_size }, 13257 13258 static const Runtime::Function kIntrinsicFunctions[] = { 13259 RUNTIME_FUNCTION_LIST(F) 13260 INLINE_FUNCTION_LIST(I) 13261 INLINE_RUNTIME_FUNCTION_LIST(I) 13262 }; 13263 13264 13265 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap, 13266 Object* dictionary) { 13267 ASSERT(Isolate::Current()->heap() == heap); 13268 ASSERT(dictionary != NULL); 13269 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0); 13270 for (int i = 0; i < kNumFunctions; ++i) { 13271 Object* name_symbol; 13272 { MaybeObject* maybe_name_symbol = 13273 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name); 13274 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol; 13275 } 13276 StringDictionary* string_dictionary = StringDictionary::cast(dictionary); 13277 { MaybeObject* maybe_dictionary = string_dictionary->Add( 13278 String::cast(name_symbol), 13279 Smi::FromInt(i), 13280 PropertyDetails(NONE, NORMAL)); 13281 if (!maybe_dictionary->ToObject(&dictionary)) { 13282 // Non-recoverable failure. Calling code must restart heap 13283 // initialization. 13284 return maybe_dictionary; 13285 } 13286 } 13287 } 13288 return dictionary; 13289 } 13290 13291 13292 const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) { 13293 Heap* heap = name->GetHeap(); 13294 int entry = heap->intrinsic_function_names()->FindEntry(*name); 13295 if (entry != kNotFound) { 13296 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); 13297 int function_index = Smi::cast(smi_index)->value(); 13298 return &(kIntrinsicFunctions[function_index]); 13299 } 13300 return NULL; 13301 } 13302 13303 13304 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { 13305 return &(kIntrinsicFunctions[static_cast<int>(id)]); 13306 } 13307 13308 13309 void Runtime::PerformGC(Object* result) { 13310 Isolate* isolate = Isolate::Current(); 13311 Failure* failure = Failure::cast(result); 13312 if (failure->IsRetryAfterGC()) { 13313 if (isolate->heap()->new_space()->AddFreshPage()) { 13314 return; 13315 } 13316 13317 // Try to do a garbage collection; ignore it if it fails. The C 13318 // entry stub will throw an out-of-memory exception in that case. 13319 isolate->heap()->CollectGarbage(failure->allocation_space(), 13320 "Runtime::PerformGC"); 13321 } else { 13322 // Handle last resort GC and make sure to allow future allocations 13323 // to grow the heap without causing GCs (if possible). 13324 isolate->counters()->gc_last_resort_from_js()->Increment(); 13325 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13326 "Runtime::PerformGC"); 13327 } 13328 } 13329 13330 13331 } } // namespace v8::internal 13332