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 #include <limits> 30 31 #include "v8.h" 32 33 #include "accessors.h" 34 #include "api.h" 35 #include "arguments.h" 36 #include "bootstrapper.h" 37 #include "codegen.h" 38 #include "compilation-cache.h" 39 #include "compiler.h" 40 #include "cpu.h" 41 #include "cpu-profiler.h" 42 #include "dateparser-inl.h" 43 #include "debug.h" 44 #include "deoptimizer.h" 45 #include "date.h" 46 #include "execution.h" 47 #include "full-codegen.h" 48 #include "global-handles.h" 49 #include "isolate-inl.h" 50 #include "jsregexp.h" 51 #include "jsregexp-inl.h" 52 #include "json-parser.h" 53 #include "json-stringifier.h" 54 #include "liveedit.h" 55 #include "misc-intrinsics.h" 56 #include "parser.h" 57 #include "platform.h" 58 #include "runtime-profiler.h" 59 #include "runtime.h" 60 #include "scopeinfo.h" 61 #include "smart-pointers.h" 62 #include "string-search.h" 63 #include "stub-cache.h" 64 #include "uri.h" 65 #include "v8conversions.h" 66 #include "v8threads.h" 67 #include "vm-state-inl.h" 68 69 #ifdef V8_I18N_SUPPORT 70 #include "i18n.h" 71 #include "unicode/brkiter.h" 72 #include "unicode/calendar.h" 73 #include "unicode/coll.h" 74 #include "unicode/curramt.h" 75 #include "unicode/datefmt.h" 76 #include "unicode/dcfmtsym.h" 77 #include "unicode/decimfmt.h" 78 #include "unicode/dtfmtsym.h" 79 #include "unicode/dtptngen.h" 80 #include "unicode/locid.h" 81 #include "unicode/numfmt.h" 82 #include "unicode/numsys.h" 83 #include "unicode/smpdtfmt.h" 84 #include "unicode/timezone.h" 85 #include "unicode/uchar.h" 86 #include "unicode/ucol.h" 87 #include "unicode/ucurr.h" 88 #include "unicode/uloc.h" 89 #include "unicode/unum.h" 90 #include "unicode/uversion.h" 91 #endif 92 93 #ifndef _STLP_VENDOR_CSTD 94 // STLPort doesn't import fpclassify and isless into the std namespace. 95 using std::fpclassify; 96 using std::isless; 97 #endif 98 99 namespace v8 { 100 namespace internal { 101 102 103 #define RUNTIME_ASSERT(value) \ 104 if (!(value)) return isolate->ThrowIllegalOperation(); 105 106 // Cast the given object to a value of the specified type and store 107 // it in a variable with the given name. If the object is not of the 108 // expected type call IllegalOperation and return. 109 #define CONVERT_ARG_CHECKED(Type, name, index) \ 110 RUNTIME_ASSERT(args[index]->Is##Type()); \ 111 Type* name = Type::cast(args[index]); 112 113 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ 114 RUNTIME_ASSERT(args[index]->Is##Type()); \ 115 Handle<Type> name = args.at<Type>(index); 116 117 // Cast the given object to a boolean and store it in a variable with 118 // the given name. If the object is not a boolean call IllegalOperation 119 // and return. 120 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ 121 RUNTIME_ASSERT(args[index]->IsBoolean()); \ 122 bool name = args[index]->IsTrue(); 123 124 // Cast the given argument to a Smi and store its value in an int variable 125 // with the given name. If the argument is not a Smi call IllegalOperation 126 // and return. 127 #define CONVERT_SMI_ARG_CHECKED(name, index) \ 128 RUNTIME_ASSERT(args[index]->IsSmi()); \ 129 int name = args.smi_at(index); 130 131 // Cast the given argument to a double and store it in a variable with 132 // the given name. If the argument is not a number (as opposed to 133 // the number not-a-number) call IllegalOperation and return. 134 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ 135 RUNTIME_ASSERT(args[index]->IsNumber()); \ 136 double name = args.number_at(index); 137 138 // Call the specified converter on the object *comand store the result in 139 // a variable of the specified type with the given name. If the 140 // object is not a Number call IllegalOperation and return. 141 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 142 RUNTIME_ASSERT(obj->IsNumber()); \ 143 type name = NumberTo##Type(obj); 144 145 146 // Cast the given argument to PropertyDetails and store its value in a 147 // variable with the given name. If the argument is not a Smi call 148 // IllegalOperation and return. 149 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ 150 RUNTIME_ASSERT(args[index]->IsSmi()); \ 151 PropertyDetails name = PropertyDetails(Smi::cast(args[index])); 152 153 154 // Assert that the given argument has a valid value for a StrictModeFlag 155 // and store it in a StrictModeFlag variable with the given name. 156 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ 157 RUNTIME_ASSERT(args[index]->IsSmi()); \ 158 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \ 159 args.smi_at(index) == kNonStrictMode); \ 160 StrictModeFlag name = \ 161 static_cast<StrictModeFlag>(args.smi_at(index)); 162 163 164 // Assert that the given argument has a valid value for a LanguageMode 165 // and store it in a LanguageMode variable with the given name. 166 #define CONVERT_LANGUAGE_MODE_ARG(name, index) \ 167 ASSERT(args[index]->IsSmi()); \ 168 ASSERT(args.smi_at(index) == CLASSIC_MODE || \ 169 args.smi_at(index) == STRICT_MODE || \ 170 args.smi_at(index) == EXTENDED_MODE); \ 171 LanguageMode name = \ 172 static_cast<LanguageMode>(args.smi_at(index)); 173 174 175 static Handle<Map> ComputeObjectLiteralMap( 176 Handle<Context> context, 177 Handle<FixedArray> constant_properties, 178 bool* is_result_from_cache) { 179 Isolate* isolate = context->GetIsolate(); 180 int properties_length = constant_properties->length(); 181 int number_of_properties = properties_length / 2; 182 // Check that there are only internal strings and array indices among keys. 183 int number_of_string_keys = 0; 184 for (int p = 0; p != properties_length; p += 2) { 185 Object* key = constant_properties->get(p); 186 uint32_t element_index = 0; 187 if (key->IsInternalizedString()) { 188 number_of_string_keys++; 189 } else if (key->ToArrayIndex(&element_index)) { 190 // An index key does not require space in the property backing store. 191 number_of_properties--; 192 } else { 193 // Bail out as a non-internalized-string non-index key makes caching 194 // impossible. 195 // ASSERT to make sure that the if condition after the loop is false. 196 ASSERT(number_of_string_keys != number_of_properties); 197 break; 198 } 199 } 200 // If we only have internalized strings and array indices among keys then we 201 // can use the map cache in the native context. 202 const int kMaxKeys = 10; 203 if ((number_of_string_keys == number_of_properties) && 204 (number_of_string_keys < kMaxKeys)) { 205 // Create the fixed array with the key. 206 Handle<FixedArray> keys = 207 isolate->factory()->NewFixedArray(number_of_string_keys); 208 if (number_of_string_keys > 0) { 209 int index = 0; 210 for (int p = 0; p < properties_length; p += 2) { 211 Object* key = constant_properties->get(p); 212 if (key->IsInternalizedString()) { 213 keys->set(index++, key); 214 } 215 } 216 ASSERT(index == number_of_string_keys); 217 } 218 *is_result_from_cache = true; 219 return isolate->factory()->ObjectLiteralMapFromCache(context, keys); 220 } 221 *is_result_from_cache = false; 222 return isolate->factory()->CopyMap( 223 Handle<Map>(context->object_function()->initial_map()), 224 number_of_properties); 225 } 226 227 228 static Handle<Object> CreateLiteralBoilerplate( 229 Isolate* isolate, 230 Handle<FixedArray> literals, 231 Handle<FixedArray> constant_properties); 232 233 234 static Handle<Object> CreateObjectLiteralBoilerplate( 235 Isolate* isolate, 236 Handle<FixedArray> literals, 237 Handle<FixedArray> constant_properties, 238 bool should_have_fast_elements, 239 bool has_function_literal) { 240 // Get the native context from the literals array. This is the 241 // context in which the function was created and we use the object 242 // function from this context to create the object literal. We do 243 // not use the object function from the current native context 244 // because this might be the object function from another context 245 // which we should not have access to. 246 Handle<Context> context = 247 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals)); 248 249 // In case we have function literals, we want the object to be in 250 // slow properties mode for now. We don't go in the map cache because 251 // maps with constant functions can't be shared if the functions are 252 // not the same (which is the common case). 253 bool is_result_from_cache = false; 254 Handle<Map> map = has_function_literal 255 ? Handle<Map>(context->object_function()->initial_map()) 256 : ComputeObjectLiteralMap(context, 257 constant_properties, 258 &is_result_from_cache); 259 260 Handle<JSObject> boilerplate = 261 isolate->factory()->NewJSObjectFromMap( 262 map, isolate->heap()->GetPretenureMode()); 263 264 // Normalize the elements of the boilerplate to save space if needed. 265 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); 266 267 // Add the constant properties to the boilerplate. 268 int length = constant_properties->length(); 269 bool should_transform = 270 !is_result_from_cache && boilerplate->HasFastProperties(); 271 if (should_transform || has_function_literal) { 272 // Normalize the properties of object to avoid n^2 behavior 273 // when extending the object multiple properties. Indicate the number of 274 // properties to be added. 275 JSObject::NormalizeProperties( 276 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); 277 } 278 279 // TODO(verwaest): Support tracking representations in the boilerplate. 280 for (int index = 0; index < length; index +=2) { 281 Handle<Object> key(constant_properties->get(index+0), isolate); 282 Handle<Object> value(constant_properties->get(index+1), isolate); 283 if (value->IsFixedArray()) { 284 // The value contains the constant_properties of a 285 // simple object or array literal. 286 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 287 value = CreateLiteralBoilerplate(isolate, literals, array); 288 if (value.is_null()) return value; 289 } 290 Handle<Object> result; 291 uint32_t element_index = 0; 292 JSReceiver::StoreMode mode = value->IsJSObject() 293 ? JSReceiver::FORCE_FIELD 294 : JSReceiver::ALLOW_AS_CONSTANT; 295 if (key->IsInternalizedString()) { 296 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { 297 // Array index as string (uint32). 298 result = JSObject::SetOwnElement( 299 boilerplate, element_index, value, kNonStrictMode); 300 } else { 301 Handle<String> name(String::cast(*key)); 302 ASSERT(!name->AsArrayIndex(&element_index)); 303 result = JSObject::SetLocalPropertyIgnoreAttributes( 304 boilerplate, name, value, NONE, 305 Object::OPTIMAL_REPRESENTATION, mode); 306 } 307 } else if (key->ToArrayIndex(&element_index)) { 308 // Array index (uint32). 309 result = JSObject::SetOwnElement( 310 boilerplate, element_index, value, kNonStrictMode); 311 } else { 312 // Non-uint32 number. 313 ASSERT(key->IsNumber()); 314 double num = key->Number(); 315 char arr[100]; 316 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 317 const char* str = DoubleToCString(num, buffer); 318 Handle<String> name = 319 isolate->factory()->NewStringFromAscii(CStrVector(str)); 320 result = JSObject::SetLocalPropertyIgnoreAttributes( 321 boilerplate, name, value, NONE, 322 Object::OPTIMAL_REPRESENTATION, mode); 323 } 324 // If setting the property on the boilerplate throws an 325 // exception, the exception is converted to an empty handle in 326 // the handle based operations. In that case, we need to 327 // convert back to an exception. 328 if (result.is_null()) return result; 329 } 330 331 // Transform to fast properties if necessary. For object literals with 332 // containing function literals we defer this operation until after all 333 // computed properties have been assigned so that we can generate 334 // constant function properties. 335 if (should_transform && !has_function_literal) { 336 JSObject::TransformToFastProperties( 337 boilerplate, boilerplate->map()->unused_property_fields()); 338 } 339 340 return boilerplate; 341 } 342 343 344 MaybeObject* TransitionElements(Handle<Object> object, 345 ElementsKind to_kind, 346 Isolate* isolate) { 347 HandleScope scope(isolate); 348 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); 349 ElementsKind from_kind = 350 Handle<JSObject>::cast(object)->map()->elements_kind(); 351 if (Map::IsValidElementsTransition(from_kind, to_kind)) { 352 Handle<Object> result = JSObject::TransitionElementsKind( 353 Handle<JSObject>::cast(object), to_kind); 354 if (result.is_null()) return isolate->ThrowIllegalOperation(); 355 return *result; 356 } 357 return isolate->ThrowIllegalOperation(); 358 } 359 360 361 static const int kSmiLiteralMinimumLength = 1024; 362 363 364 Handle<Object> Runtime::CreateArrayLiteralBoilerplate( 365 Isolate* isolate, 366 Handle<FixedArray> literals, 367 Handle<FixedArray> elements) { 368 // Create the JSArray. 369 Handle<JSFunction> constructor( 370 JSFunction::NativeContextFromLiterals(*literals)->array_function()); 371 372 Handle<JSArray> object = Handle<JSArray>::cast( 373 isolate->factory()->NewJSObject( 374 constructor, isolate->heap()->GetPretenureMode())); 375 376 ElementsKind constant_elements_kind = 377 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value()); 378 Handle<FixedArrayBase> constant_elements_values( 379 FixedArrayBase::cast(elements->get(1))); 380 381 ASSERT(IsFastElementsKind(constant_elements_kind)); 382 Context* native_context = isolate->context()->native_context(); 383 Object* maybe_maps_array = native_context->js_array_maps(); 384 ASSERT(!maybe_maps_array->IsUndefined()); 385 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get( 386 constant_elements_kind); 387 ASSERT(maybe_map->IsMap()); 388 object->set_map(Map::cast(maybe_map)); 389 390 Handle<FixedArrayBase> copied_elements_values; 391 if (IsFastDoubleElementsKind(constant_elements_kind)) { 392 ASSERT(FLAG_smi_only_arrays); 393 copied_elements_values = isolate->factory()->CopyFixedDoubleArray( 394 Handle<FixedDoubleArray>::cast(constant_elements_values)); 395 } else { 396 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind)); 397 const bool is_cow = 398 (constant_elements_values->map() == 399 isolate->heap()->fixed_cow_array_map()); 400 if (is_cow) { 401 copied_elements_values = constant_elements_values; 402 #if DEBUG 403 Handle<FixedArray> fixed_array_values = 404 Handle<FixedArray>::cast(copied_elements_values); 405 for (int i = 0; i < fixed_array_values->length(); i++) { 406 ASSERT(!fixed_array_values->get(i)->IsFixedArray()); 407 } 408 #endif 409 } else { 410 Handle<FixedArray> fixed_array_values = 411 Handle<FixedArray>::cast(constant_elements_values); 412 Handle<FixedArray> fixed_array_values_copy = 413 isolate->factory()->CopyFixedArray(fixed_array_values); 414 copied_elements_values = fixed_array_values_copy; 415 for (int i = 0; i < fixed_array_values->length(); i++) { 416 Object* current = fixed_array_values->get(i); 417 if (current->IsFixedArray()) { 418 // The value contains the constant_properties of a 419 // simple object or array literal. 420 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); 421 Handle<Object> result = 422 CreateLiteralBoilerplate(isolate, literals, fa); 423 if (result.is_null()) return result; 424 fixed_array_values_copy->set(i, *result); 425 } 426 } 427 } 428 } 429 object->set_elements(*copied_elements_values); 430 object->set_length(Smi::FromInt(copied_elements_values->length())); 431 432 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is 433 // on or the object is larger than the threshold. 434 if (!FLAG_smi_only_arrays && 435 constant_elements_values->length() < kSmiLiteralMinimumLength) { 436 ElementsKind elements_kind = object->GetElementsKind(); 437 if (!IsFastObjectElementsKind(elements_kind)) { 438 if (IsFastHoleyElementsKind(elements_kind)) { 439 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS, 440 isolate)->IsFailure()); 441 } else { 442 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure()); 443 } 444 } 445 } 446 447 object->ValidateElements(); 448 return object; 449 } 450 451 452 static Handle<Object> CreateLiteralBoilerplate( 453 Isolate* isolate, 454 Handle<FixedArray> literals, 455 Handle<FixedArray> array) { 456 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 457 const bool kHasNoFunctionLiteral = false; 458 switch (CompileTimeValue::GetLiteralType(array)) { 459 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: 460 return CreateObjectLiteralBoilerplate(isolate, 461 literals, 462 elements, 463 true, 464 kHasNoFunctionLiteral); 465 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 466 return CreateObjectLiteralBoilerplate(isolate, 467 literals, 468 elements, 469 false, 470 kHasNoFunctionLiteral); 471 case CompileTimeValue::ARRAY_LITERAL: 472 return Runtime::CreateArrayLiteralBoilerplate( 473 isolate, literals, elements); 474 default: 475 UNREACHABLE(); 476 return Handle<Object>::null(); 477 } 478 } 479 480 481 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { 482 HandleScope scope(isolate); 483 ASSERT(args.length() == 4); 484 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 485 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 486 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2); 487 CONVERT_SMI_ARG_CHECKED(flags, 3); 488 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; 489 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; 490 491 // Check if boilerplate exists. If not, create it first. 492 Handle<Object> boilerplate(literals->get(literals_index), isolate); 493 if (*boilerplate == isolate->heap()->undefined_value()) { 494 boilerplate = CreateObjectLiteralBoilerplate(isolate, 495 literals, 496 constant_properties, 497 should_have_fast_elements, 498 has_function_literal); 499 RETURN_IF_EMPTY_HANDLE(isolate, boilerplate); 500 // Update the functions literal and return the boilerplate. 501 literals->set(literals_index, *boilerplate); 502 } 503 return JSObject::cast(*boilerplate)->DeepCopy(isolate); 504 } 505 506 507 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) { 508 HandleScope scope(isolate); 509 ASSERT(args.length() == 4); 510 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 511 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 512 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2); 513 CONVERT_SMI_ARG_CHECKED(flags, 3); 514 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; 515 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; 516 517 // Check if boilerplate exists. If not, create it first. 518 Handle<Object> boilerplate(literals->get(literals_index), isolate); 519 if (*boilerplate == isolate->heap()->undefined_value()) { 520 boilerplate = CreateObjectLiteralBoilerplate(isolate, 521 literals, 522 constant_properties, 523 should_have_fast_elements, 524 has_function_literal); 525 RETURN_IF_EMPTY_HANDLE(isolate, boilerplate); 526 // Update the functions literal and return the boilerplate. 527 literals->set(literals_index, *boilerplate); 528 } 529 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate)); 530 } 531 532 533 static Handle<AllocationSite> GetLiteralAllocationSite( 534 Isolate* isolate, 535 Handle<FixedArray> literals, 536 int literals_index, 537 Handle<FixedArray> elements) { 538 // Check if boilerplate exists. If not, create it first. 539 Handle<Object> literal_site(literals->get(literals_index), isolate); 540 Handle<AllocationSite> site; 541 if (*literal_site == isolate->heap()->undefined_value()) { 542 ASSERT(*elements != isolate->heap()->empty_fixed_array()); 543 Handle<Object> boilerplate = 544 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements); 545 if (boilerplate.is_null()) return site; 546 site = isolate->factory()->NewAllocationSite(); 547 site->set_transition_info(*boilerplate); 548 literals->set(literals_index, *site); 549 } else { 550 site = Handle<AllocationSite>::cast(literal_site); 551 } 552 553 return site; 554 } 555 556 557 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { 558 HandleScope scope(isolate); 559 ASSERT(args.length() == 3); 560 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 561 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 562 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 563 564 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals, 565 literals_index, elements); 566 RETURN_IF_EMPTY_HANDLE(isolate, site); 567 568 JSObject* boilerplate = JSObject::cast(site->transition_info()); 569 return boilerplate->DeepCopy(isolate); 570 } 571 572 573 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) { 574 HandleScope scope(isolate); 575 ASSERT(args.length() == 3); 576 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 577 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 578 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 579 580 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals, 581 literals_index, elements); 582 RETURN_IF_EMPTY_HANDLE(isolate, site); 583 584 JSObject* boilerplate = JSObject::cast(site->transition_info()); 585 if (boilerplate->elements()->map() == 586 isolate->heap()->fixed_cow_array_map()) { 587 isolate->counters()->cow_arrays_created_runtime()->Increment(); 588 } 589 590 AllocationSiteMode mode = AllocationSite::GetMode( 591 boilerplate->GetElementsKind()); 592 if (mode == TRACK_ALLOCATION_SITE) { 593 return isolate->heap()->CopyJSObjectWithAllocationSite( 594 boilerplate, *site); 595 } 596 597 return isolate->heap()->CopyJSObject(boilerplate); 598 } 599 600 601 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) { 602 HandleScope scope(isolate); 603 ASSERT(args.length() == 1); 604 Handle<Object> name(args[0], isolate); 605 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); 606 Symbol* symbol; 607 MaybeObject* maybe = isolate->heap()->AllocateSymbol(); 608 if (!maybe->To(&symbol)) return maybe; 609 if (name->IsString()) symbol->set_name(*name); 610 return symbol; 611 } 612 613 614 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) { 615 SealHandleScope shs(isolate); 616 ASSERT(args.length() == 1); 617 CONVERT_ARG_CHECKED(Symbol, symbol, 0); 618 return symbol->name(); 619 } 620 621 622 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) { 623 SealHandleScope shs(isolate); 624 ASSERT(args.length() == 2); 625 CONVERT_ARG_CHECKED(JSReceiver, handler, 0); 626 Object* prototype = args[1]; 627 Object* used_prototype = 628 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); 629 return isolate->heap()->AllocateJSProxy(handler, used_prototype); 630 } 631 632 633 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) { 634 SealHandleScope shs(isolate); 635 ASSERT(args.length() == 4); 636 CONVERT_ARG_CHECKED(JSReceiver, handler, 0); 637 Object* call_trap = args[1]; 638 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); 639 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2); 640 Object* prototype = args[3]; 641 Object* used_prototype = 642 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); 643 return isolate->heap()->AllocateJSFunctionProxy( 644 handler, call_trap, construct_trap, used_prototype); 645 } 646 647 648 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) { 649 SealHandleScope shs(isolate); 650 ASSERT(args.length() == 1); 651 Object* obj = args[0]; 652 return isolate->heap()->ToBoolean(obj->IsJSProxy()); 653 } 654 655 656 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) { 657 SealHandleScope shs(isolate); 658 ASSERT(args.length() == 1); 659 Object* obj = args[0]; 660 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); 661 } 662 663 664 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { 665 SealHandleScope shs(isolate); 666 ASSERT(args.length() == 1); 667 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 668 return proxy->handler(); 669 } 670 671 672 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) { 673 SealHandleScope shs(isolate); 674 ASSERT(args.length() == 1); 675 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 676 return proxy->call_trap(); 677 } 678 679 680 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) { 681 SealHandleScope shs(isolate); 682 ASSERT(args.length() == 1); 683 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 684 return proxy->construct_trap(); 685 } 686 687 688 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { 689 SealHandleScope shs(isolate); 690 ASSERT(args.length() == 1); 691 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 692 proxy->Fix(); 693 return isolate->heap()->undefined_value(); 694 } 695 696 697 void Runtime::FreeArrayBuffer(Isolate* isolate, 698 JSArrayBuffer* phantom_array_buffer) { 699 if (phantom_array_buffer->is_external()) return; 700 701 size_t allocated_length = NumberToSize( 702 isolate, phantom_array_buffer->byte_length()); 703 704 isolate->heap()->AdjustAmountOfExternalAllocatedMemory( 705 -static_cast<intptr_t>(allocated_length)); 706 CHECK(V8::ArrayBufferAllocator() != NULL); 707 V8::ArrayBufferAllocator()->Free( 708 phantom_array_buffer->backing_store(), 709 allocated_length); 710 } 711 712 713 void Runtime::SetupArrayBuffer(Isolate* isolate, 714 Handle<JSArrayBuffer> array_buffer, 715 bool is_external, 716 void* data, 717 size_t allocated_length) { 718 ASSERT(array_buffer->GetInternalFieldCount() == 719 v8::ArrayBuffer::kInternalFieldCount); 720 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 721 array_buffer->SetInternalField(i, Smi::FromInt(0)); 722 } 723 array_buffer->set_backing_store(data); 724 array_buffer->set_flag(Smi::FromInt(0)); 725 array_buffer->set_is_external(is_external); 726 727 Handle<Object> byte_length = 728 isolate->factory()->NewNumberFromSize(allocated_length); 729 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 730 array_buffer->set_byte_length(*byte_length); 731 732 array_buffer->set_weak_next(isolate->heap()->array_buffers_list()); 733 isolate->heap()->set_array_buffers_list(*array_buffer); 734 array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); 735 } 736 737 738 bool Runtime::SetupArrayBufferAllocatingData( 739 Isolate* isolate, 740 Handle<JSArrayBuffer> array_buffer, 741 size_t allocated_length, 742 bool initialize) { 743 void* data; 744 CHECK(V8::ArrayBufferAllocator() != NULL); 745 if (allocated_length != 0) { 746 if (initialize) { 747 data = V8::ArrayBufferAllocator()->Allocate(allocated_length); 748 } else { 749 data = 750 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); 751 } 752 if (data == NULL) return false; 753 } else { 754 data = NULL; 755 } 756 757 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); 758 759 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); 760 761 return true; 762 } 763 764 765 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { 766 HandleScope scope(isolate); 767 ASSERT(args.length() == 2); 768 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); 769 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); 770 size_t allocated_length; 771 if (byteLength->IsSmi()) { 772 allocated_length = Smi::cast(*byteLength)->value(); 773 } else { 774 ASSERT(byteLength->IsHeapNumber()); 775 double value = HeapNumber::cast(*byteLength)->value(); 776 777 ASSERT(value >= 0); 778 779 if (value > std::numeric_limits<size_t>::max()) { 780 return isolate->Throw( 781 *isolate->factory()->NewRangeError("invalid_array_buffer_length", 782 HandleVector<Object>(NULL, 0))); 783 } 784 785 allocated_length = static_cast<size_t>(value); 786 } 787 788 if (!Runtime::SetupArrayBufferAllocatingData(isolate, 789 holder, allocated_length)) { 790 return isolate->Throw(*isolate->factory()-> 791 NewRangeError("invalid_array_buffer_length", 792 HandleVector<Object>(NULL, 0))); 793 } 794 795 return *holder; 796 } 797 798 799 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { 800 SealHandleScope shs(isolate); 801 ASSERT(args.length() == 1); 802 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); 803 return holder->byte_length(); 804 } 805 806 807 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { 808 HandleScope scope(isolate); 809 ASSERT(args.length() == 3); 810 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); 811 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); 812 CONVERT_DOUBLE_ARG_CHECKED(first, 2); 813 size_t start = static_cast<size_t>(first); 814 size_t target_length = NumberToSize(isolate, target->byte_length()); 815 816 if (target_length == 0) return isolate->heap()->undefined_value(); 817 818 ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start); 819 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); 820 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); 821 CopyBytes(target_data, source_data + start, target_length); 822 return isolate->heap()->undefined_value(); 823 } 824 825 826 enum TypedArrayId { 827 // arrayIds below should be synchromized with typedarray.js natives. 828 ARRAY_ID_UINT8 = 1, 829 ARRAY_ID_INT8 = 2, 830 ARRAY_ID_UINT16 = 3, 831 ARRAY_ID_INT16 = 4, 832 ARRAY_ID_UINT32 = 5, 833 ARRAY_ID_INT32 = 6, 834 ARRAY_ID_FLOAT32 = 7, 835 ARRAY_ID_FLOAT64 = 8, 836 ARRAY_ID_UINT8C = 9 837 }; 838 839 static void ArrayIdToTypeAndSize( 840 int arrayId, ExternalArrayType* array_type, size_t* element_size) { 841 switch (arrayId) { 842 case ARRAY_ID_UINT8: 843 *array_type = kExternalUnsignedByteArray; 844 *element_size = 1; 845 break; 846 case ARRAY_ID_INT8: 847 *array_type = kExternalByteArray; 848 *element_size = 1; 849 break; 850 case ARRAY_ID_UINT16: 851 *array_type = kExternalUnsignedShortArray; 852 *element_size = 2; 853 break; 854 case ARRAY_ID_INT16: 855 *array_type = kExternalShortArray; 856 *element_size = 2; 857 break; 858 case ARRAY_ID_UINT32: 859 *array_type = kExternalUnsignedIntArray; 860 *element_size = 4; 861 break; 862 case ARRAY_ID_INT32: 863 *array_type = kExternalIntArray; 864 *element_size = 4; 865 break; 866 case ARRAY_ID_FLOAT32: 867 *array_type = kExternalFloatArray; 868 *element_size = 4; 869 break; 870 case ARRAY_ID_FLOAT64: 871 *array_type = kExternalDoubleArray; 872 *element_size = 8; 873 break; 874 case ARRAY_ID_UINT8C: 875 *array_type = kExternalPixelArray; 876 *element_size = 1; 877 break; 878 default: 879 UNREACHABLE(); 880 } 881 } 882 883 884 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { 885 HandleScope scope(isolate); 886 ASSERT(args.length() == 5); 887 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 888 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 889 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2); 890 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3); 891 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4); 892 893 ASSERT(holder->GetInternalFieldCount() == 894 v8::ArrayBufferView::kInternalFieldCount); 895 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 896 holder->SetInternalField(i, Smi::FromInt(0)); 897 } 898 899 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. 900 size_t element_size = 1; // Bogus initialization. 901 ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); 902 903 holder->set_buffer(*buffer); 904 holder->set_byte_offset(*byte_offset_object); 905 holder->set_byte_length(*byte_length_object); 906 907 size_t byte_offset = NumberToSize(isolate, *byte_offset_object); 908 size_t byte_length = NumberToSize(isolate, *byte_length_object); 909 ASSERT(byte_length % element_size == 0); 910 size_t length = byte_length / element_size; 911 912 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); 913 holder->set_length(*length_obj); 914 holder->set_weak_next(buffer->weak_first_view()); 915 buffer->set_weak_first_view(*holder); 916 917 Handle<ExternalArray> elements = 918 isolate->factory()->NewExternalArray( 919 static_cast<int>(length), array_type, 920 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); 921 holder->set_elements(*elements); 922 return isolate->heap()->undefined_value(); 923 } 924 925 926 // Initializes a typed array from an array-like object. 927 // If an array-like object happens to be a typed array of the same type, 928 // initializes backing store using memove. 929 // 930 // Returns true if backing store was initialized or false otherwise. 931 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { 932 HandleScope scope(isolate); 933 ASSERT(args.length() == 4); 934 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 935 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 936 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); 937 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3); 938 939 ASSERT(holder->GetInternalFieldCount() == 940 v8::ArrayBufferView::kInternalFieldCount); 941 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 942 holder->SetInternalField(i, Smi::FromInt(0)); 943 } 944 945 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. 946 size_t element_size = 1; // Bogus initialization. 947 ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); 948 949 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 950 size_t length = NumberToSize(isolate, *length_obj); 951 if (length > (kMaxInt / element_size)) { 952 return isolate->Throw(*isolate->factory()-> 953 NewRangeError("invalid_array_buffer_length", 954 HandleVector<Object>(NULL, 0))); 955 } 956 size_t byte_length = length * element_size; 957 958 // We assume that the caller of this function will initialize holder 959 // with the loop 960 // for(i = 0; i < length; i++) { holder[i] = source[i]; } 961 // If source is a typed array, this loop will always run to completion, 962 // so we are sure that the backing store will be initialized. 963 // Otherwise, we do not know (the indexing operation might throw). 964 // Hence we require zero initialization unless our source is a typed array. 965 bool should_zero_initialize = !source->IsJSTypedArray(); 966 967 if (!Runtime::SetupArrayBufferAllocatingData( 968 isolate, buffer, byte_length, should_zero_initialize)) { 969 return isolate->Throw(*isolate->factory()-> 970 NewRangeError("invalid_array_buffer_length", 971 HandleVector<Object>(NULL, 0))); 972 } 973 974 holder->set_buffer(*buffer); 975 holder->set_byte_offset(Smi::FromInt(0)); 976 Handle<Object> byte_length_obj( 977 isolate->factory()->NewNumberFromSize(byte_length)); 978 holder->set_byte_length(*byte_length_obj); 979 holder->set_length(*length_obj); 980 holder->set_weak_next(buffer->weak_first_view()); 981 buffer->set_weak_first_view(*holder); 982 983 Handle<ExternalArray> elements = 984 isolate->factory()->NewExternalArray( 985 static_cast<int>(length), array_type, 986 static_cast<uint8_t*>(buffer->backing_store())); 987 holder->set_elements(*elements); 988 989 if (source->IsJSTypedArray()) { 990 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); 991 992 if (typed_array->type() == holder->type()) { 993 uint8_t* backing_store = 994 static_cast<uint8_t*>( 995 JSArrayBuffer::cast(typed_array->buffer())->backing_store()); 996 size_t source_byte_offset = 997 NumberToSize(isolate, typed_array->byte_offset()); 998 OS::MemCopy( 999 buffer->backing_store(), 1000 backing_store + source_byte_offset, 1001 byte_length); 1002 return *isolate->factory()->true_value(); 1003 } else { 1004 return *isolate->factory()->false_value(); 1005 } 1006 } 1007 1008 return *isolate->factory()->false_value(); 1009 } 1010 1011 1012 #define TYPED_ARRAY_GETTER(getter, accessor) \ 1013 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \ 1014 HandleScope scope(isolate); \ 1015 ASSERT(args.length() == 1); \ 1016 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \ 1017 if (!holder->IsJSTypedArray()) \ 1018 return isolate->Throw(*isolate->factory()->NewTypeError( \ 1019 "not_typed_array", HandleVector<Object>(NULL, 0))); \ 1020 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \ 1021 return typed_array->accessor(); \ 1022 } 1023 1024 TYPED_ARRAY_GETTER(Buffer, buffer) 1025 TYPED_ARRAY_GETTER(ByteLength, byte_length) 1026 TYPED_ARRAY_GETTER(ByteOffset, byte_offset) 1027 TYPED_ARRAY_GETTER(Length, length) 1028 1029 #undef TYPED_ARRAY_GETTER 1030 1031 // Return codes for Runtime_TypedArraySetFastCases. 1032 // Should be synchronized with typedarray.js natives. 1033 enum TypedArraySetResultCodes { 1034 // Set from typed array of the same type. 1035 // This is processed by TypedArraySetFastCases 1036 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, 1037 // Set from typed array of the different type, overlapping in memory. 1038 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, 1039 // Set from typed array of the different type, non-overlapping. 1040 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, 1041 // Set from non-typed array. 1042 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 1043 }; 1044 1045 1046 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { 1047 HandleScope scope(isolate); 1048 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); 1049 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1); 1050 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2); 1051 1052 if (!target_obj->IsJSTypedArray()) 1053 return isolate->Throw(*isolate->factory()->NewTypeError( 1054 "not_typed_array", HandleVector<Object>(NULL, 0))); 1055 1056 if (!source_obj->IsJSTypedArray()) 1057 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); 1058 1059 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); 1060 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); 1061 size_t offset = NumberToSize(isolate, *offset_obj); 1062 size_t target_length = NumberToSize(isolate, target->length()); 1063 size_t source_length = NumberToSize(isolate, source->length()); 1064 size_t target_byte_length = NumberToSize(isolate, target->byte_length()); 1065 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); 1066 if (offset > target_length || 1067 offset + source_length > target_length || 1068 offset + source_length < offset) // overflow 1069 return isolate->Throw(*isolate->factory()->NewRangeError( 1070 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0))); 1071 1072 size_t target_offset = NumberToSize(isolate, target->byte_offset()); 1073 size_t source_offset = NumberToSize(isolate, source->byte_offset()); 1074 uint8_t* target_base = 1075 static_cast<uint8_t*>( 1076 JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset; 1077 uint8_t* source_base = 1078 static_cast<uint8_t*>( 1079 JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset; 1080 1081 // Typed arrays of the same type: use memmove. 1082 if (target->type() == source->type()) { 1083 memmove(target_base + offset * target->element_size(), 1084 source_base, source_byte_length); 1085 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); 1086 } 1087 1088 // Typed arrays of different types over the same backing store 1089 if ((source_base <= target_base && 1090 source_base + source_byte_length > target_base) || 1091 (target_base <= source_base && 1092 target_base + target_byte_length > source_base)) { 1093 // We do not support overlapping ArrayBuffers 1094 ASSERT( 1095 JSArrayBuffer::cast(target->buffer())->backing_store() == 1096 JSArrayBuffer::cast(source->buffer())->backing_store()); 1097 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); 1098 } else { // Non-overlapping typed arrays 1099 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); 1100 } 1101 } 1102 1103 1104 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) { 1105 HandleScope scope(isolate); 1106 ASSERT(args.length() == 4); 1107 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); 1108 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); 1109 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2); 1110 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3); 1111 1112 ASSERT(holder->GetInternalFieldCount() == 1113 v8::ArrayBufferView::kInternalFieldCount); 1114 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 1115 holder->SetInternalField(i, Smi::FromInt(0)); 1116 } 1117 1118 holder->set_buffer(*buffer); 1119 ASSERT(byte_offset->IsNumber()); 1120 ASSERT( 1121 NumberToSize(isolate, buffer->byte_length()) >= 1122 NumberToSize(isolate, *byte_offset) 1123 + NumberToSize(isolate, *byte_length)); 1124 holder->set_byte_offset(*byte_offset); 1125 ASSERT(byte_length->IsNumber()); 1126 holder->set_byte_length(*byte_length); 1127 1128 holder->set_weak_next(buffer->weak_first_view()); 1129 buffer->set_weak_first_view(*holder); 1130 1131 return isolate->heap()->undefined_value(); 1132 } 1133 1134 1135 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) { 1136 HandleScope scope(isolate); 1137 ASSERT(args.length() == 1); 1138 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1139 return data_view->buffer(); 1140 } 1141 1142 1143 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) { 1144 HandleScope scope(isolate); 1145 ASSERT(args.length() == 1); 1146 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1147 return data_view->byte_offset(); 1148 } 1149 1150 1151 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) { 1152 HandleScope scope(isolate); 1153 ASSERT(args.length() == 1); 1154 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1155 return data_view->byte_length(); 1156 } 1157 1158 1159 inline static bool NeedToFlipBytes(bool is_little_endian) { 1160 #ifdef V8_TARGET_LITTLE_ENDIAN 1161 return !is_little_endian; 1162 #else 1163 return is_little_endian; 1164 #endif 1165 } 1166 1167 1168 template<int n> 1169 inline void CopyBytes(uint8_t* target, uint8_t* source) { 1170 for (int i = 0; i < n; i++) { 1171 *(target++) = *(source++); 1172 } 1173 } 1174 1175 1176 template<int n> 1177 inline void FlipBytes(uint8_t* target, uint8_t* source) { 1178 source = source + (n-1); 1179 for (int i = 0; i < n; i++) { 1180 *(target++) = *(source--); 1181 } 1182 } 1183 1184 1185 template<typename T> 1186 inline static bool DataViewGetValue( 1187 Isolate* isolate, 1188 Handle<JSDataView> data_view, 1189 Handle<Object> byte_offset_obj, 1190 bool is_little_endian, 1191 T* result) { 1192 size_t byte_offset = NumberToSize(isolate, *byte_offset_obj); 1193 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1194 1195 size_t data_view_byte_offset = 1196 NumberToSize(isolate, data_view->byte_offset()); 1197 size_t data_view_byte_length = 1198 NumberToSize(isolate, data_view->byte_length()); 1199 if (byte_offset + sizeof(T) > data_view_byte_length || 1200 byte_offset + sizeof(T) < byte_offset) { // overflow 1201 return false; 1202 } 1203 1204 union Value { 1205 T data; 1206 uint8_t bytes[sizeof(T)]; 1207 }; 1208 1209 Value value; 1210 size_t buffer_offset = data_view_byte_offset + byte_offset; 1211 ASSERT( 1212 NumberToSize(isolate, buffer->byte_length()) 1213 >= buffer_offset + sizeof(T)); 1214 uint8_t* source = 1215 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1216 if (NeedToFlipBytes(is_little_endian)) { 1217 FlipBytes<sizeof(T)>(value.bytes, source); 1218 } else { 1219 CopyBytes<sizeof(T)>(value.bytes, source); 1220 } 1221 *result = value.data; 1222 return true; 1223 } 1224 1225 1226 template<typename T> 1227 static bool DataViewSetValue( 1228 Isolate* isolate, 1229 Handle<JSDataView> data_view, 1230 Handle<Object> byte_offset_obj, 1231 bool is_little_endian, 1232 T data) { 1233 size_t byte_offset = NumberToSize(isolate, *byte_offset_obj); 1234 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1235 1236 size_t data_view_byte_offset = 1237 NumberToSize(isolate, data_view->byte_offset()); 1238 size_t data_view_byte_length = 1239 NumberToSize(isolate, data_view->byte_length()); 1240 if (byte_offset + sizeof(T) > data_view_byte_length || 1241 byte_offset + sizeof(T) < byte_offset) { // overflow 1242 return false; 1243 } 1244 1245 union Value { 1246 T data; 1247 uint8_t bytes[sizeof(T)]; 1248 }; 1249 1250 Value value; 1251 value.data = data; 1252 size_t buffer_offset = data_view_byte_offset + byte_offset; 1253 ASSERT( 1254 NumberToSize(isolate, buffer->byte_length()) 1255 >= buffer_offset + sizeof(T)); 1256 uint8_t* target = 1257 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1258 if (NeedToFlipBytes(is_little_endian)) { 1259 FlipBytes<sizeof(T)>(target, value.bytes); 1260 } else { 1261 CopyBytes<sizeof(T)>(target, value.bytes); 1262 } 1263 return true; 1264 } 1265 1266 1267 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ 1268 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \ 1269 HandleScope scope(isolate); \ 1270 ASSERT(args.length() == 3); \ 1271 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1272 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ 1273 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ 1274 Type result; \ 1275 if (DataViewGetValue( \ 1276 isolate, holder, offset, is_little_endian, &result)) { \ 1277 return isolate->heap()->Converter(result); \ 1278 } else { \ 1279 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1280 "invalid_data_view_accessor_offset", \ 1281 HandleVector<Object>(NULL, 0))); \ 1282 } \ 1283 } 1284 1285 DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32) 1286 DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32) 1287 DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32) 1288 DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32) 1289 DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32) 1290 DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32) 1291 DATA_VIEW_GETTER(Float32, float, NumberFromDouble) 1292 DATA_VIEW_GETTER(Float64, double, NumberFromDouble) 1293 1294 #undef DATA_VIEW_GETTER 1295 1296 1297 template <typename T> 1298 static T DataViewConvertValue(double value); 1299 1300 1301 template <> 1302 int8_t DataViewConvertValue<int8_t>(double value) { 1303 return static_cast<int8_t>(DoubleToInt32(value)); 1304 } 1305 1306 1307 template <> 1308 int16_t DataViewConvertValue<int16_t>(double value) { 1309 return static_cast<int16_t>(DoubleToInt32(value)); 1310 } 1311 1312 1313 template <> 1314 int32_t DataViewConvertValue<int32_t>(double value) { 1315 return DoubleToInt32(value); 1316 } 1317 1318 1319 template <> 1320 uint8_t DataViewConvertValue<uint8_t>(double value) { 1321 return static_cast<uint8_t>(DoubleToUint32(value)); 1322 } 1323 1324 1325 template <> 1326 uint16_t DataViewConvertValue<uint16_t>(double value) { 1327 return static_cast<uint16_t>(DoubleToUint32(value)); 1328 } 1329 1330 1331 template <> 1332 uint32_t DataViewConvertValue<uint32_t>(double value) { 1333 return DoubleToUint32(value); 1334 } 1335 1336 1337 template <> 1338 float DataViewConvertValue<float>(double value) { 1339 return static_cast<float>(value); 1340 } 1341 1342 1343 template <> 1344 double DataViewConvertValue<double>(double value) { 1345 return value; 1346 } 1347 1348 1349 #define DATA_VIEW_SETTER(TypeName, Type) \ 1350 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \ 1351 HandleScope scope(isolate); \ 1352 ASSERT(args.length() == 4); \ 1353 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1354 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ 1355 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \ 1356 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ 1357 Type v = DataViewConvertValue<Type>(value->Number()); \ 1358 if (DataViewSetValue( \ 1359 isolate, holder, offset, is_little_endian, v)) { \ 1360 return isolate->heap()->undefined_value(); \ 1361 } else { \ 1362 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1363 "invalid_data_view_accessor_offset", \ 1364 HandleVector<Object>(NULL, 0))); \ 1365 } \ 1366 } 1367 1368 DATA_VIEW_SETTER(Uint8, uint8_t) 1369 DATA_VIEW_SETTER(Int8, int8_t) 1370 DATA_VIEW_SETTER(Uint16, uint16_t) 1371 DATA_VIEW_SETTER(Int16, int16_t) 1372 DATA_VIEW_SETTER(Uint32, uint32_t) 1373 DATA_VIEW_SETTER(Int32, int32_t) 1374 DATA_VIEW_SETTER(Float32, float) 1375 DATA_VIEW_SETTER(Float64, double) 1376 1377 #undef DATA_VIEW_SETTER 1378 1379 1380 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { 1381 HandleScope scope(isolate); 1382 ASSERT(args.length() == 1); 1383 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1384 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0); 1385 holder->set_table(*table); 1386 return *holder; 1387 } 1388 1389 1390 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) { 1391 HandleScope scope(isolate); 1392 ASSERT(args.length() == 2); 1393 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1394 Handle<Object> key(args[1], isolate); 1395 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1396 table = ObjectHashSetAdd(table, key); 1397 holder->set_table(*table); 1398 return isolate->heap()->undefined_value(); 1399 } 1400 1401 1402 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) { 1403 HandleScope scope(isolate); 1404 ASSERT(args.length() == 2); 1405 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1406 Handle<Object> key(args[1], isolate); 1407 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1408 return isolate->heap()->ToBoolean(table->Contains(*key)); 1409 } 1410 1411 1412 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { 1413 HandleScope scope(isolate); 1414 ASSERT(args.length() == 2); 1415 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1416 Handle<Object> key(args[1], isolate); 1417 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1418 table = ObjectHashSetRemove(table, key); 1419 holder->set_table(*table); 1420 return isolate->heap()->undefined_value(); 1421 } 1422 1423 1424 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) { 1425 HandleScope scope(isolate); 1426 ASSERT(args.length() == 1); 1427 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1428 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1429 return Smi::FromInt(table->NumberOfElements()); 1430 } 1431 1432 1433 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) { 1434 HandleScope scope(isolate); 1435 ASSERT(args.length() == 1); 1436 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1437 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); 1438 holder->set_table(*table); 1439 return *holder; 1440 } 1441 1442 1443 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) { 1444 HandleScope scope(isolate); 1445 ASSERT(args.length() == 2); 1446 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1447 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1448 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1449 Handle<Object> lookup(table->Lookup(*key), isolate); 1450 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1451 } 1452 1453 1454 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) { 1455 HandleScope scope(isolate); 1456 ASSERT(args.length() == 2); 1457 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1458 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1459 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1460 Handle<Object> lookup(table->Lookup(*key), isolate); 1461 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1462 } 1463 1464 1465 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) { 1466 HandleScope scope(isolate); 1467 ASSERT(args.length() == 2); 1468 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1469 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1470 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1471 Handle<Object> lookup(table->Lookup(*key), isolate); 1472 Handle<ObjectHashTable> new_table = 1473 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value()); 1474 holder->set_table(*new_table); 1475 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1476 } 1477 1478 1479 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { 1480 HandleScope scope(isolate); 1481 ASSERT(args.length() == 3); 1482 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1483 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1484 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 1485 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1486 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value); 1487 holder->set_table(*new_table); 1488 return isolate->heap()->undefined_value(); 1489 } 1490 1491 1492 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) { 1493 HandleScope scope(isolate); 1494 ASSERT(args.length() == 1); 1495 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1496 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1497 return Smi::FromInt(table->NumberOfElements()); 1498 } 1499 1500 1501 static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate, 1502 Handle<JSWeakCollection> weak_collection) { 1503 ASSERT(weak_collection->map()->inobject_properties() == 0); 1504 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); 1505 weak_collection->set_table(*table); 1506 weak_collection->set_next(Smi::FromInt(0)); 1507 return *weak_collection; 1508 } 1509 1510 1511 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) { 1512 HandleScope scope(isolate); 1513 ASSERT(args.length() == 1); 1514 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1515 return WeakCollectionInitialize(isolate, weak_collection); 1516 } 1517 1518 1519 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) { 1520 HandleScope scope(isolate); 1521 ASSERT(args.length() == 2); 1522 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1523 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1524 Handle<ObjectHashTable> table( 1525 ObjectHashTable::cast(weak_collection->table())); 1526 Handle<Object> lookup(table->Lookup(*key), isolate); 1527 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1528 } 1529 1530 1531 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) { 1532 HandleScope scope(isolate); 1533 ASSERT(args.length() == 2); 1534 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1535 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1536 Handle<ObjectHashTable> table( 1537 ObjectHashTable::cast(weak_collection->table())); 1538 Handle<Object> lookup(table->Lookup(*key), isolate); 1539 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1540 } 1541 1542 1543 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) { 1544 HandleScope scope(isolate); 1545 ASSERT(args.length() == 2); 1546 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1547 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1548 Handle<ObjectHashTable> table(ObjectHashTable::cast( 1549 weak_collection->table())); 1550 Handle<Object> lookup(table->Lookup(*key), isolate); 1551 Handle<ObjectHashTable> new_table = 1552 PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value()); 1553 weak_collection->set_table(*new_table); 1554 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1555 } 1556 1557 1558 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) { 1559 HandleScope scope(isolate); 1560 ASSERT(args.length() == 3); 1561 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1562 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1563 Handle<Object> value(args[2], isolate); 1564 Handle<ObjectHashTable> table( 1565 ObjectHashTable::cast(weak_collection->table())); 1566 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value); 1567 weak_collection->set_table(*new_table); 1568 return isolate->heap()->undefined_value(); 1569 } 1570 1571 1572 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { 1573 SealHandleScope shs(isolate); 1574 ASSERT(args.length() == 1); 1575 Object* obj = args[0]; 1576 if (!obj->IsJSObject()) return isolate->heap()->null_value(); 1577 return JSObject::cast(obj)->class_name(); 1578 } 1579 1580 1581 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) { 1582 SealHandleScope shs(isolate); 1583 ASSERT(args.length() == 1); 1584 CONVERT_ARG_CHECKED(Object, obj, 0); 1585 // We don't expect access checks to be needed on JSProxy objects. 1586 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); 1587 do { 1588 if (obj->IsAccessCheckNeeded() && 1589 !isolate->MayNamedAccess(JSObject::cast(obj), 1590 isolate->heap()->proto_string(), 1591 v8::ACCESS_GET)) { 1592 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET); 1593 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1594 return isolate->heap()->undefined_value(); 1595 } 1596 obj = obj->GetPrototype(isolate); 1597 } while (obj->IsJSObject() && 1598 JSObject::cast(obj)->map()->is_hidden_prototype()); 1599 return obj; 1600 } 1601 1602 1603 static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate, 1604 Object* receiver) { 1605 Object* current = receiver->GetPrototype(isolate); 1606 while (current->IsJSObject() && 1607 JSObject::cast(current)->map()->is_hidden_prototype()) { 1608 current = current->GetPrototype(isolate); 1609 } 1610 return current; 1611 } 1612 1613 1614 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) { 1615 HandleScope scope(isolate); 1616 ASSERT(args.length() == 2); 1617 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1618 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 1619 if (FLAG_harmony_observation && obj->map()->is_observed()) { 1620 Handle<Object> old_value( 1621 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); 1622 1623 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); 1624 RETURN_IF_EMPTY_HANDLE(isolate, result); 1625 1626 Handle<Object> new_value( 1627 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); 1628 if (!new_value->SameValue(*old_value)) { 1629 JSObject::EnqueueChangeRecord(obj, "prototype", 1630 isolate->factory()->proto_string(), 1631 old_value); 1632 } 1633 return *result; 1634 } 1635 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); 1636 RETURN_IF_EMPTY_HANDLE(isolate, result); 1637 return *result; 1638 } 1639 1640 1641 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { 1642 SealHandleScope shs(isolate); 1643 ASSERT(args.length() == 2); 1644 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). 1645 Object* O = args[0]; 1646 Object* V = args[1]; 1647 while (true) { 1648 Object* prototype = V->GetPrototype(isolate); 1649 if (prototype->IsNull()) return isolate->heap()->false_value(); 1650 if (O == prototype) return isolate->heap()->true_value(); 1651 V = prototype; 1652 } 1653 } 1654 1655 1656 static bool CheckAccessException(Object* callback, 1657 v8::AccessType access_type) { 1658 if (callback->IsAccessorInfo()) { 1659 AccessorInfo* info = AccessorInfo::cast(callback); 1660 return 1661 (access_type == v8::ACCESS_HAS && 1662 (info->all_can_read() || info->all_can_write())) || 1663 (access_type == v8::ACCESS_GET && info->all_can_read()) || 1664 (access_type == v8::ACCESS_SET && info->all_can_write()); 1665 } 1666 return false; 1667 } 1668 1669 1670 template<class Key> 1671 static bool CheckGenericAccess( 1672 JSObject* receiver, 1673 JSObject* holder, 1674 Key key, 1675 v8::AccessType access_type, 1676 bool (Isolate::*mayAccess)(JSObject*, Key, v8::AccessType)) { 1677 Isolate* isolate = receiver->GetIsolate(); 1678 for (JSObject* current = receiver; 1679 true; 1680 current = JSObject::cast(current->GetPrototype())) { 1681 if (current->IsAccessCheckNeeded() && 1682 !(isolate->*mayAccess)(current, key, access_type)) { 1683 return false; 1684 } 1685 if (current == holder) break; 1686 } 1687 return true; 1688 } 1689 1690 1691 enum AccessCheckResult { 1692 ACCESS_FORBIDDEN, 1693 ACCESS_ALLOWED, 1694 ACCESS_ABSENT 1695 }; 1696 1697 1698 static AccessCheckResult CheckPropertyAccess( 1699 JSObject* obj, 1700 Name* name, 1701 v8::AccessType access_type) { 1702 uint32_t index; 1703 if (name->AsArrayIndex(&index)) { 1704 // TODO(1095): we should traverse hidden prototype hierachy as well. 1705 if (CheckGenericAccess( 1706 obj, obj, index, access_type, &Isolate::MayIndexedAccess)) { 1707 return ACCESS_ALLOWED; 1708 } 1709 1710 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); 1711 return ACCESS_FORBIDDEN; 1712 } 1713 1714 LookupResult lookup(obj->GetIsolate()); 1715 obj->LocalLookup(name, &lookup, true); 1716 1717 if (!lookup.IsProperty()) return ACCESS_ABSENT; 1718 if (CheckGenericAccess<Object*>( 1719 obj, lookup.holder(), name, access_type, &Isolate::MayNamedAccess)) { 1720 return ACCESS_ALLOWED; 1721 } 1722 1723 // Access check callback denied the access, but some properties 1724 // can have a special permissions which override callbacks descision 1725 // (currently see v8::AccessControl). 1726 // API callbacks can have per callback access exceptions. 1727 switch (lookup.type()) { 1728 case CALLBACKS: 1729 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1730 return ACCESS_ALLOWED; 1731 } 1732 break; 1733 case INTERCEPTOR: 1734 // If the object has an interceptor, try real named properties. 1735 // Overwrite the result to fetch the correct property later. 1736 lookup.holder()->LookupRealNamedProperty(name, &lookup); 1737 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) { 1738 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1739 return ACCESS_ALLOWED; 1740 } 1741 } 1742 break; 1743 default: 1744 break; 1745 } 1746 1747 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); 1748 return ACCESS_FORBIDDEN; 1749 } 1750 1751 1752 // Enumerator used as indices into the array returned from GetOwnProperty 1753 enum PropertyDescriptorIndices { 1754 IS_ACCESSOR_INDEX, 1755 VALUE_INDEX, 1756 GETTER_INDEX, 1757 SETTER_INDEX, 1758 WRITABLE_INDEX, 1759 ENUMERABLE_INDEX, 1760 CONFIGURABLE_INDEX, 1761 DESCRIPTOR_SIZE 1762 }; 1763 1764 1765 static MaybeObject* GetOwnProperty(Isolate* isolate, 1766 Handle<JSObject> obj, 1767 Handle<Name> name) { 1768 Heap* heap = isolate->heap(); 1769 // Due to some WebKit tests, we want to make sure that we do not log 1770 // more than one access failure here. 1771 AccessCheckResult access_check_result = 1772 CheckPropertyAccess(*obj, *name, v8::ACCESS_HAS); 1773 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1774 switch (access_check_result) { 1775 case ACCESS_FORBIDDEN: return heap->false_value(); 1776 case ACCESS_ALLOWED: break; 1777 case ACCESS_ABSENT: return heap->undefined_value(); 1778 } 1779 1780 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); 1781 if (attrs == ABSENT) { 1782 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1783 return heap->undefined_value(); 1784 } 1785 ASSERT(!isolate->has_scheduled_exception()); 1786 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name); 1787 Handle<AccessorPair> accessors(raw_accessors, isolate); 1788 1789 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); 1790 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); 1791 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); 1792 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL)); 1793 1794 if (raw_accessors == NULL) { 1795 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); 1796 // GetProperty does access check. 1797 Handle<Object> value = GetProperty(isolate, obj, name); 1798 RETURN_IF_EMPTY_HANDLE(isolate, value); 1799 elms->set(VALUE_INDEX, *value); 1800 } else { 1801 // Access checks are performed for both accessors separately. 1802 // When they fail, the respective field is not set in the descriptor. 1803 Object* getter = accessors->GetComponent(ACCESSOR_GETTER); 1804 Object* setter = accessors->GetComponent(ACCESSOR_SETTER); 1805 if (!getter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_GET)) { 1806 ASSERT(!isolate->has_scheduled_exception()); 1807 elms->set(GETTER_INDEX, getter); 1808 } else { 1809 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1810 } 1811 if (!setter->IsMap() && CheckPropertyAccess(*obj, *name, v8::ACCESS_SET)) { 1812 ASSERT(!isolate->has_scheduled_exception()); 1813 elms->set(SETTER_INDEX, setter); 1814 } else { 1815 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1816 } 1817 } 1818 1819 return *isolate->factory()->NewJSArrayWithElements(elms); 1820 } 1821 1822 1823 // Returns an array with the property description: 1824 // if args[1] is not a property on args[0] 1825 // returns undefined 1826 // if args[1] is a data property on args[0] 1827 // [false, value, Writeable, Enumerable, Configurable] 1828 // if args[1] is an accessor on args[0] 1829 // [true, GetFunction, SetFunction, Enumerable, Configurable] 1830 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) { 1831 HandleScope scope(isolate); 1832 ASSERT(args.length() == 2); 1833 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1834 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 1835 return GetOwnProperty(isolate, obj, name); 1836 } 1837 1838 1839 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) { 1840 SealHandleScope shs(isolate); 1841 ASSERT(args.length() == 1); 1842 CONVERT_ARG_CHECKED(JSObject, obj, 0); 1843 return obj->PreventExtensions(); 1844 } 1845 1846 1847 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) { 1848 SealHandleScope shs(isolate); 1849 ASSERT(args.length() == 1); 1850 CONVERT_ARG_CHECKED(JSObject, obj, 0); 1851 if (obj->IsJSGlobalProxy()) { 1852 Object* proto = obj->GetPrototype(); 1853 if (proto->IsNull()) return isolate->heap()->false_value(); 1854 ASSERT(proto->IsJSGlobalObject()); 1855 obj = JSObject::cast(proto); 1856 } 1857 return isolate->heap()->ToBoolean(obj->map()->is_extensible()); 1858 } 1859 1860 1861 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) { 1862 HandleScope scope(isolate); 1863 ASSERT(args.length() == 3); 1864 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); 1865 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 1866 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); 1867 Handle<Object> result = 1868 RegExpImpl::Compile(re, pattern, flags); 1869 RETURN_IF_EMPTY_HANDLE(isolate, result); 1870 return *result; 1871 } 1872 1873 1874 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) { 1875 HandleScope scope(isolate); 1876 ASSERT(args.length() == 1); 1877 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); 1878 return *isolate->factory()->CreateApiFunction(data); 1879 } 1880 1881 1882 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) { 1883 SealHandleScope shs(isolate); 1884 ASSERT(args.length() == 1); 1885 Object* arg = args[0]; 1886 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); 1887 return isolate->heap()->ToBoolean(result); 1888 } 1889 1890 1891 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) { 1892 SealHandleScope shs(isolate); 1893 ASSERT(args.length() == 2); 1894 CONVERT_ARG_CHECKED(HeapObject, templ, 0); 1895 CONVERT_SMI_ARG_CHECKED(index, 1) 1896 int offset = index * kPointerSize + HeapObject::kHeaderSize; 1897 InstanceType type = templ->map()->instance_type(); 1898 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || 1899 type == OBJECT_TEMPLATE_INFO_TYPE); 1900 RUNTIME_ASSERT(offset > 0); 1901 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { 1902 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); 1903 } else { 1904 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 1905 } 1906 return *HeapObject::RawField(templ, offset); 1907 } 1908 1909 1910 RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) { 1911 SealHandleScope shs(isolate); 1912 ASSERT(args.length() == 1); 1913 CONVERT_ARG_CHECKED(HeapObject, object, 0); 1914 Map* old_map = object->map(); 1915 bool needs_access_checks = old_map->is_access_check_needed(); 1916 if (needs_access_checks) { 1917 // Copy map so it won't interfere constructor's initial map. 1918 Map* new_map; 1919 MaybeObject* maybe_new_map = old_map->Copy(); 1920 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 1921 1922 new_map->set_is_access_check_needed(false); 1923 object->set_map(new_map); 1924 } 1925 return isolate->heap()->ToBoolean(needs_access_checks); 1926 } 1927 1928 1929 RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) { 1930 SealHandleScope shs(isolate); 1931 ASSERT(args.length() == 1); 1932 CONVERT_ARG_CHECKED(HeapObject, object, 0); 1933 Map* old_map = object->map(); 1934 if (!old_map->is_access_check_needed()) { 1935 // Copy map so it won't interfere constructor's initial map. 1936 Map* new_map; 1937 MaybeObject* maybe_new_map = old_map->Copy(); 1938 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 1939 1940 new_map->set_is_access_check_needed(true); 1941 object->set_map(new_map); 1942 } 1943 return isolate->heap()->undefined_value(); 1944 } 1945 1946 1947 static Failure* ThrowRedeclarationError(Isolate* isolate, 1948 const char* type, 1949 Handle<String> name) { 1950 HandleScope scope(isolate); 1951 Handle<Object> type_handle = 1952 isolate->factory()->NewStringFromAscii(CStrVector(type)); 1953 Handle<Object> args[2] = { type_handle, name }; 1954 Handle<Object> error = 1955 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); 1956 return isolate->Throw(*error); 1957 } 1958 1959 1960 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { 1961 HandleScope scope(isolate); 1962 ASSERT(args.length() == 3); 1963 Handle<GlobalObject> global = Handle<GlobalObject>( 1964 isolate->context()->global_object()); 1965 1966 Handle<Context> context = args.at<Context>(0); 1967 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); 1968 CONVERT_SMI_ARG_CHECKED(flags, 2); 1969 1970 // Traverse the name/value pairs and set the properties. 1971 int length = pairs->length(); 1972 for (int i = 0; i < length; i += 2) { 1973 HandleScope scope(isolate); 1974 Handle<String> name(String::cast(pairs->get(i))); 1975 Handle<Object> value(pairs->get(i + 1), isolate); 1976 1977 // We have to declare a global const property. To capture we only 1978 // assign to it when evaluating the assignment for "const x = 1979 // <expr>" the initial value is the hole. 1980 bool is_var = value->IsUndefined(); 1981 bool is_const = value->IsTheHole(); 1982 bool is_function = value->IsSharedFunctionInfo(); 1983 ASSERT(is_var + is_const + is_function == 1); 1984 1985 if (is_var || is_const) { 1986 // Lookup the property in the global object, and don't set the 1987 // value of the variable if the property is already there. 1988 // Do the lookup locally only, see ES5 erratum. 1989 LookupResult lookup(isolate); 1990 if (FLAG_es52_globals) { 1991 global->LocalLookup(*name, &lookup, true); 1992 } else { 1993 global->Lookup(*name, &lookup); 1994 } 1995 if (lookup.IsFound()) { 1996 // We found an existing property. Unless it was an interceptor 1997 // that claims the property is absent, skip this declaration. 1998 if (!lookup.IsInterceptor()) continue; 1999 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 2000 if (attributes != ABSENT) continue; 2001 // Fall-through and introduce the absent property by using 2002 // SetProperty. 2003 } 2004 } else if (is_function) { 2005 // Copy the function and update its context. Use it as value. 2006 Handle<SharedFunctionInfo> shared = 2007 Handle<SharedFunctionInfo>::cast(value); 2008 Handle<JSFunction> function = 2009 isolate->factory()->NewFunctionFromSharedFunctionInfo( 2010 shared, context, TENURED); 2011 value = function; 2012 } 2013 2014 LookupResult lookup(isolate); 2015 global->LocalLookup(*name, &lookup, true); 2016 2017 // Compute the property attributes. According to ECMA-262, 2018 // the property must be non-configurable except in eval. 2019 int attr = NONE; 2020 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); 2021 if (!is_eval) { 2022 attr |= DONT_DELETE; 2023 } 2024 bool is_native = DeclareGlobalsNativeFlag::decode(flags); 2025 if (is_const || (is_native && is_function)) { 2026 attr |= READ_ONLY; 2027 } 2028 2029 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); 2030 2031 if (!lookup.IsFound() || is_function) { 2032 // If the local property exists, check that we can reconfigure it 2033 // as required for function declarations. 2034 if (lookup.IsFound() && lookup.IsDontDelete()) { 2035 if (lookup.IsReadOnly() || lookup.IsDontEnum() || 2036 lookup.IsPropertyCallbacks()) { 2037 return ThrowRedeclarationError(isolate, "function", name); 2038 } 2039 // If the existing property is not configurable, keep its attributes. 2040 attr = lookup.GetAttributes(); 2041 } 2042 // Define or redefine own property. 2043 RETURN_IF_EMPTY_HANDLE(isolate, 2044 JSObject::SetLocalPropertyIgnoreAttributes( 2045 global, name, value, static_cast<PropertyAttributes>(attr))); 2046 } else { 2047 // Do a [[Put]] on the existing (own) property. 2048 RETURN_IF_EMPTY_HANDLE(isolate, 2049 JSObject::SetProperty( 2050 global, name, value, static_cast<PropertyAttributes>(attr), 2051 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode)); 2052 } 2053 } 2054 2055 ASSERT(!isolate->has_pending_exception()); 2056 return isolate->heap()->undefined_value(); 2057 } 2058 2059 2060 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { 2061 HandleScope scope(isolate); 2062 ASSERT(args.length() == 4); 2063 2064 // Declarations are always made in a function or native context. In the 2065 // case of eval code, the context passed is the context of the caller, 2066 // which may be some nested context and not the declaration context. 2067 RUNTIME_ASSERT(args[0]->IsContext()); 2068 Handle<Context> context(Context::cast(args[0])->declaration_context()); 2069 2070 Handle<String> name(String::cast(args[1])); 2071 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2)); 2072 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); 2073 Handle<Object> initial_value(args[3], isolate); 2074 2075 int index; 2076 PropertyAttributes attributes; 2077 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 2078 BindingFlags binding_flags; 2079 Handle<Object> holder = 2080 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2081 2082 if (attributes != ABSENT) { 2083 // The name was declared before; check for conflicting re-declarations. 2084 // Note: this is actually inconsistent with what happens for globals (where 2085 // we silently ignore such declarations). 2086 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 2087 // Functions are not read-only. 2088 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 2089 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 2090 return ThrowRedeclarationError(isolate, type, name); 2091 } 2092 2093 // Initialize it if necessary. 2094 if (*initial_value != NULL) { 2095 if (index >= 0) { 2096 ASSERT(holder.is_identical_to(context)); 2097 if (((attributes & READ_ONLY) == 0) || 2098 context->get(index)->IsTheHole()) { 2099 context->set(index, *initial_value); 2100 } 2101 } else { 2102 // Slow case: The property is in the context extension object of a 2103 // function context or the global object of a native context. 2104 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2105 RETURN_IF_EMPTY_HANDLE( 2106 isolate, 2107 JSReceiver::SetProperty(object, name, initial_value, mode, 2108 kNonStrictMode)); 2109 } 2110 } 2111 2112 } else { 2113 // The property is not in the function context. It needs to be 2114 // "declared" in the function context's extension context or as a 2115 // property of the the global object. 2116 Handle<JSObject> object; 2117 if (context->has_extension()) { 2118 object = Handle<JSObject>(JSObject::cast(context->extension())); 2119 } else { 2120 // Context extension objects are allocated lazily. 2121 ASSERT(context->IsFunctionContext()); 2122 object = isolate->factory()->NewJSObject( 2123 isolate->context_extension_function()); 2124 context->set_extension(*object); 2125 } 2126 ASSERT(*object != NULL); 2127 2128 // Declare the property by setting it to the initial value if provided, 2129 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 2130 // constant declarations). 2131 ASSERT(!object->HasLocalProperty(*name)); 2132 Handle<Object> value(isolate->heap()->undefined_value(), isolate); 2133 if (*initial_value != NULL) value = initial_value; 2134 // Declaring a const context slot is a conflicting declaration if 2135 // there is a callback with that name in a prototype. It is 2136 // allowed to introduce const variables in 2137 // JSContextExtensionObjects. They are treated specially in 2138 // SetProperty and no setters are invoked for those since they are 2139 // not real JSObjects. 2140 if (initial_value->IsTheHole() && 2141 !object->IsJSContextExtensionObject()) { 2142 LookupResult lookup(isolate); 2143 object->Lookup(*name, &lookup); 2144 if (lookup.IsPropertyCallbacks()) { 2145 return ThrowRedeclarationError(isolate, "const", name); 2146 } 2147 } 2148 if (object->IsJSGlobalObject()) { 2149 // Define own property on the global object. 2150 RETURN_IF_EMPTY_HANDLE(isolate, 2151 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode)); 2152 } else { 2153 RETURN_IF_EMPTY_HANDLE(isolate, 2154 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); 2155 } 2156 } 2157 2158 return isolate->heap()->undefined_value(); 2159 } 2160 2161 2162 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { 2163 SealHandleScope shs(isolate); 2164 // args[0] == name 2165 // args[1] == language_mode 2166 // args[2] == value (optional) 2167 2168 // Determine if we need to assign to the variable if it already 2169 // exists (based on the number of arguments). 2170 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); 2171 bool assign = args.length() == 3; 2172 2173 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2174 GlobalObject* global = isolate->context()->global_object(); 2175 RUNTIME_ASSERT(args[1]->IsSmi()); 2176 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); 2177 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) 2178 ? kNonStrictMode : kStrictMode; 2179 2180 // According to ECMA-262, section 12.2, page 62, the property must 2181 // not be deletable. 2182 PropertyAttributes attributes = DONT_DELETE; 2183 2184 // Lookup the property locally in the global object. If it isn't 2185 // there, there is a property with this name in the prototype chain. 2186 // We follow Safari and Firefox behavior and only set the property 2187 // locally if there is an explicit initialization value that we have 2188 // to assign to the property. 2189 // Note that objects can have hidden prototypes, so we need to traverse 2190 // the whole chain of hidden prototypes to do a 'local' lookup. 2191 Object* object = global; 2192 LookupResult lookup(isolate); 2193 JSObject::cast(object)->LocalLookup(*name, &lookup, true); 2194 if (lookup.IsInterceptor()) { 2195 HandleScope handle_scope(isolate); 2196 PropertyAttributes intercepted = 2197 lookup.holder()->GetPropertyAttribute(*name); 2198 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 2199 // Found an interceptor that's not read only. 2200 if (assign) { 2201 return lookup.holder()->SetProperty( 2202 &lookup, *name, args[2], attributes, strict_mode_flag); 2203 } else { 2204 return isolate->heap()->undefined_value(); 2205 } 2206 } 2207 } 2208 2209 // Reload global in case the loop above performed a GC. 2210 global = isolate->context()->global_object(); 2211 if (assign) { 2212 return global->SetProperty(*name, args[2], attributes, strict_mode_flag); 2213 } 2214 return isolate->heap()->undefined_value(); 2215 } 2216 2217 2218 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { 2219 SealHandleScope shs(isolate); 2220 // All constants are declared with an initial value. The name 2221 // of the constant is the first argument and the initial value 2222 // is the second. 2223 RUNTIME_ASSERT(args.length() == 2); 2224 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2225 Handle<Object> value = args.at<Object>(1); 2226 2227 // Get the current global object from top. 2228 GlobalObject* global = isolate->context()->global_object(); 2229 2230 // According to ECMA-262, section 12.2, page 62, the property must 2231 // not be deletable. Since it's a const, it must be READ_ONLY too. 2232 PropertyAttributes attributes = 2233 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 2234 2235 // Lookup the property locally in the global object. If it isn't 2236 // there, we add the property and take special precautions to always 2237 // add it as a local property even in case of callbacks in the 2238 // prototype chain (this rules out using SetProperty). 2239 // We use SetLocalPropertyIgnoreAttributes instead 2240 LookupResult lookup(isolate); 2241 global->LocalLookup(*name, &lookup); 2242 if (!lookup.IsFound()) { 2243 return global->SetLocalPropertyIgnoreAttributes(*name, 2244 *value, 2245 attributes); 2246 } 2247 2248 if (!lookup.IsReadOnly()) { 2249 // Restore global object from context (in case of GC) and continue 2250 // with setting the value. 2251 HandleScope handle_scope(isolate); 2252 Handle<GlobalObject> global(isolate->context()->global_object()); 2253 2254 // BUG 1213575: Handle the case where we have to set a read-only 2255 // property through an interceptor and only do it if it's 2256 // uninitialized, e.g. the hole. Nirk... 2257 // Passing non-strict mode because the property is writable. 2258 RETURN_IF_EMPTY_HANDLE( 2259 isolate, 2260 JSReceiver::SetProperty(global, name, value, attributes, 2261 kNonStrictMode)); 2262 return *value; 2263 } 2264 2265 // Set the value, but only if we're assigning the initial value to a 2266 // constant. For now, we determine this by checking if the 2267 // current value is the hole. 2268 // Strict mode handling not needed (const is disallowed in strict mode). 2269 if (lookup.IsField()) { 2270 FixedArray* properties = global->properties(); 2271 int index = lookup.GetFieldIndex().field_index(); 2272 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { 2273 properties->set(index, *value); 2274 } 2275 } else if (lookup.IsNormal()) { 2276 if (global->GetNormalizedProperty(&lookup)->IsTheHole() || 2277 !lookup.IsReadOnly()) { 2278 HandleScope scope(isolate); 2279 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value); 2280 } 2281 } else { 2282 // Ignore re-initialization of constants that have already been 2283 // assigned a constant value. 2284 ASSERT(lookup.IsReadOnly() && lookup.IsConstant()); 2285 } 2286 2287 // Use the set value as the result of the operation. 2288 return *value; 2289 } 2290 2291 2292 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { 2293 HandleScope scope(isolate); 2294 ASSERT(args.length() == 3); 2295 2296 Handle<Object> value(args[0], isolate); 2297 ASSERT(!value->IsTheHole()); 2298 2299 // Initializations are always done in a function or native context. 2300 RUNTIME_ASSERT(args[1]->IsContext()); 2301 Handle<Context> context(Context::cast(args[1])->declaration_context()); 2302 2303 Handle<String> name(String::cast(args[2])); 2304 2305 int index; 2306 PropertyAttributes attributes; 2307 ContextLookupFlags flags = FOLLOW_CHAINS; 2308 BindingFlags binding_flags; 2309 Handle<Object> holder = 2310 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2311 2312 if (index >= 0) { 2313 ASSERT(holder->IsContext()); 2314 // Property was found in a context. Perform the assignment if we 2315 // found some non-constant or an uninitialized constant. 2316 Handle<Context> context = Handle<Context>::cast(holder); 2317 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { 2318 context->set(index, *value); 2319 } 2320 return *value; 2321 } 2322 2323 // The property could not be found, we introduce it as a property of the 2324 // global object. 2325 if (attributes == ABSENT) { 2326 Handle<JSObject> global = Handle<JSObject>( 2327 isolate->context()->global_object()); 2328 // Strict mode not needed (const disallowed in strict mode). 2329 RETURN_IF_EMPTY_HANDLE( 2330 isolate, 2331 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode)); 2332 return *value; 2333 } 2334 2335 // The property was present in some function's context extension object, 2336 // as a property on the subject of a with, or as a property of the global 2337 // object. 2338 // 2339 // In most situations, eval-introduced consts should still be present in 2340 // the context extension object. However, because declaration and 2341 // initialization are separate, the property might have been deleted 2342 // before we reach the initialization point. 2343 // 2344 // Example: 2345 // 2346 // function f() { eval("delete x; const x;"); } 2347 // 2348 // In that case, the initialization behaves like a normal assignment. 2349 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2350 2351 if (*object == context->extension()) { 2352 // This is the property that was introduced by the const declaration. 2353 // Set it if it hasn't been set before. NOTE: We cannot use 2354 // GetProperty() to get the current value as it 'unholes' the value. 2355 LookupResult lookup(isolate); 2356 object->LocalLookupRealNamedProperty(*name, &lookup); 2357 ASSERT(lookup.IsFound()); // the property was declared 2358 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 2359 2360 if (lookup.IsField()) { 2361 FixedArray* properties = object->properties(); 2362 int index = lookup.GetFieldIndex().field_index(); 2363 if (properties->get(index)->IsTheHole()) { 2364 properties->set(index, *value); 2365 } 2366 } else if (lookup.IsNormal()) { 2367 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { 2368 JSObject::SetNormalizedProperty(object, &lookup, value); 2369 } 2370 } else { 2371 // We should not reach here. Any real, named property should be 2372 // either a field or a dictionary slot. 2373 UNREACHABLE(); 2374 } 2375 } else { 2376 // The property was found on some other object. Set it if it is not a 2377 // read-only property. 2378 if ((attributes & READ_ONLY) == 0) { 2379 // Strict mode not needed (const disallowed in strict mode). 2380 RETURN_IF_EMPTY_HANDLE( 2381 isolate, 2382 JSReceiver::SetProperty(object, name, value, attributes, 2383 kNonStrictMode)); 2384 } 2385 } 2386 2387 return *value; 2388 } 2389 2390 2391 RUNTIME_FUNCTION(MaybeObject*, 2392 Runtime_OptimizeObjectForAddingMultipleProperties) { 2393 HandleScope scope(isolate); 2394 ASSERT(args.length() == 2); 2395 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 2396 CONVERT_SMI_ARG_CHECKED(properties, 1); 2397 if (object->HasFastProperties()) { 2398 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 2399 } 2400 return *object; 2401 } 2402 2403 2404 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { 2405 HandleScope scope(isolate); 2406 ASSERT(args.length() == 4); 2407 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 2408 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 2409 // Due to the way the JS calls are constructed this must be less than the 2410 // length of a string, i.e. it is always a Smi. We check anyway for security. 2411 CONVERT_SMI_ARG_CHECKED(index, 2); 2412 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 2413 RUNTIME_ASSERT(index >= 0); 2414 RUNTIME_ASSERT(index <= subject->length()); 2415 isolate->counters()->regexp_entry_runtime()->Increment(); 2416 Handle<Object> result = RegExpImpl::Exec(regexp, 2417 subject, 2418 index, 2419 last_match_info); 2420 RETURN_IF_EMPTY_HANDLE(isolate, result); 2421 return *result; 2422 } 2423 2424 2425 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) { 2426 SealHandleScope shs(isolate); 2427 ASSERT(args.length() == 3); 2428 CONVERT_SMI_ARG_CHECKED(elements_count, 0); 2429 if (elements_count < 0 || 2430 elements_count > FixedArray::kMaxLength || 2431 !Smi::IsValid(elements_count)) { 2432 return isolate->ThrowIllegalOperation(); 2433 } 2434 Object* new_object; 2435 { MaybeObject* maybe_new_object = 2436 isolate->heap()->AllocateFixedArray(elements_count); 2437 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 2438 } 2439 FixedArray* elements = FixedArray::cast(new_object); 2440 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw( 2441 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE); 2442 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 2443 } 2444 { 2445 DisallowHeapAllocation no_gc; 2446 HandleScope scope(isolate); 2447 reinterpret_cast<HeapObject*>(new_object)-> 2448 set_map(isolate->native_context()->regexp_result_map()); 2449 } 2450 JSArray* array = JSArray::cast(new_object); 2451 array->set_properties(isolate->heap()->empty_fixed_array()); 2452 array->set_elements(elements); 2453 array->set_length(Smi::FromInt(elements_count)); 2454 // Write in-object properties after the length of the array. 2455 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); 2456 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); 2457 return array; 2458 } 2459 2460 2461 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { 2462 SealHandleScope shs(isolate); 2463 DisallowHeapAllocation no_allocation; 2464 ASSERT(args.length() == 5); 2465 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0); 2466 CONVERT_ARG_CHECKED(String, source, 1); 2467 // If source is the empty string we set it to "(?:)" instead as 2468 // suggested by ECMA-262, 5th, section 15.10.4.1. 2469 if (source->length() == 0) source = isolate->heap()->query_colon_string(); 2470 2471 Object* global = args[2]; 2472 if (!global->IsTrue()) global = isolate->heap()->false_value(); 2473 2474 Object* ignoreCase = args[3]; 2475 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value(); 2476 2477 Object* multiline = args[4]; 2478 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value(); 2479 2480 Map* map = regexp->map(); 2481 Object* constructor = map->constructor(); 2482 if (constructor->IsJSFunction() && 2483 JSFunction::cast(constructor)->initial_map() == map) { 2484 // If we still have the original map, set in-object properties directly. 2485 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source); 2486 // Both true and false are immovable immortal objects so no need for write 2487 // barrier. 2488 regexp->InObjectPropertyAtPut( 2489 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER); 2490 regexp->InObjectPropertyAtPut( 2491 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER); 2492 regexp->InObjectPropertyAtPut( 2493 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER); 2494 regexp->InObjectPropertyAtPut( 2495 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER); 2496 return regexp; 2497 } 2498 2499 // Map has changed, so use generic, but slower, method. 2500 PropertyAttributes final = 2501 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 2502 PropertyAttributes writable = 2503 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 2504 Heap* heap = isolate->heap(); 2505 MaybeObject* result; 2506 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_string(), 2507 source, 2508 final); 2509 // TODO(jkummerow): Turn these back into ASSERTs when we can be certain 2510 // that it never fires in Release mode in the wild. 2511 CHECK(!result->IsFailure()); 2512 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_string(), 2513 global, 2514 final); 2515 CHECK(!result->IsFailure()); 2516 result = 2517 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_string(), 2518 ignoreCase, 2519 final); 2520 CHECK(!result->IsFailure()); 2521 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_string(), 2522 multiline, 2523 final); 2524 CHECK(!result->IsFailure()); 2525 result = 2526 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_string(), 2527 Smi::FromInt(0), 2528 writable); 2529 CHECK(!result->IsFailure()); 2530 USE(result); 2531 return regexp; 2532 } 2533 2534 2535 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { 2536 HandleScope scope(isolate); 2537 ASSERT(args.length() == 1); 2538 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); 2539 // This is necessary to enable fast checks for absence of elements 2540 // on Array.prototype and below. 2541 prototype->set_elements(isolate->heap()->empty_fixed_array()); 2542 return Smi::FromInt(0); 2543 } 2544 2545 2546 static Handle<JSFunction> InstallBuiltin(Isolate* isolate, 2547 Handle<JSObject> holder, 2548 const char* name, 2549 Builtins::Name builtin_name) { 2550 Handle<String> key = isolate->factory()->InternalizeUtf8String(name); 2551 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); 2552 Handle<JSFunction> optimized = 2553 isolate->factory()->NewFunction(key, 2554 JS_OBJECT_TYPE, 2555 JSObject::kHeaderSize, 2556 code, 2557 false); 2558 optimized->shared()->DontAdaptArguments(); 2559 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode); 2560 return optimized; 2561 } 2562 2563 2564 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { 2565 HandleScope scope(isolate); 2566 ASSERT(args.length() == 1); 2567 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0); 2568 2569 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); 2570 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); 2571 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); 2572 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); 2573 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); 2574 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); 2575 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); 2576 2577 return *holder; 2578 } 2579 2580 2581 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) { 2582 SealHandleScope shs(isolate); 2583 ASSERT(args.length() == 1); 2584 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2585 if (!callable->IsJSFunction()) { 2586 HandleScope scope(isolate); 2587 bool threw = false; 2588 Handle<Object> delegate = 2589 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw); 2590 if (threw) return Failure::Exception(); 2591 callable = JSFunction::cast(*delegate); 2592 } 2593 JSFunction* function = JSFunction::cast(callable); 2594 SharedFunctionInfo* shared = function->shared(); 2595 return isolate->heap()->ToBoolean(shared->is_classic_mode()); 2596 } 2597 2598 2599 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { 2600 SealHandleScope shs(isolate); 2601 ASSERT(args.length() == 1); 2602 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2603 2604 if (!callable->IsJSFunction()) { 2605 HandleScope scope(isolate); 2606 bool threw = false; 2607 Handle<Object> delegate = 2608 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw); 2609 if (threw) return Failure::Exception(); 2610 callable = JSFunction::cast(*delegate); 2611 } 2612 JSFunction* function = JSFunction::cast(callable); 2613 2614 SharedFunctionInfo* shared = function->shared(); 2615 if (shared->native() || !shared->is_classic_mode()) { 2616 return isolate->heap()->undefined_value(); 2617 } 2618 // Returns undefined for strict or native functions, or 2619 // the associated global receiver for "normal" functions. 2620 2621 Context* native_context = 2622 function->context()->global_object()->native_context(); 2623 return native_context->global_object()->global_receiver(); 2624 } 2625 2626 2627 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { 2628 HandleScope scope(isolate); 2629 ASSERT(args.length() == 4); 2630 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 2631 int index = args.smi_at(1); 2632 Handle<String> pattern = args.at<String>(2); 2633 Handle<String> flags = args.at<String>(3); 2634 2635 // Get the RegExp function from the context in the literals array. 2636 // This is the RegExp function from the context in which the 2637 // function was created. We do not use the RegExp function from the 2638 // current native context because this might be the RegExp function 2639 // from another context which we should not have access to. 2640 Handle<JSFunction> constructor = 2641 Handle<JSFunction>( 2642 JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); 2643 // Compute the regular expression literal. 2644 bool has_pending_exception; 2645 Handle<Object> regexp = 2646 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, 2647 &has_pending_exception); 2648 if (has_pending_exception) { 2649 ASSERT(isolate->has_pending_exception()); 2650 return Failure::Exception(); 2651 } 2652 literals->set(index, *regexp); 2653 return *regexp; 2654 } 2655 2656 2657 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { 2658 SealHandleScope shs(isolate); 2659 ASSERT(args.length() == 1); 2660 2661 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2662 return f->shared()->name(); 2663 } 2664 2665 2666 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { 2667 SealHandleScope shs(isolate); 2668 ASSERT(args.length() == 2); 2669 2670 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2671 CONVERT_ARG_CHECKED(String, name, 1); 2672 f->shared()->set_name(name); 2673 return isolate->heap()->undefined_value(); 2674 } 2675 2676 2677 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) { 2678 SealHandleScope shs(isolate); 2679 ASSERT(args.length() == 1); 2680 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2681 return isolate->heap()->ToBoolean( 2682 f->shared()->name_should_print_as_anonymous()); 2683 } 2684 2685 2686 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 2687 SealHandleScope shs(isolate); 2688 ASSERT(args.length() == 1); 2689 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2690 f->shared()->set_name_should_print_as_anonymous(true); 2691 return isolate->heap()->undefined_value(); 2692 } 2693 2694 2695 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) { 2696 SealHandleScope shs(isolate); 2697 ASSERT(args.length() == 1); 2698 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2699 return isolate->heap()->ToBoolean(f->shared()->is_generator()); 2700 } 2701 2702 2703 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { 2704 SealHandleScope shs(isolate); 2705 ASSERT(args.length() == 1); 2706 2707 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2708 f->RemovePrototype(); 2709 2710 return isolate->heap()->undefined_value(); 2711 } 2712 2713 2714 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { 2715 HandleScope scope(isolate); 2716 ASSERT(args.length() == 1); 2717 2718 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2719 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); 2720 if (!script->IsScript()) return isolate->heap()->undefined_value(); 2721 2722 return *GetScriptWrapper(Handle<Script>::cast(script)); 2723 } 2724 2725 2726 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { 2727 HandleScope scope(isolate); 2728 ASSERT(args.length() == 1); 2729 2730 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); 2731 Handle<SharedFunctionInfo> shared(f->shared()); 2732 return *shared->GetSourceCode(); 2733 } 2734 2735 2736 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { 2737 SealHandleScope shs(isolate); 2738 ASSERT(args.length() == 1); 2739 2740 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2741 int pos = fun->shared()->start_position(); 2742 return Smi::FromInt(pos); 2743 } 2744 2745 2746 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { 2747 SealHandleScope shs(isolate); 2748 ASSERT(args.length() == 2); 2749 2750 CONVERT_ARG_CHECKED(Code, code, 0); 2751 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 2752 2753 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 2754 2755 Address pc = code->address() + offset; 2756 return Smi::FromInt(code->SourcePosition(pc)); 2757 } 2758 2759 2760 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { 2761 SealHandleScope shs(isolate); 2762 ASSERT(args.length() == 2); 2763 2764 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2765 CONVERT_ARG_CHECKED(String, name, 1); 2766 fun->SetInstanceClassName(name); 2767 return isolate->heap()->undefined_value(); 2768 } 2769 2770 2771 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { 2772 SealHandleScope shs(isolate); 2773 ASSERT(args.length() == 2); 2774 2775 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2776 CONVERT_SMI_ARG_CHECKED(length, 1); 2777 fun->shared()->set_length(length); 2778 return isolate->heap()->undefined_value(); 2779 } 2780 2781 2782 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { 2783 SealHandleScope shs(isolate); 2784 ASSERT(args.length() == 2); 2785 2786 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2787 ASSERT(fun->should_have_prototype()); 2788 Object* obj; 2789 { MaybeObject* maybe_obj = 2790 Accessors::FunctionSetPrototype(fun, args[1], NULL); 2791 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2792 } 2793 return args[0]; // return TOS 2794 } 2795 2796 2797 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { 2798 SealHandleScope shs(isolate); 2799 RUNTIME_ASSERT(args.length() == 1); 2800 CONVERT_ARG_CHECKED(JSFunction, function, 0); 2801 2802 String* name = isolate->heap()->prototype_string(); 2803 2804 if (function->HasFastProperties()) { 2805 // Construct a new field descriptor with updated attributes. 2806 DescriptorArray* instance_desc = function->map()->instance_descriptors(); 2807 2808 int index = instance_desc->SearchWithCache(name, function->map()); 2809 ASSERT(index != DescriptorArray::kNotFound); 2810 PropertyDetails details = instance_desc->GetDetails(index); 2811 2812 CallbacksDescriptor new_desc(name, 2813 instance_desc->GetValue(index), 2814 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY)); 2815 2816 // Create a new map featuring the new field descriptors array. 2817 Map* new_map; 2818 MaybeObject* maybe_map = 2819 function->map()->CopyReplaceDescriptor( 2820 instance_desc, &new_desc, index, OMIT_TRANSITION); 2821 if (!maybe_map->To(&new_map)) return maybe_map; 2822 2823 function->set_map(new_map); 2824 } else { // Dictionary properties. 2825 // Directly manipulate the property details. 2826 int entry = function->property_dictionary()->FindEntry(name); 2827 ASSERT(entry != NameDictionary::kNotFound); 2828 PropertyDetails details = function->property_dictionary()->DetailsAt(entry); 2829 PropertyDetails new_details( 2830 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), 2831 details.type(), 2832 details.dictionary_index()); 2833 function->property_dictionary()->DetailsAtPut(entry, new_details); 2834 } 2835 return function; 2836 } 2837 2838 2839 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { 2840 SealHandleScope shs(isolate); 2841 ASSERT(args.length() == 1); 2842 2843 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2844 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); 2845 } 2846 2847 2848 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { 2849 SealHandleScope shs(isolate); 2850 ASSERT(args.length() == 1); 2851 2852 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2853 return isolate->heap()->ToBoolean(f->IsBuiltin()); 2854 } 2855 2856 2857 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { 2858 HandleScope scope(isolate); 2859 ASSERT(args.length() == 2); 2860 2861 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 2862 Handle<Object> code = args.at<Object>(1); 2863 2864 if (code->IsNull()) return *target; 2865 RUNTIME_ASSERT(code->IsJSFunction()); 2866 Handle<JSFunction> source = Handle<JSFunction>::cast(code); 2867 Handle<SharedFunctionInfo> target_shared(target->shared()); 2868 Handle<SharedFunctionInfo> source_shared(source->shared()); 2869 2870 if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) { 2871 return Failure::Exception(); 2872 } 2873 2874 // Mark both, the source and the target, as un-flushable because the 2875 // shared unoptimized code makes them impossible to enqueue in a list. 2876 ASSERT(target_shared->code()->gc_metadata() == NULL); 2877 ASSERT(source_shared->code()->gc_metadata() == NULL); 2878 target_shared->set_dont_flush(true); 2879 source_shared->set_dont_flush(true); 2880 2881 // Set the code, scope info, formal parameter count, and the length 2882 // of the target shared function info. Set the source code of the 2883 // target function to undefined. SetCode is only used for built-in 2884 // constructors like String, Array, and Object, and some web code 2885 // doesn't like seeing source code for constructors. 2886 target_shared->ReplaceCode(source_shared->code()); 2887 target_shared->set_scope_info(source_shared->scope_info()); 2888 target_shared->set_length(source_shared->length()); 2889 target_shared->set_formal_parameter_count( 2890 source_shared->formal_parameter_count()); 2891 target_shared->set_script(isolate->heap()->undefined_value()); 2892 2893 // Since we don't store the source we should never optimize this. 2894 target_shared->code()->set_optimizable(false); 2895 2896 // Set the code of the target function. 2897 target->ReplaceCode(source_shared->code()); 2898 ASSERT(target->next_function_link()->IsUndefined()); 2899 2900 // Make sure we get a fresh copy of the literal vector to avoid cross 2901 // context contamination. 2902 Handle<Context> context(source->context()); 2903 int number_of_literals = source->NumberOfLiterals(); 2904 Handle<FixedArray> literals = 2905 isolate->factory()->NewFixedArray(number_of_literals, TENURED); 2906 if (number_of_literals > 0) { 2907 literals->set(JSFunction::kLiteralNativeContextIndex, 2908 context->native_context()); 2909 } 2910 target->set_context(*context); 2911 target->set_literals(*literals); 2912 2913 if (isolate->logger()->is_logging_code_events() || 2914 isolate->cpu_profiler()->is_profiling()) { 2915 isolate->logger()->LogExistingFunction( 2916 source_shared, Handle<Code>(source_shared->code())); 2917 } 2918 2919 return *target; 2920 } 2921 2922 2923 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) { 2924 HandleScope scope(isolate); 2925 ASSERT(args.length() == 2); 2926 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 2927 CONVERT_SMI_ARG_CHECKED(num, 1); 2928 RUNTIME_ASSERT(num >= 0); 2929 SetExpectedNofProperties(function, num); 2930 return isolate->heap()->undefined_value(); 2931 } 2932 2933 2934 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) { 2935 SealHandleScope shs(isolate); 2936 ASSERT(args.length() == 0); 2937 2938 JavaScriptFrameIterator it(isolate); 2939 JavaScriptFrame* frame = it.frame(); 2940 JSFunction* function = frame->function(); 2941 RUNTIME_ASSERT(function->shared()->is_generator()); 2942 2943 JSGeneratorObject* generator; 2944 if (frame->IsConstructor()) { 2945 generator = JSGeneratorObject::cast(frame->receiver()); 2946 } else { 2947 MaybeObject* maybe_generator = 2948 isolate->heap()->AllocateJSGeneratorObject(function); 2949 if (!maybe_generator->To(&generator)) return maybe_generator; 2950 } 2951 generator->set_function(function); 2952 generator->set_context(Context::cast(frame->context())); 2953 generator->set_receiver(frame->receiver()); 2954 generator->set_continuation(0); 2955 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); 2956 generator->set_stack_handler_index(-1); 2957 2958 return generator; 2959 } 2960 2961 2962 RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { 2963 SealHandleScope shs(isolate); 2964 ASSERT(args.length() == 1); 2965 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); 2966 2967 JavaScriptFrameIterator stack_iterator(isolate); 2968 JavaScriptFrame* frame = stack_iterator.frame(); 2969 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); 2970 ASSERT_EQ(frame->function(), generator_object->function()); 2971 2972 // The caller should have saved the context and continuation already. 2973 ASSERT_EQ(generator_object->context(), Context::cast(frame->context())); 2974 ASSERT_LT(0, generator_object->continuation()); 2975 2976 // We expect there to be at least two values on the operand stack: the return 2977 // value of the yield expression, and the argument to this runtime call. 2978 // Neither of those should be saved. 2979 int operands_count = frame->ComputeOperandsCount(); 2980 ASSERT_GE(operands_count, 2); 2981 operands_count -= 2; 2982 2983 if (operands_count == 0) { 2984 // Although it's semantically harmless to call this function with an 2985 // operands_count of zero, it is also unnecessary. 2986 ASSERT_EQ(generator_object->operand_stack(), 2987 isolate->heap()->empty_fixed_array()); 2988 ASSERT_EQ(generator_object->stack_handler_index(), -1); 2989 // If there are no operands on the stack, there shouldn't be a handler 2990 // active either. 2991 ASSERT(!frame->HasHandler()); 2992 } else { 2993 int stack_handler_index = -1; 2994 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count); 2995 FixedArray* operand_stack; 2996 if (!alloc->To(&operand_stack)) return alloc; 2997 frame->SaveOperandStack(operand_stack, &stack_handler_index); 2998 generator_object->set_operand_stack(operand_stack); 2999 generator_object->set_stack_handler_index(stack_handler_index); 3000 } 3001 3002 return isolate->heap()->undefined_value(); 3003 } 3004 3005 3006 // Note that this function is the slow path for resuming generators. It is only 3007 // called if the suspended activation had operands on the stack, stack handlers 3008 // needing rewinding, or if the resume should throw an exception. The fast path 3009 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is 3010 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is 3011 // called in any case, as it needs to reconstruct the stack frame and make space 3012 // for arguments and operands. 3013 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { 3014 SealHandleScope shs(isolate); 3015 ASSERT(args.length() == 3); 3016 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); 3017 CONVERT_ARG_CHECKED(Object, value, 1); 3018 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); 3019 JavaScriptFrameIterator stack_iterator(isolate); 3020 JavaScriptFrame* frame = stack_iterator.frame(); 3021 3022 ASSERT_EQ(frame->function(), generator_object->function()); 3023 ASSERT(frame->function()->is_compiled()); 3024 3025 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); 3026 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); 3027 3028 Address pc = generator_object->function()->code()->instruction_start(); 3029 int offset = generator_object->continuation(); 3030 ASSERT(offset > 0); 3031 frame->set_pc(pc + offset); 3032 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); 3033 3034 FixedArray* operand_stack = generator_object->operand_stack(); 3035 int operands_count = operand_stack->length(); 3036 if (operands_count != 0) { 3037 frame->RestoreOperandStack(operand_stack, 3038 generator_object->stack_handler_index()); 3039 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); 3040 generator_object->set_stack_handler_index(-1); 3041 } 3042 3043 JSGeneratorObject::ResumeMode resume_mode = 3044 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); 3045 switch (resume_mode) { 3046 case JSGeneratorObject::NEXT: 3047 return value; 3048 case JSGeneratorObject::THROW: 3049 return isolate->Throw(value); 3050 } 3051 3052 UNREACHABLE(); 3053 return isolate->ThrowIllegalOperation(); 3054 } 3055 3056 3057 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { 3058 HandleScope scope(isolate); 3059 ASSERT(args.length() == 1); 3060 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); 3061 int continuation = generator->continuation(); 3062 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ? 3063 "generator_finished" : "generator_running"; 3064 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0); 3065 Handle<Object> error = isolate->factory()->NewError(message, argv); 3066 return isolate->Throw(*error); 3067 } 3068 3069 3070 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) { 3071 SealHandleScope shs(isolate); 3072 ASSERT(args.length() == 1); 3073 CONVERT_ARG_CHECKED(JSObject, object, 0); 3074 return object->Freeze(isolate); 3075 } 3076 3077 3078 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate, 3079 Object* char_code) { 3080 if (char_code->IsNumber()) { 3081 return isolate->heap()->LookupSingleCharacterStringFromCode( 3082 NumberToUint32(char_code) & 0xffff); 3083 } 3084 return isolate->heap()->empty_string(); 3085 } 3086 3087 3088 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { 3089 SealHandleScope shs(isolate); 3090 ASSERT(args.length() == 2); 3091 3092 CONVERT_ARG_CHECKED(String, subject, 0); 3093 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); 3094 3095 // Flatten the string. If someone wants to get a char at an index 3096 // in a cons string, it is likely that more indices will be 3097 // accessed. 3098 Object* flat; 3099 { MaybeObject* maybe_flat = subject->TryFlatten(); 3100 if (!maybe_flat->ToObject(&flat)) return maybe_flat; 3101 } 3102 subject = String::cast(flat); 3103 3104 if (i >= static_cast<uint32_t>(subject->length())) { 3105 return isolate->heap()->nan_value(); 3106 } 3107 3108 return Smi::FromInt(subject->Get(i)); 3109 } 3110 3111 3112 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) { 3113 SealHandleScope shs(isolate); 3114 ASSERT(args.length() == 1); 3115 return CharFromCode(isolate, args[0]); 3116 } 3117 3118 3119 class FixedArrayBuilder { 3120 public: 3121 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) 3122 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), 3123 length_(0), 3124 has_non_smi_elements_(false) { 3125 // Require a non-zero initial size. Ensures that doubling the size to 3126 // extend the array will work. 3127 ASSERT(initial_capacity > 0); 3128 } 3129 3130 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) 3131 : array_(backing_store), 3132 length_(0), 3133 has_non_smi_elements_(false) { 3134 // Require a non-zero initial size. Ensures that doubling the size to 3135 // extend the array will work. 3136 ASSERT(backing_store->length() > 0); 3137 } 3138 3139 bool HasCapacity(int elements) { 3140 int length = array_->length(); 3141 int required_length = length_ + elements; 3142 return (length >= required_length); 3143 } 3144 3145 void EnsureCapacity(int elements) { 3146 int length = array_->length(); 3147 int required_length = length_ + elements; 3148 if (length < required_length) { 3149 int new_length = length; 3150 do { 3151 new_length *= 2; 3152 } while (new_length < required_length); 3153 Handle<FixedArray> extended_array = 3154 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); 3155 array_->CopyTo(0, *extended_array, 0, length_); 3156 array_ = extended_array; 3157 } 3158 } 3159 3160 void Add(Object* value) { 3161 ASSERT(!value->IsSmi()); 3162 ASSERT(length_ < capacity()); 3163 array_->set(length_, value); 3164 length_++; 3165 has_non_smi_elements_ = true; 3166 } 3167 3168 void Add(Smi* value) { 3169 ASSERT(value->IsSmi()); 3170 ASSERT(length_ < capacity()); 3171 array_->set(length_, value); 3172 length_++; 3173 } 3174 3175 Handle<FixedArray> array() { 3176 return array_; 3177 } 3178 3179 int length() { 3180 return length_; 3181 } 3182 3183 int capacity() { 3184 return array_->length(); 3185 } 3186 3187 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { 3188 Factory* factory = target_array->GetIsolate()->factory(); 3189 factory->SetContent(target_array, array_); 3190 target_array->set_length(Smi::FromInt(length_)); 3191 return target_array; 3192 } 3193 3194 3195 private: 3196 Handle<FixedArray> array_; 3197 int length_; 3198 bool has_non_smi_elements_; 3199 }; 3200 3201 3202 // Forward declarations. 3203 const int kStringBuilderConcatHelperLengthBits = 11; 3204 const int kStringBuilderConcatHelperPositionBits = 19; 3205 3206 template <typename schar> 3207 static inline void StringBuilderConcatHelper(String*, 3208 schar*, 3209 FixedArray*, 3210 int); 3211 3212 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> 3213 StringBuilderSubstringLength; 3214 typedef BitField<int, 3215 kStringBuilderConcatHelperLengthBits, 3216 kStringBuilderConcatHelperPositionBits> 3217 StringBuilderSubstringPosition; 3218 3219 3220 class ReplacementStringBuilder { 3221 public: 3222 ReplacementStringBuilder(Heap* heap, 3223 Handle<String> subject, 3224 int estimated_part_count) 3225 : heap_(heap), 3226 array_builder_(heap->isolate(), estimated_part_count), 3227 subject_(subject), 3228 character_count_(0), 3229 is_ascii_(subject->IsOneByteRepresentation()) { 3230 // Require a non-zero initial size. Ensures that doubling the size to 3231 // extend the array will work. 3232 ASSERT(estimated_part_count > 0); 3233 } 3234 3235 static inline void AddSubjectSlice(FixedArrayBuilder* builder, 3236 int from, 3237 int to) { 3238 ASSERT(from >= 0); 3239 int length = to - from; 3240 ASSERT(length > 0); 3241 if (StringBuilderSubstringLength::is_valid(length) && 3242 StringBuilderSubstringPosition::is_valid(from)) { 3243 int encoded_slice = StringBuilderSubstringLength::encode(length) | 3244 StringBuilderSubstringPosition::encode(from); 3245 builder->Add(Smi::FromInt(encoded_slice)); 3246 } else { 3247 // Otherwise encode as two smis. 3248 builder->Add(Smi::FromInt(-length)); 3249 builder->Add(Smi::FromInt(from)); 3250 } 3251 } 3252 3253 3254 void EnsureCapacity(int elements) { 3255 array_builder_.EnsureCapacity(elements); 3256 } 3257 3258 3259 void AddSubjectSlice(int from, int to) { 3260 AddSubjectSlice(&array_builder_, from, to); 3261 IncrementCharacterCount(to - from); 3262 } 3263 3264 3265 void AddString(Handle<String> string) { 3266 int length = string->length(); 3267 ASSERT(length > 0); 3268 AddElement(*string); 3269 if (!string->IsOneByteRepresentation()) { 3270 is_ascii_ = false; 3271 } 3272 IncrementCharacterCount(length); 3273 } 3274 3275 3276 Handle<String> ToString() { 3277 if (array_builder_.length() == 0) { 3278 return heap_->isolate()->factory()->empty_string(); 3279 } 3280 3281 Handle<String> joined_string; 3282 if (is_ascii_) { 3283 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); 3284 DisallowHeapAllocation no_gc; 3285 uint8_t* char_buffer = seq->GetChars(); 3286 StringBuilderConcatHelper(*subject_, 3287 char_buffer, 3288 *array_builder_.array(), 3289 array_builder_.length()); 3290 joined_string = Handle<String>::cast(seq); 3291 } else { 3292 // Non-ASCII. 3293 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_); 3294 DisallowHeapAllocation no_gc; 3295 uc16* char_buffer = seq->GetChars(); 3296 StringBuilderConcatHelper(*subject_, 3297 char_buffer, 3298 *array_builder_.array(), 3299 array_builder_.length()); 3300 joined_string = Handle<String>::cast(seq); 3301 } 3302 return joined_string; 3303 } 3304 3305 3306 void IncrementCharacterCount(int by) { 3307 if (character_count_ > String::kMaxLength - by) { 3308 V8::FatalProcessOutOfMemory("String.replace result too large."); 3309 } 3310 character_count_ += by; 3311 } 3312 3313 private: 3314 Handle<SeqOneByteString> NewRawOneByteString(int length) { 3315 return heap_->isolate()->factory()->NewRawOneByteString(length); 3316 } 3317 3318 3319 Handle<SeqTwoByteString> NewRawTwoByteString(int length) { 3320 return heap_->isolate()->factory()->NewRawTwoByteString(length); 3321 } 3322 3323 3324 void AddElement(Object* element) { 3325 ASSERT(element->IsSmi() || element->IsString()); 3326 ASSERT(array_builder_.capacity() > array_builder_.length()); 3327 array_builder_.Add(element); 3328 } 3329 3330 Heap* heap_; 3331 FixedArrayBuilder array_builder_; 3332 Handle<String> subject_; 3333 int character_count_; 3334 bool is_ascii_; 3335 }; 3336 3337 3338 class CompiledReplacement { 3339 public: 3340 explicit CompiledReplacement(Zone* zone) 3341 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} 3342 3343 // Return whether the replacement is simple. 3344 bool Compile(Handle<String> replacement, 3345 int capture_count, 3346 int subject_length); 3347 3348 // Use Apply only if Compile returned false. 3349 void Apply(ReplacementStringBuilder* builder, 3350 int match_from, 3351 int match_to, 3352 int32_t* match); 3353 3354 // Number of distinct parts of the replacement pattern. 3355 int parts() { 3356 return parts_.length(); 3357 } 3358 3359 Zone* zone() const { return zone_; } 3360 3361 private: 3362 enum PartType { 3363 SUBJECT_PREFIX = 1, 3364 SUBJECT_SUFFIX, 3365 SUBJECT_CAPTURE, 3366 REPLACEMENT_SUBSTRING, 3367 REPLACEMENT_STRING, 3368 3369 NUMBER_OF_PART_TYPES 3370 }; 3371 3372 struct ReplacementPart { 3373 static inline ReplacementPart SubjectMatch() { 3374 return ReplacementPart(SUBJECT_CAPTURE, 0); 3375 } 3376 static inline ReplacementPart SubjectCapture(int capture_index) { 3377 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 3378 } 3379 static inline ReplacementPart SubjectPrefix() { 3380 return ReplacementPart(SUBJECT_PREFIX, 0); 3381 } 3382 static inline ReplacementPart SubjectSuffix(int subject_length) { 3383 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 3384 } 3385 static inline ReplacementPart ReplacementString() { 3386 return ReplacementPart(REPLACEMENT_STRING, 0); 3387 } 3388 static inline ReplacementPart ReplacementSubString(int from, int to) { 3389 ASSERT(from >= 0); 3390 ASSERT(to > from); 3391 return ReplacementPart(-from, to); 3392 } 3393 3394 // If tag <= 0 then it is the negation of a start index of a substring of 3395 // the replacement pattern, otherwise it's a value from PartType. 3396 ReplacementPart(int tag, int data) 3397 : tag(tag), data(data) { 3398 // Must be non-positive or a PartType value. 3399 ASSERT(tag < NUMBER_OF_PART_TYPES); 3400 } 3401 // Either a value of PartType or a non-positive number that is 3402 // the negation of an index into the replacement string. 3403 int tag; 3404 // The data value's interpretation depends on the value of tag: 3405 // tag == SUBJECT_PREFIX || 3406 // tag == SUBJECT_SUFFIX: data is unused. 3407 // tag == SUBJECT_CAPTURE: data is the number of the capture. 3408 // tag == REPLACEMENT_SUBSTRING || 3409 // tag == REPLACEMENT_STRING: data is index into array of substrings 3410 // of the replacement string. 3411 // tag <= 0: Temporary representation of the substring of the replacement 3412 // string ranging over -tag .. data. 3413 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 3414 // substring objects. 3415 int data; 3416 }; 3417 3418 template<typename Char> 3419 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 3420 Vector<Char> characters, 3421 int capture_count, 3422 int subject_length, 3423 Zone* zone) { 3424 int length = characters.length(); 3425 int last = 0; 3426 for (int i = 0; i < length; i++) { 3427 Char c = characters[i]; 3428 if (c == '$') { 3429 int next_index = i + 1; 3430 if (next_index == length) { // No next character! 3431 break; 3432 } 3433 Char c2 = characters[next_index]; 3434 switch (c2) { 3435 case '$': 3436 if (i > last) { 3437 // There is a substring before. Include the first "$". 3438 parts->Add(ReplacementPart::ReplacementSubString(last, next_index), 3439 zone); 3440 last = next_index + 1; // Continue after the second "$". 3441 } else { 3442 // Let the next substring start with the second "$". 3443 last = next_index; 3444 } 3445 i = next_index; 3446 break; 3447 case '`': 3448 if (i > last) { 3449 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3450 } 3451 parts->Add(ReplacementPart::SubjectPrefix(), zone); 3452 i = next_index; 3453 last = i + 1; 3454 break; 3455 case '\'': 3456 if (i > last) { 3457 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3458 } 3459 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone); 3460 i = next_index; 3461 last = i + 1; 3462 break; 3463 case '&': 3464 if (i > last) { 3465 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3466 } 3467 parts->Add(ReplacementPart::SubjectMatch(), zone); 3468 i = next_index; 3469 last = i + 1; 3470 break; 3471 case '0': 3472 case '1': 3473 case '2': 3474 case '3': 3475 case '4': 3476 case '5': 3477 case '6': 3478 case '7': 3479 case '8': 3480 case '9': { 3481 int capture_ref = c2 - '0'; 3482 if (capture_ref > capture_count) { 3483 i = next_index; 3484 continue; 3485 } 3486 int second_digit_index = next_index + 1; 3487 if (second_digit_index < length) { 3488 // Peek ahead to see if we have two digits. 3489 Char c3 = characters[second_digit_index]; 3490 if ('0' <= c3 && c3 <= '9') { // Double digits. 3491 int double_digit_ref = capture_ref * 10 + c3 - '0'; 3492 if (double_digit_ref <= capture_count) { 3493 next_index = second_digit_index; 3494 capture_ref = double_digit_ref; 3495 } 3496 } 3497 } 3498 if (capture_ref > 0) { 3499 if (i > last) { 3500 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3501 } 3502 ASSERT(capture_ref <= capture_count); 3503 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); 3504 last = next_index + 1; 3505 } 3506 i = next_index; 3507 break; 3508 } 3509 default: 3510 i = next_index; 3511 break; 3512 } 3513 } 3514 } 3515 if (length > last) { 3516 if (last == 0) { 3517 // Replacement is simple. Do not use Apply to do the replacement. 3518 return true; 3519 } else { 3520 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); 3521 } 3522 } 3523 return false; 3524 } 3525 3526 ZoneList<ReplacementPart> parts_; 3527 ZoneList<Handle<String> > replacement_substrings_; 3528 Zone* zone_; 3529 }; 3530 3531 3532 bool CompiledReplacement::Compile(Handle<String> replacement, 3533 int capture_count, 3534 int subject_length) { 3535 { 3536 DisallowHeapAllocation no_gc; 3537 String::FlatContent content = replacement->GetFlatContent(); 3538 ASSERT(content.IsFlat()); 3539 bool simple = false; 3540 if (content.IsAscii()) { 3541 simple = ParseReplacementPattern(&parts_, 3542 content.ToOneByteVector(), 3543 capture_count, 3544 subject_length, 3545 zone()); 3546 } else { 3547 ASSERT(content.IsTwoByte()); 3548 simple = ParseReplacementPattern(&parts_, 3549 content.ToUC16Vector(), 3550 capture_count, 3551 subject_length, 3552 zone()); 3553 } 3554 if (simple) return true; 3555 } 3556 3557 Isolate* isolate = replacement->GetIsolate(); 3558 // Find substrings of replacement string and create them as String objects. 3559 int substring_index = 0; 3560 for (int i = 0, n = parts_.length(); i < n; i++) { 3561 int tag = parts_[i].tag; 3562 if (tag <= 0) { // A replacement string slice. 3563 int from = -tag; 3564 int to = parts_[i].data; 3565 replacement_substrings_.Add( 3566 isolate->factory()->NewSubString(replacement, from, to), zone()); 3567 parts_[i].tag = REPLACEMENT_SUBSTRING; 3568 parts_[i].data = substring_index; 3569 substring_index++; 3570 } else if (tag == REPLACEMENT_STRING) { 3571 replacement_substrings_.Add(replacement, zone()); 3572 parts_[i].data = substring_index; 3573 substring_index++; 3574 } 3575 } 3576 return false; 3577 } 3578 3579 3580 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 3581 int match_from, 3582 int match_to, 3583 int32_t* match) { 3584 ASSERT_LT(0, parts_.length()); 3585 for (int i = 0, n = parts_.length(); i < n; i++) { 3586 ReplacementPart part = parts_[i]; 3587 switch (part.tag) { 3588 case SUBJECT_PREFIX: 3589 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 3590 break; 3591 case SUBJECT_SUFFIX: { 3592 int subject_length = part.data; 3593 if (match_to < subject_length) { 3594 builder->AddSubjectSlice(match_to, subject_length); 3595 } 3596 break; 3597 } 3598 case SUBJECT_CAPTURE: { 3599 int capture = part.data; 3600 int from = match[capture * 2]; 3601 int to = match[capture * 2 + 1]; 3602 if (from >= 0 && to > from) { 3603 builder->AddSubjectSlice(from, to); 3604 } 3605 break; 3606 } 3607 case REPLACEMENT_SUBSTRING: 3608 case REPLACEMENT_STRING: 3609 builder->AddString(replacement_substrings_[part.data]); 3610 break; 3611 default: 3612 UNREACHABLE(); 3613 } 3614 } 3615 } 3616 3617 3618 void FindAsciiStringIndices(Vector<const uint8_t> subject, 3619 char pattern, 3620 ZoneList<int>* indices, 3621 unsigned int limit, 3622 Zone* zone) { 3623 ASSERT(limit > 0); 3624 // Collect indices of pattern in subject using memchr. 3625 // Stop after finding at most limit values. 3626 const uint8_t* subject_start = subject.start(); 3627 const uint8_t* subject_end = subject_start + subject.length(); 3628 const uint8_t* pos = subject_start; 3629 while (limit > 0) { 3630 pos = reinterpret_cast<const uint8_t*>( 3631 memchr(pos, pattern, subject_end - pos)); 3632 if (pos == NULL) return; 3633 indices->Add(static_cast<int>(pos - subject_start), zone); 3634 pos++; 3635 limit--; 3636 } 3637 } 3638 3639 3640 void FindTwoByteStringIndices(const Vector<const uc16> subject, 3641 uc16 pattern, 3642 ZoneList<int>* indices, 3643 unsigned int limit, 3644 Zone* zone) { 3645 ASSERT(limit > 0); 3646 const uc16* subject_start = subject.start(); 3647 const uc16* subject_end = subject_start + subject.length(); 3648 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { 3649 if (*pos == pattern) { 3650 indices->Add(static_cast<int>(pos - subject_start), zone); 3651 limit--; 3652 } 3653 } 3654 } 3655 3656 3657 template <typename SubjectChar, typename PatternChar> 3658 void FindStringIndices(Isolate* isolate, 3659 Vector<const SubjectChar> subject, 3660 Vector<const PatternChar> pattern, 3661 ZoneList<int>* indices, 3662 unsigned int limit, 3663 Zone* zone) { 3664 ASSERT(limit > 0); 3665 // Collect indices of pattern in subject. 3666 // Stop after finding at most limit values. 3667 int pattern_length = pattern.length(); 3668 int index = 0; 3669 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); 3670 while (limit > 0) { 3671 index = search.Search(subject, index); 3672 if (index < 0) return; 3673 indices->Add(index, zone); 3674 index += pattern_length; 3675 limit--; 3676 } 3677 } 3678 3679 3680 void FindStringIndicesDispatch(Isolate* isolate, 3681 String* subject, 3682 String* pattern, 3683 ZoneList<int>* indices, 3684 unsigned int limit, 3685 Zone* zone) { 3686 { 3687 DisallowHeapAllocation no_gc; 3688 String::FlatContent subject_content = subject->GetFlatContent(); 3689 String::FlatContent pattern_content = pattern->GetFlatContent(); 3690 ASSERT(subject_content.IsFlat()); 3691 ASSERT(pattern_content.IsFlat()); 3692 if (subject_content.IsAscii()) { 3693 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector(); 3694 if (pattern_content.IsAscii()) { 3695 Vector<const uint8_t> pattern_vector = 3696 pattern_content.ToOneByteVector(); 3697 if (pattern_vector.length() == 1) { 3698 FindAsciiStringIndices(subject_vector, 3699 pattern_vector[0], 3700 indices, 3701 limit, 3702 zone); 3703 } else { 3704 FindStringIndices(isolate, 3705 subject_vector, 3706 pattern_vector, 3707 indices, 3708 limit, 3709 zone); 3710 } 3711 } else { 3712 FindStringIndices(isolate, 3713 subject_vector, 3714 pattern_content.ToUC16Vector(), 3715 indices, 3716 limit, 3717 zone); 3718 } 3719 } else { 3720 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); 3721 if (pattern_content.IsAscii()) { 3722 Vector<const uint8_t> pattern_vector = 3723 pattern_content.ToOneByteVector(); 3724 if (pattern_vector.length() == 1) { 3725 FindTwoByteStringIndices(subject_vector, 3726 pattern_vector[0], 3727 indices, 3728 limit, 3729 zone); 3730 } else { 3731 FindStringIndices(isolate, 3732 subject_vector, 3733 pattern_vector, 3734 indices, 3735 limit, 3736 zone); 3737 } 3738 } else { 3739 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); 3740 if (pattern_vector.length() == 1) { 3741 FindTwoByteStringIndices(subject_vector, 3742 pattern_vector[0], 3743 indices, 3744 limit, 3745 zone); 3746 } else { 3747 FindStringIndices(isolate, 3748 subject_vector, 3749 pattern_vector, 3750 indices, 3751 limit, 3752 zone); 3753 } 3754 } 3755 } 3756 } 3757 } 3758 3759 3760 template<typename ResultSeqString> 3761 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( 3762 Isolate* isolate, 3763 Handle<String> subject, 3764 Handle<JSRegExp> pattern_regexp, 3765 Handle<String> replacement, 3766 Handle<JSArray> last_match_info) { 3767 ASSERT(subject->IsFlat()); 3768 ASSERT(replacement->IsFlat()); 3769 3770 ZoneScope zone_scope(isolate->runtime_zone()); 3771 ZoneList<int> indices(8, zone_scope.zone()); 3772 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 3773 String* pattern = 3774 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 3775 int subject_len = subject->length(); 3776 int pattern_len = pattern->length(); 3777 int replacement_len = replacement->length(); 3778 3779 FindStringIndicesDispatch( 3780 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone()); 3781 3782 int matches = indices.length(); 3783 if (matches == 0) return *subject; 3784 3785 // Detect integer overflow. 3786 int64_t result_len_64 = 3787 (static_cast<int64_t>(replacement_len) - 3788 static_cast<int64_t>(pattern_len)) * 3789 static_cast<int64_t>(matches) + 3790 static_cast<int64_t>(subject_len); 3791 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11); 3792 int result_len = static_cast<int>(result_len_64); 3793 3794 int subject_pos = 0; 3795 int result_pos = 0; 3796 3797 Handle<ResultSeqString> result; 3798 if (ResultSeqString::kHasAsciiEncoding) { 3799 result = Handle<ResultSeqString>::cast( 3800 isolate->factory()->NewRawOneByteString(result_len)); 3801 } else { 3802 result = Handle<ResultSeqString>::cast( 3803 isolate->factory()->NewRawTwoByteString(result_len)); 3804 } 3805 3806 for (int i = 0; i < matches; i++) { 3807 // Copy non-matched subject content. 3808 if (subject_pos < indices.at(i)) { 3809 String::WriteToFlat(*subject, 3810 result->GetChars() + result_pos, 3811 subject_pos, 3812 indices.at(i)); 3813 result_pos += indices.at(i) - subject_pos; 3814 } 3815 3816 // Replace match. 3817 if (replacement_len > 0) { 3818 String::WriteToFlat(*replacement, 3819 result->GetChars() + result_pos, 3820 0, 3821 replacement_len); 3822 result_pos += replacement_len; 3823 } 3824 3825 subject_pos = indices.at(i) + pattern_len; 3826 } 3827 // Add remaining subject content at the end. 3828 if (subject_pos < subject_len) { 3829 String::WriteToFlat(*subject, 3830 result->GetChars() + result_pos, 3831 subject_pos, 3832 subject_len); 3833 } 3834 3835 int32_t match_indices[] = { indices.at(matches - 1), 3836 indices.at(matches - 1) + pattern_len }; 3837 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); 3838 3839 return *result; 3840 } 3841 3842 3843 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( 3844 Isolate* isolate, 3845 Handle<String> subject, 3846 Handle<JSRegExp> regexp, 3847 Handle<String> replacement, 3848 Handle<JSArray> last_match_info) { 3849 ASSERT(subject->IsFlat()); 3850 ASSERT(replacement->IsFlat()); 3851 3852 int capture_count = regexp->CaptureCount(); 3853 int subject_length = subject->length(); 3854 3855 // CompiledReplacement uses zone allocation. 3856 ZoneScope zone_scope(isolate->runtime_zone()); 3857 CompiledReplacement compiled_replacement(zone_scope.zone()); 3858 bool simple_replace = compiled_replacement.Compile(replacement, 3859 capture_count, 3860 subject_length); 3861 3862 // Shortcut for simple non-regexp global replacements 3863 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { 3864 if (subject->HasOnlyOneByteChars() && 3865 replacement->HasOnlyOneByteChars()) { 3866 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 3867 isolate, subject, regexp, replacement, last_match_info); 3868 } else { 3869 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 3870 isolate, subject, regexp, replacement, last_match_info); 3871 } 3872 } 3873 3874 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 3875 if (global_cache.HasException()) return Failure::Exception(); 3876 3877 int32_t* current_match = global_cache.FetchNext(); 3878 if (current_match == NULL) { 3879 if (global_cache.HasException()) return Failure::Exception(); 3880 return *subject; 3881 } 3882 3883 // Guessing the number of parts that the final result string is built 3884 // from. Global regexps can match any number of times, so we guess 3885 // conservatively. 3886 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1; 3887 ReplacementStringBuilder builder(isolate->heap(), 3888 subject, 3889 expected_parts); 3890 3891 // Number of parts added by compiled replacement plus preceeding 3892 // string and possibly suffix after last match. It is possible for 3893 // all components to use two elements when encoded as two smis. 3894 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 3895 3896 int prev = 0; 3897 3898 do { 3899 builder.EnsureCapacity(parts_added_per_loop); 3900 3901 int start = current_match[0]; 3902 int end = current_match[1]; 3903 3904 if (prev < start) { 3905 builder.AddSubjectSlice(prev, start); 3906 } 3907 3908 if (simple_replace) { 3909 builder.AddString(replacement); 3910 } else { 3911 compiled_replacement.Apply(&builder, 3912 start, 3913 end, 3914 current_match); 3915 } 3916 prev = end; 3917 3918 current_match = global_cache.FetchNext(); 3919 } while (current_match != NULL); 3920 3921 if (global_cache.HasException()) return Failure::Exception(); 3922 3923 if (prev < subject_length) { 3924 builder.EnsureCapacity(2); 3925 builder.AddSubjectSlice(prev, subject_length); 3926 } 3927 3928 RegExpImpl::SetLastMatchInfo(last_match_info, 3929 subject, 3930 capture_count, 3931 global_cache.LastSuccessfulMatch()); 3932 3933 return *(builder.ToString()); 3934 } 3935 3936 3937 template <typename ResultSeqString> 3938 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( 3939 Isolate* isolate, 3940 Handle<String> subject, 3941 Handle<JSRegExp> regexp, 3942 Handle<JSArray> last_match_info) { 3943 ASSERT(subject->IsFlat()); 3944 3945 // Shortcut for simple non-regexp global replacements 3946 if (regexp->TypeTag() == JSRegExp::ATOM) { 3947 Handle<String> empty_string = isolate->factory()->empty_string(); 3948 if (subject->IsOneByteRepresentation()) { 3949 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 3950 isolate, subject, regexp, empty_string, last_match_info); 3951 } else { 3952 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 3953 isolate, subject, regexp, empty_string, last_match_info); 3954 } 3955 } 3956 3957 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 3958 if (global_cache.HasException()) return Failure::Exception(); 3959 3960 int32_t* current_match = global_cache.FetchNext(); 3961 if (current_match == NULL) { 3962 if (global_cache.HasException()) return Failure::Exception(); 3963 return *subject; 3964 } 3965 3966 int start = current_match[0]; 3967 int end = current_match[1]; 3968 int capture_count = regexp->CaptureCount(); 3969 int subject_length = subject->length(); 3970 3971 int new_length = subject_length - (end - start); 3972 if (new_length == 0) return isolate->heap()->empty_string(); 3973 3974 Handle<ResultSeqString> answer; 3975 if (ResultSeqString::kHasAsciiEncoding) { 3976 answer = Handle<ResultSeqString>::cast( 3977 isolate->factory()->NewRawOneByteString(new_length)); 3978 } else { 3979 answer = Handle<ResultSeqString>::cast( 3980 isolate->factory()->NewRawTwoByteString(new_length)); 3981 } 3982 3983 int prev = 0; 3984 int position = 0; 3985 3986 do { 3987 start = current_match[0]; 3988 end = current_match[1]; 3989 if (prev < start) { 3990 // Add substring subject[prev;start] to answer string. 3991 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start); 3992 position += start - prev; 3993 } 3994 prev = end; 3995 3996 current_match = global_cache.FetchNext(); 3997 } while (current_match != NULL); 3998 3999 if (global_cache.HasException()) return Failure::Exception(); 4000 4001 RegExpImpl::SetLastMatchInfo(last_match_info, 4002 subject, 4003 capture_count, 4004 global_cache.LastSuccessfulMatch()); 4005 4006 if (prev < subject_length) { 4007 // Add substring subject[prev;length] to answer string. 4008 String::WriteToFlat( 4009 *subject, answer->GetChars() + position, prev, subject_length); 4010 position += subject_length - prev; 4011 } 4012 4013 if (position == 0) return isolate->heap()->empty_string(); 4014 4015 // Shorten string and fill 4016 int string_size = ResultSeqString::SizeFor(position); 4017 int allocated_string_size = ResultSeqString::SizeFor(new_length); 4018 int delta = allocated_string_size - string_size; 4019 4020 answer->set_length(position); 4021 if (delta == 0) return *answer; 4022 4023 Address end_of_string = answer->address() + string_size; 4024 isolate->heap()->CreateFillerObjectAt(end_of_string, delta); 4025 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { 4026 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); 4027 } 4028 4029 return *answer; 4030 } 4031 4032 4033 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) { 4034 HandleScope scope(isolate); 4035 ASSERT(args.length() == 4); 4036 4037 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4038 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); 4039 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4040 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 4041 4042 ASSERT(regexp->GetFlags().is_global()); 4043 4044 if (!subject->IsFlat()) subject = FlattenGetString(subject); 4045 4046 if (replacement->length() == 0) { 4047 if (subject->HasOnlyOneByteChars()) { 4048 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( 4049 isolate, subject, regexp, last_match_info); 4050 } else { 4051 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( 4052 isolate, subject, regexp, last_match_info); 4053 } 4054 } 4055 4056 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement); 4057 4058 return StringReplaceGlobalRegExpWithString( 4059 isolate, subject, regexp, replacement, last_match_info); 4060 } 4061 4062 4063 Handle<String> StringReplaceOneCharWithString(Isolate* isolate, 4064 Handle<String> subject, 4065 Handle<String> search, 4066 Handle<String> replace, 4067 bool* found, 4068 int recursion_limit) { 4069 if (recursion_limit == 0) return Handle<String>::null(); 4070 if (subject->IsConsString()) { 4071 ConsString* cons = ConsString::cast(*subject); 4072 Handle<String> first = Handle<String>(cons->first()); 4073 Handle<String> second = Handle<String>(cons->second()); 4074 Handle<String> new_first = 4075 StringReplaceOneCharWithString(isolate, 4076 first, 4077 search, 4078 replace, 4079 found, 4080 recursion_limit - 1); 4081 if (*found) return isolate->factory()->NewConsString(new_first, second); 4082 if (new_first.is_null()) return new_first; 4083 4084 Handle<String> new_second = 4085 StringReplaceOneCharWithString(isolate, 4086 second, 4087 search, 4088 replace, 4089 found, 4090 recursion_limit - 1); 4091 if (*found) return isolate->factory()->NewConsString(first, new_second); 4092 if (new_second.is_null()) return new_second; 4093 4094 return subject; 4095 } else { 4096 int index = Runtime::StringMatch(isolate, subject, search, 0); 4097 if (index == -1) return subject; 4098 *found = true; 4099 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); 4100 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); 4101 Handle<String> second = 4102 isolate->factory()->NewSubString(subject, index + 1, subject->length()); 4103 return isolate->factory()->NewConsString(cons1, second); 4104 } 4105 } 4106 4107 4108 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { 4109 HandleScope scope(isolate); 4110 ASSERT(args.length() == 3); 4111 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4112 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); 4113 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); 4114 4115 // If the cons string tree is too deep, we simply abort the recursion and 4116 // retry with a flattened subject string. 4117 const int kRecursionLimit = 0x1000; 4118 bool found = false; 4119 Handle<String> result = StringReplaceOneCharWithString(isolate, 4120 subject, 4121 search, 4122 replace, 4123 &found, 4124 kRecursionLimit); 4125 if (!result.is_null()) return *result; 4126 return *StringReplaceOneCharWithString(isolate, 4127 FlattenGetString(subject), 4128 search, 4129 replace, 4130 &found, 4131 kRecursionLimit); 4132 } 4133 4134 4135 // Perform string match of pattern on subject, starting at start index. 4136 // Caller must ensure that 0 <= start_index <= sub->length(), 4137 // and should check that pat->length() + start_index <= sub->length(). 4138 int Runtime::StringMatch(Isolate* isolate, 4139 Handle<String> sub, 4140 Handle<String> pat, 4141 int start_index) { 4142 ASSERT(0 <= start_index); 4143 ASSERT(start_index <= sub->length()); 4144 4145 int pattern_length = pat->length(); 4146 if (pattern_length == 0) return start_index; 4147 4148 int subject_length = sub->length(); 4149 if (start_index + pattern_length > subject_length) return -1; 4150 4151 if (!sub->IsFlat()) FlattenString(sub); 4152 if (!pat->IsFlat()) FlattenString(pat); 4153 4154 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4155 // Extract flattened substrings of cons strings before determining asciiness. 4156 String::FlatContent seq_sub = sub->GetFlatContent(); 4157 String::FlatContent seq_pat = pat->GetFlatContent(); 4158 4159 // dispatch on type of strings 4160 if (seq_pat.IsAscii()) { 4161 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector(); 4162 if (seq_sub.IsAscii()) { 4163 return SearchString(isolate, 4164 seq_sub.ToOneByteVector(), 4165 pat_vector, 4166 start_index); 4167 } 4168 return SearchString(isolate, 4169 seq_sub.ToUC16Vector(), 4170 pat_vector, 4171 start_index); 4172 } 4173 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); 4174 if (seq_sub.IsAscii()) { 4175 return SearchString(isolate, 4176 seq_sub.ToOneByteVector(), 4177 pat_vector, 4178 start_index); 4179 } 4180 return SearchString(isolate, 4181 seq_sub.ToUC16Vector(), 4182 pat_vector, 4183 start_index); 4184 } 4185 4186 4187 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { 4188 HandleScope scope(isolate); 4189 ASSERT(args.length() == 3); 4190 4191 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4192 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4193 4194 Object* index = args[2]; 4195 uint32_t start_index; 4196 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4197 4198 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 4199 int position = 4200 Runtime::StringMatch(isolate, sub, pat, start_index); 4201 return Smi::FromInt(position); 4202 } 4203 4204 4205 template <typename schar, typename pchar> 4206 static int StringMatchBackwards(Vector<const schar> subject, 4207 Vector<const pchar> pattern, 4208 int idx) { 4209 int pattern_length = pattern.length(); 4210 ASSERT(pattern_length >= 1); 4211 ASSERT(idx + pattern_length <= subject.length()); 4212 4213 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 4214 for (int i = 0; i < pattern_length; i++) { 4215 uc16 c = pattern[i]; 4216 if (c > String::kMaxOneByteCharCode) { 4217 return -1; 4218 } 4219 } 4220 } 4221 4222 pchar pattern_first_char = pattern[0]; 4223 for (int i = idx; i >= 0; i--) { 4224 if (subject[i] != pattern_first_char) continue; 4225 int j = 1; 4226 while (j < pattern_length) { 4227 if (pattern[j] != subject[i+j]) { 4228 break; 4229 } 4230 j++; 4231 } 4232 if (j == pattern_length) { 4233 return i; 4234 } 4235 } 4236 return -1; 4237 } 4238 4239 4240 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { 4241 HandleScope scope(isolate); 4242 ASSERT(args.length() == 3); 4243 4244 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4245 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4246 4247 Object* index = args[2]; 4248 uint32_t start_index; 4249 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4250 4251 uint32_t pat_length = pat->length(); 4252 uint32_t sub_length = sub->length(); 4253 4254 if (start_index + pat_length > sub_length) { 4255 start_index = sub_length - pat_length; 4256 } 4257 4258 if (pat_length == 0) { 4259 return Smi::FromInt(start_index); 4260 } 4261 4262 if (!sub->IsFlat()) FlattenString(sub); 4263 if (!pat->IsFlat()) FlattenString(pat); 4264 4265 int position = -1; 4266 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4267 4268 String::FlatContent sub_content = sub->GetFlatContent(); 4269 String::FlatContent pat_content = pat->GetFlatContent(); 4270 4271 if (pat_content.IsAscii()) { 4272 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector(); 4273 if (sub_content.IsAscii()) { 4274 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4275 pat_vector, 4276 start_index); 4277 } else { 4278 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4279 pat_vector, 4280 start_index); 4281 } 4282 } else { 4283 Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); 4284 if (sub_content.IsAscii()) { 4285 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4286 pat_vector, 4287 start_index); 4288 } else { 4289 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4290 pat_vector, 4291 start_index); 4292 } 4293 } 4294 4295 return Smi::FromInt(position); 4296 } 4297 4298 4299 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { 4300 SealHandleScope shs(isolate); 4301 ASSERT(args.length() == 2); 4302 4303 CONVERT_ARG_CHECKED(String, str1, 0); 4304 CONVERT_ARG_CHECKED(String, str2, 1); 4305 4306 if (str1 == str2) return Smi::FromInt(0); // Equal. 4307 int str1_length = str1->length(); 4308 int str2_length = str2->length(); 4309 4310 // Decide trivial cases without flattening. 4311 if (str1_length == 0) { 4312 if (str2_length == 0) return Smi::FromInt(0); // Equal. 4313 return Smi::FromInt(-str2_length); 4314 } else { 4315 if (str2_length == 0) return Smi::FromInt(str1_length); 4316 } 4317 4318 int end = str1_length < str2_length ? str1_length : str2_length; 4319 4320 // No need to flatten if we are going to find the answer on the first 4321 // character. At this point we know there is at least one character 4322 // in each string, due to the trivial case handling above. 4323 int d = str1->Get(0) - str2->Get(0); 4324 if (d != 0) return Smi::FromInt(d); 4325 4326 str1->TryFlatten(); 4327 str2->TryFlatten(); 4328 4329 ConsStringIteratorOp* op1 = 4330 isolate->runtime_state()->string_locale_compare_it1(); 4331 ConsStringIteratorOp* op2 = 4332 isolate->runtime_state()->string_locale_compare_it2(); 4333 // TODO(dcarney) Can do array compares here more efficiently. 4334 StringCharacterStream stream1(str1, op1); 4335 StringCharacterStream stream2(str2, op2); 4336 4337 for (int i = 0; i < end; i++) { 4338 uint16_t char1 = stream1.GetNext(); 4339 uint16_t char2 = stream2.GetNext(); 4340 if (char1 != char2) return Smi::FromInt(char1 - char2); 4341 } 4342 4343 return Smi::FromInt(str1_length - str2_length); 4344 } 4345 4346 4347 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { 4348 SealHandleScope shs(isolate); 4349 ASSERT(args.length() == 3); 4350 4351 CONVERT_ARG_CHECKED(String, value, 0); 4352 int start, end; 4353 // We have a fast integer-only case here to avoid a conversion to double in 4354 // the common case where from and to are Smis. 4355 if (args[1]->IsSmi() && args[2]->IsSmi()) { 4356 CONVERT_SMI_ARG_CHECKED(from_number, 1); 4357 CONVERT_SMI_ARG_CHECKED(to_number, 2); 4358 start = from_number; 4359 end = to_number; 4360 } else { 4361 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); 4362 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); 4363 start = FastD2IChecked(from_number); 4364 end = FastD2IChecked(to_number); 4365 } 4366 RUNTIME_ASSERT(end >= start); 4367 RUNTIME_ASSERT(start >= 0); 4368 RUNTIME_ASSERT(end <= value->length()); 4369 isolate->counters()->sub_string_runtime()->Increment(); 4370 if (end - start == 1) { 4371 return isolate->heap()->LookupSingleCharacterStringFromCode( 4372 value->Get(start)); 4373 } 4374 return value->SubString(start, end); 4375 } 4376 4377 4378 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { 4379 HandleScope handles(isolate); 4380 ASSERT_EQ(3, args.length()); 4381 4382 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4383 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4384 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); 4385 4386 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4387 if (global_cache.HasException()) return Failure::Exception(); 4388 4389 int capture_count = regexp->CaptureCount(); 4390 4391 ZoneScope zone_scope(isolate->runtime_zone()); 4392 ZoneList<int> offsets(8, zone_scope.zone()); 4393 4394 while (true) { 4395 int32_t* match = global_cache.FetchNext(); 4396 if (match == NULL) break; 4397 offsets.Add(match[0], zone_scope.zone()); // start 4398 offsets.Add(match[1], zone_scope.zone()); // end 4399 } 4400 4401 if (global_cache.HasException()) return Failure::Exception(); 4402 4403 if (offsets.length() == 0) { 4404 // Not a single match. 4405 return isolate->heap()->null_value(); 4406 } 4407 4408 RegExpImpl::SetLastMatchInfo(regexp_info, 4409 subject, 4410 capture_count, 4411 global_cache.LastSuccessfulMatch()); 4412 4413 int matches = offsets.length() / 2; 4414 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); 4415 Handle<String> substring = 4416 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); 4417 elements->set(0, *substring); 4418 for (int i = 1; i < matches; i++) { 4419 HandleScope temp_scope(isolate); 4420 int from = offsets.at(i * 2); 4421 int to = offsets.at(i * 2 + 1); 4422 Handle<String> substring = 4423 isolate->factory()->NewProperSubString(subject, from, to); 4424 elements->set(i, *substring); 4425 } 4426 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); 4427 result->set_length(Smi::FromInt(matches)); 4428 return *result; 4429 } 4430 4431 4432 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain 4433 // separate last match info. See comment on that function. 4434 template<bool has_capture> 4435 static MaybeObject* SearchRegExpMultiple( 4436 Isolate* isolate, 4437 Handle<String> subject, 4438 Handle<JSRegExp> regexp, 4439 Handle<JSArray> last_match_array, 4440 Handle<JSArray> result_array) { 4441 ASSERT(subject->IsFlat()); 4442 ASSERT_NE(has_capture, regexp->CaptureCount() == 0); 4443 4444 int capture_count = regexp->CaptureCount(); 4445 int subject_length = subject->length(); 4446 4447 static const int kMinLengthToCache = 0x1000; 4448 4449 if (subject_length > kMinLengthToCache) { 4450 Handle<Object> cached_answer(RegExpResultsCache::Lookup( 4451 isolate->heap(), 4452 *subject, 4453 regexp->data(), 4454 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate); 4455 if (*cached_answer != Smi::FromInt(0)) { 4456 Handle<FixedArray> cached_fixed_array = 4457 Handle<FixedArray>(FixedArray::cast(*cached_answer)); 4458 // The cache FixedArray is a COW-array and can therefore be reused. 4459 isolate->factory()->SetContent(result_array, cached_fixed_array); 4460 // The actual length of the result array is stored in the last element of 4461 // the backing store (the backing FixedArray may have a larger capacity). 4462 Object* cached_fixed_array_last_element = 4463 cached_fixed_array->get(cached_fixed_array->length() - 1); 4464 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element); 4465 result_array->set_length(js_array_length); 4466 RegExpImpl::SetLastMatchInfo( 4467 last_match_array, subject, capture_count, NULL); 4468 return *result_array; 4469 } 4470 } 4471 4472 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4473 if (global_cache.HasException()) return Failure::Exception(); 4474 4475 Handle<FixedArray> result_elements; 4476 if (result_array->HasFastObjectElements()) { 4477 result_elements = 4478 Handle<FixedArray>(FixedArray::cast(result_array->elements())); 4479 } 4480 if (result_elements.is_null() || result_elements->length() < 16) { 4481 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 4482 } 4483 4484 FixedArrayBuilder builder(result_elements); 4485 4486 // Position to search from. 4487 int match_start = -1; 4488 int match_end = 0; 4489 bool first = true; 4490 4491 // Two smis before and after the match, for very long strings. 4492 static const int kMaxBuilderEntriesPerRegExpMatch = 5; 4493 4494 while (true) { 4495 int32_t* current_match = global_cache.FetchNext(); 4496 if (current_match == NULL) break; 4497 match_start = current_match[0]; 4498 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 4499 if (match_end < match_start) { 4500 ReplacementStringBuilder::AddSubjectSlice(&builder, 4501 match_end, 4502 match_start); 4503 } 4504 match_end = current_match[1]; 4505 { 4506 // Avoid accumulating new handles inside loop. 4507 HandleScope temp_scope(isolate); 4508 Handle<String> match; 4509 if (!first) { 4510 match = isolate->factory()->NewProperSubString(subject, 4511 match_start, 4512 match_end); 4513 } else { 4514 match = isolate->factory()->NewSubString(subject, 4515 match_start, 4516 match_end); 4517 first = false; 4518 } 4519 4520 if (has_capture) { 4521 // Arguments array to replace function is match, captures, index and 4522 // subject, i.e., 3 + capture count in total. 4523 Handle<FixedArray> elements = 4524 isolate->factory()->NewFixedArray(3 + capture_count); 4525 4526 elements->set(0, *match); 4527 for (int i = 1; i <= capture_count; i++) { 4528 int start = current_match[i * 2]; 4529 if (start >= 0) { 4530 int end = current_match[i * 2 + 1]; 4531 ASSERT(start <= end); 4532 Handle<String> substring = 4533 isolate->factory()->NewSubString(subject, start, end); 4534 elements->set(i, *substring); 4535 } else { 4536 ASSERT(current_match[i * 2 + 1] < 0); 4537 elements->set(i, isolate->heap()->undefined_value()); 4538 } 4539 } 4540 elements->set(capture_count + 1, Smi::FromInt(match_start)); 4541 elements->set(capture_count + 2, *subject); 4542 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 4543 } else { 4544 builder.Add(*match); 4545 } 4546 } 4547 } 4548 4549 if (global_cache.HasException()) return Failure::Exception(); 4550 4551 if (match_start >= 0) { 4552 // Finished matching, with at least one match. 4553 if (match_end < subject_length) { 4554 ReplacementStringBuilder::AddSubjectSlice(&builder, 4555 match_end, 4556 subject_length); 4557 } 4558 4559 RegExpImpl::SetLastMatchInfo( 4560 last_match_array, subject, capture_count, NULL); 4561 4562 if (subject_length > kMinLengthToCache) { 4563 // Store the length of the result array into the last element of the 4564 // backing FixedArray. 4565 builder.EnsureCapacity(1); 4566 Handle<FixedArray> fixed_array = builder.array(); 4567 fixed_array->set(fixed_array->length() - 1, 4568 Smi::FromInt(builder.length())); 4569 // Cache the result and turn the FixedArray into a COW array. 4570 RegExpResultsCache::Enter(isolate->heap(), 4571 *subject, 4572 regexp->data(), 4573 *fixed_array, 4574 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 4575 } 4576 return *builder.ToJSArray(result_array); 4577 } else { 4578 return isolate->heap()->null_value(); // No matches at all. 4579 } 4580 } 4581 4582 4583 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets 4584 // lastMatchInfoOverride to maintain the last match info, so we don't need to 4585 // set any other last match array info. 4586 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { 4587 HandleScope handles(isolate); 4588 ASSERT(args.length() == 4); 4589 4590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 4591 if (!subject->IsFlat()) FlattenString(subject); 4592 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 4593 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); 4594 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); 4595 4596 ASSERT(regexp->GetFlags().is_global()); 4597 4598 if (regexp->CaptureCount() == 0) { 4599 return SearchRegExpMultiple<false>( 4600 isolate, subject, regexp, last_match_info, result_array); 4601 } else { 4602 return SearchRegExpMultiple<true>( 4603 isolate, subject, regexp, last_match_info, result_array); 4604 } 4605 } 4606 4607 4608 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { 4609 SealHandleScope shs(isolate); 4610 ASSERT(args.length() == 2); 4611 CONVERT_SMI_ARG_CHECKED(radix, 1); 4612 RUNTIME_ASSERT(2 <= radix && radix <= 36); 4613 4614 // Fast case where the result is a one character string. 4615 if (args[0]->IsSmi()) { 4616 int value = args.smi_at(0); 4617 if (value >= 0 && value < radix) { 4618 // Character array used for conversion. 4619 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 4620 return isolate->heap()-> 4621 LookupSingleCharacterStringFromCode(kCharTable[value]); 4622 } 4623 } 4624 4625 // Slow case. 4626 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4627 if (std::isnan(value)) { 4628 return *isolate->factory()->nan_string(); 4629 } 4630 if (std::isinf(value)) { 4631 if (value < 0) { 4632 return *isolate->factory()->minus_infinity_string(); 4633 } 4634 return *isolate->factory()->infinity_string(); 4635 } 4636 char* str = DoubleToRadixCString(value, radix); 4637 MaybeObject* result = 4638 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4639 DeleteArray(str); 4640 return result; 4641 } 4642 4643 4644 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { 4645 SealHandleScope shs(isolate); 4646 ASSERT(args.length() == 2); 4647 4648 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4649 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4650 int f = FastD2IChecked(f_number); 4651 RUNTIME_ASSERT(f >= 0); 4652 char* str = DoubleToFixedCString(value, f); 4653 MaybeObject* res = 4654 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4655 DeleteArray(str); 4656 return res; 4657 } 4658 4659 4660 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { 4661 SealHandleScope shs(isolate); 4662 ASSERT(args.length() == 2); 4663 4664 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4665 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4666 int f = FastD2IChecked(f_number); 4667 RUNTIME_ASSERT(f >= -1 && f <= 20); 4668 char* str = DoubleToExponentialCString(value, f); 4669 MaybeObject* res = 4670 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4671 DeleteArray(str); 4672 return res; 4673 } 4674 4675 4676 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { 4677 SealHandleScope shs(isolate); 4678 ASSERT(args.length() == 2); 4679 4680 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4681 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4682 int f = FastD2IChecked(f_number); 4683 RUNTIME_ASSERT(f >= 1 && f <= 21); 4684 char* str = DoubleToPrecisionCString(value, f); 4685 MaybeObject* res = 4686 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4687 DeleteArray(str); 4688 return res; 4689 } 4690 4691 4692 // Returns a single character string where first character equals 4693 // string->Get(index). 4694 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 4695 if (index < static_cast<uint32_t>(string->length())) { 4696 string->TryFlatten(); 4697 return LookupSingleCharacterStringFromCode( 4698 string->GetIsolate(), 4699 string->Get(index)); 4700 } 4701 return Execution::CharAt(string, index); 4702 } 4703 4704 4705 MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate, 4706 Handle<Object> object, 4707 uint32_t index) { 4708 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, 4709 GetElementOrCharAt(isolate, object, index)); 4710 } 4711 4712 4713 MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, 4714 Handle<Object> object, 4715 uint32_t index) { 4716 // Handle [] indexing on Strings 4717 if (object->IsString()) { 4718 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 4719 if (!result->IsUndefined()) return *result; 4720 } 4721 4722 // Handle [] indexing on String objects 4723 if (object->IsStringObjectWithCharacterAt(index)) { 4724 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 4725 Handle<Object> result = 4726 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 4727 if (!result->IsUndefined()) return *result; 4728 } 4729 4730 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 4731 return object->GetPrototype(isolate)->GetElement(index); 4732 } 4733 4734 return object->GetElement(index); 4735 } 4736 4737 4738 MaybeObject* Runtime::HasObjectProperty(Isolate* isolate, 4739 Handle<JSReceiver> object, 4740 Handle<Object> key) { 4741 HandleScope scope(isolate); 4742 4743 // Check if the given key is an array index. 4744 uint32_t index; 4745 if (key->ToArrayIndex(&index)) { 4746 return isolate->heap()->ToBoolean(object->HasElement(index)); 4747 } 4748 4749 // Convert the key to a name - possibly by calling back into JavaScript. 4750 Handle<Name> name; 4751 if (key->IsName()) { 4752 name = Handle<Name>::cast(key); 4753 } else { 4754 bool has_pending_exception = false; 4755 Handle<Object> converted = 4756 Execution::ToString(key, &has_pending_exception); 4757 if (has_pending_exception) return Failure::Exception(); 4758 name = Handle<Name>::cast(converted); 4759 } 4760 4761 return isolate->heap()->ToBoolean(object->HasProperty(*name)); 4762 } 4763 4764 MaybeObject* Runtime::GetObjectPropertyOrFail( 4765 Isolate* isolate, 4766 Handle<Object> object, 4767 Handle<Object> key) { 4768 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, 4769 GetObjectProperty(isolate, object, key)); 4770 } 4771 4772 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, 4773 Handle<Object> object, 4774 Handle<Object> key) { 4775 HandleScope scope(isolate); 4776 4777 if (object->IsUndefined() || object->IsNull()) { 4778 Handle<Object> args[2] = { key, object }; 4779 Handle<Object> error = 4780 isolate->factory()->NewTypeError("non_object_property_load", 4781 HandleVector(args, 2)); 4782 return isolate->Throw(*error); 4783 } 4784 4785 // Check if the given key is an array index. 4786 uint32_t index; 4787 if (key->ToArrayIndex(&index)) { 4788 return GetElementOrCharAt(isolate, object, index); 4789 } 4790 4791 // Convert the key to a name - possibly by calling back into JavaScript. 4792 Handle<Name> name; 4793 if (key->IsName()) { 4794 name = Handle<Name>::cast(key); 4795 } else { 4796 bool has_pending_exception = false; 4797 Handle<Object> converted = 4798 Execution::ToString(key, &has_pending_exception); 4799 if (has_pending_exception) return Failure::Exception(); 4800 name = Handle<Name>::cast(converted); 4801 } 4802 4803 // Check if the name is trivially convertible to an index and get 4804 // the element if so. 4805 if (name->AsArrayIndex(&index)) { 4806 return GetElementOrCharAt(isolate, object, index); 4807 } else { 4808 return object->GetProperty(*name); 4809 } 4810 } 4811 4812 4813 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { 4814 SealHandleScope shs(isolate); 4815 ASSERT(args.length() == 2); 4816 4817 Handle<Object> object = args.at<Object>(0); 4818 Handle<Object> key = args.at<Object>(1); 4819 4820 return Runtime::GetObjectProperty(isolate, object, key); 4821 } 4822 4823 4824 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. 4825 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { 4826 SealHandleScope shs(isolate); 4827 ASSERT(args.length() == 2); 4828 4829 // Fast cases for getting named properties of the receiver JSObject 4830 // itself. 4831 // 4832 // The global proxy objects has to be excluded since LocalLookup on 4833 // the global proxy object can return a valid result even though the 4834 // global proxy object never has properties. This is the case 4835 // because the global proxy object forwards everything to its hidden 4836 // prototype including local lookups. 4837 // 4838 // Additionally, we need to make sure that we do not cache results 4839 // for objects that require access checks. 4840 if (args[0]->IsJSObject()) { 4841 if (!args[0]->IsJSGlobalProxy() && 4842 !args[0]->IsAccessCheckNeeded() && 4843 args[1]->IsName()) { 4844 JSObject* receiver = JSObject::cast(args[0]); 4845 Name* key = Name::cast(args[1]); 4846 if (receiver->HasFastProperties()) { 4847 // Attempt to use lookup cache. 4848 Map* receiver_map = receiver->map(); 4849 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); 4850 int offset = keyed_lookup_cache->Lookup(receiver_map, key); 4851 if (offset != -1) { 4852 // Doubles are not cached, so raw read the value. 4853 Object* value = receiver->RawFastPropertyAt(offset); 4854 return value->IsTheHole() 4855 ? isolate->heap()->undefined_value() 4856 : value; 4857 } 4858 // Lookup cache miss. Perform lookup and update the cache if 4859 // appropriate. 4860 LookupResult result(isolate); 4861 receiver->LocalLookup(key, &result); 4862 if (result.IsField()) { 4863 int offset = result.GetFieldIndex().field_index(); 4864 // Do not track double fields in the keyed lookup cache. Reading 4865 // double values requires boxing. 4866 if (!FLAG_track_double_fields || 4867 !result.representation().IsDouble()) { 4868 keyed_lookup_cache->Update(receiver_map, key, offset); 4869 } 4870 return receiver->FastPropertyAt(result.representation(), offset); 4871 } 4872 } else { 4873 // Attempt dictionary lookup. 4874 NameDictionary* dictionary = receiver->property_dictionary(); 4875 int entry = dictionary->FindEntry(key); 4876 if ((entry != NameDictionary::kNotFound) && 4877 (dictionary->DetailsAt(entry).type() == NORMAL)) { 4878 Object* value = dictionary->ValueAt(entry); 4879 if (!receiver->IsGlobalObject()) return value; 4880 value = PropertyCell::cast(value)->value(); 4881 if (!value->IsTheHole()) return value; 4882 // If value is the hole do the general lookup. 4883 } 4884 } 4885 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { 4886 // JSObject without a name key. If the key is a Smi, check for a 4887 // definite out-of-bounds access to elements, which is a strong indicator 4888 // that subsequent accesses will also call the runtime. Proactively 4889 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of 4890 // doubles for those future calls in the case that the elements would 4891 // become FAST_DOUBLE_ELEMENTS. 4892 Handle<JSObject> js_object(args.at<JSObject>(0)); 4893 ElementsKind elements_kind = js_object->GetElementsKind(); 4894 if (IsFastDoubleElementsKind(elements_kind)) { 4895 FixedArrayBase* elements = js_object->elements(); 4896 if (args.at<Smi>(1)->value() >= elements->length()) { 4897 if (IsFastHoleyElementsKind(elements_kind)) { 4898 elements_kind = FAST_HOLEY_ELEMENTS; 4899 } else { 4900 elements_kind = FAST_ELEMENTS; 4901 } 4902 MaybeObject* maybe_object = TransitionElements(js_object, 4903 elements_kind, 4904 isolate); 4905 if (maybe_object->IsFailure()) return maybe_object; 4906 } 4907 } else { 4908 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || 4909 !IsFastElementsKind(elements_kind)); 4910 } 4911 } 4912 } else if (args[0]->IsString() && args[1]->IsSmi()) { 4913 // Fast case for string indexing using [] with a smi index. 4914 HandleScope scope(isolate); 4915 Handle<String> str = args.at<String>(0); 4916 int index = args.smi_at(1); 4917 if (index >= 0 && index < str->length()) { 4918 Handle<Object> result = GetCharAt(str, index); 4919 return *result; 4920 } 4921 } 4922 4923 // Fall back to GetObjectProperty. 4924 return Runtime::GetObjectProperty(isolate, 4925 args.at<Object>(0), 4926 args.at<Object>(1)); 4927 } 4928 4929 4930 static bool IsValidAccessor(Handle<Object> obj) { 4931 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull(); 4932 } 4933 4934 4935 // Implements part of 8.12.9 DefineOwnProperty. 4936 // There are 3 cases that lead here: 4937 // Step 4b - define a new accessor property. 4938 // Steps 9c & 12 - replace an existing data property with an accessor property. 4939 // Step 12 - update an existing accessor property with an accessor or generic 4940 // descriptor. 4941 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { 4942 HandleScope scope(isolate); 4943 ASSERT(args.length() == 5); 4944 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 4945 RUNTIME_ASSERT(!obj->IsNull()); 4946 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 4947 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 4948 RUNTIME_ASSERT(IsValidAccessor(getter)); 4949 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 4950 RUNTIME_ASSERT(IsValidAccessor(setter)); 4951 CONVERT_SMI_ARG_CHECKED(unchecked, 4); 4952 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4953 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 4954 4955 bool fast = obj->HasFastProperties(); 4956 JSObject::DefineAccessor(obj, name, getter, setter, attr); 4957 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 4958 if (fast) JSObject::TransformToFastProperties(obj, 0); 4959 return isolate->heap()->undefined_value(); 4960 } 4961 4962 4963 // Implements part of 8.12.9 DefineOwnProperty. 4964 // There are 3 cases that lead here: 4965 // Step 4a - define a new data property. 4966 // Steps 9b & 12 - replace an existing accessor property with a data property. 4967 // Step 12 - update an existing data property with a data or generic 4968 // descriptor. 4969 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { 4970 HandleScope scope(isolate); 4971 ASSERT(args.length() == 4); 4972 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); 4973 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 4974 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2); 4975 CONVERT_SMI_ARG_CHECKED(unchecked, 3); 4976 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 4977 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 4978 4979 LookupResult result(isolate); 4980 js_object->LocalLookupRealNamedProperty(*name, &result); 4981 4982 // Special case for callback properties. 4983 if (result.IsPropertyCallbacks()) { 4984 Object* callback = result.GetCallbackObject(); 4985 // To be compatible with Safari we do not change the value on API objects 4986 // in Object.defineProperty(). Firefox disagrees here, and actually changes 4987 // the value. 4988 if (callback->IsAccessorInfo()) { 4989 return isolate->heap()->undefined_value(); 4990 } 4991 // Avoid redefining foreign callback as data property, just use the stored 4992 // setter to update the value instead. 4993 // TODO(mstarzinger): So far this only works if property attributes don't 4994 // change, this should be fixed once we cleanup the underlying code. 4995 if (callback->IsForeign() && result.GetAttributes() == attr) { 4996 return js_object->SetPropertyWithCallback(callback, 4997 *name, 4998 *obj_value, 4999 result.holder(), 5000 kStrictMode); 5001 } 5002 } 5003 5004 // Take special care when attributes are different and there is already 5005 // a property. For simplicity we normalize the property which enables us 5006 // to not worry about changing the instance_descriptor and creating a new 5007 // map. The current version of SetObjectProperty does not handle attributes 5008 // correctly in the case where a property is a field and is reset with 5009 // new attributes. 5010 if (result.IsFound() && 5011 (attr != result.GetAttributes() || result.IsPropertyCallbacks())) { 5012 // New attributes - normalize to avoid writing to instance descriptor 5013 if (js_object->IsJSGlobalProxy()) { 5014 // Since the result is a property, the prototype will exist so 5015 // we don't have to check for null. 5016 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); 5017 } 5018 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); 5019 // Use IgnoreAttributes version since a readonly property may be 5020 // overridden and SetProperty does not allow this. 5021 return js_object->SetLocalPropertyIgnoreAttributes(*name, 5022 *obj_value, 5023 attr); 5024 } 5025 5026 return Runtime::ForceSetObjectProperty(isolate, 5027 js_object, 5028 name, 5029 obj_value, 5030 attr); 5031 } 5032 5033 5034 // Return property without being observable by accessors or interceptors. 5035 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) { 5036 SealHandleScope shs(isolate); 5037 ASSERT(args.length() == 2); 5038 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5039 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5040 LookupResult lookup(isolate); 5041 object->LookupRealNamedProperty(*key, &lookup); 5042 if (!lookup.IsFound()) return isolate->heap()->undefined_value(); 5043 switch (lookup.type()) { 5044 case NORMAL: 5045 return lookup.holder()->GetNormalizedProperty(&lookup); 5046 case FIELD: 5047 return lookup.holder()->FastPropertyAt( 5048 lookup.representation(), 5049 lookup.GetFieldIndex().field_index()); 5050 case CONSTANT: 5051 return lookup.GetConstant(); 5052 case CALLBACKS: 5053 case HANDLER: 5054 case INTERCEPTOR: 5055 case TRANSITION: 5056 return isolate->heap()->undefined_value(); 5057 case NONEXISTENT: 5058 UNREACHABLE(); 5059 } 5060 return isolate->heap()->undefined_value(); 5061 } 5062 5063 5064 MaybeObject* Runtime::SetObjectPropertyOrFail( 5065 Isolate* isolate, 5066 Handle<Object> object, 5067 Handle<Object> key, 5068 Handle<Object> value, 5069 PropertyAttributes attr, 5070 StrictModeFlag strict_mode) { 5071 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, 5072 SetObjectProperty(isolate, object, key, value, attr, strict_mode)); 5073 } 5074 5075 5076 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, 5077 Handle<Object> object, 5078 Handle<Object> key, 5079 Handle<Object> value, 5080 PropertyAttributes attr, 5081 StrictModeFlag strict_mode) { 5082 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; 5083 HandleScope scope(isolate); 5084 5085 if (object->IsUndefined() || object->IsNull()) { 5086 Handle<Object> args[2] = { key, object }; 5087 Handle<Object> error = 5088 isolate->factory()->NewTypeError("non_object_property_store", 5089 HandleVector(args, 2)); 5090 return isolate->Throw(*error); 5091 } 5092 5093 if (object->IsJSProxy()) { 5094 bool has_pending_exception = false; 5095 Handle<Object> name = key->IsSymbol() 5096 ? key : Execution::ToString(key, &has_pending_exception); 5097 if (has_pending_exception) return Failure::Exception(); 5098 return JSProxy::cast(*object)->SetProperty( 5099 Name::cast(*name), *value, attr, strict_mode); 5100 } 5101 5102 // If the object isn't a JavaScript object, we ignore the store. 5103 if (!object->IsJSObject()) return *value; 5104 5105 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 5106 5107 // Check if the given key is an array index. 5108 uint32_t index; 5109 if (key->ToArrayIndex(&index)) { 5110 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5111 // of a string using [] notation. We need to support this too in 5112 // JavaScript. 5113 // In the case of a String object we just need to redirect the assignment to 5114 // the underlying string if the index is in range. Since the underlying 5115 // string does nothing with the assignment then we can ignore such 5116 // assignments. 5117 if (js_object->IsStringObjectWithCharacterAt(index)) { 5118 return *value; 5119 } 5120 5121 js_object->ValidateElements(); 5122 if (js_object->HasExternalArrayElements()) { 5123 if (!value->IsNumber() && !value->IsUndefined()) { 5124 bool has_exception; 5125 Handle<Object> number = Execution::ToNumber(value, &has_exception); 5126 if (has_exception) return Failure::Exception(); 5127 value = number; 5128 } 5129 } 5130 MaybeObject* result = js_object->SetElement( 5131 index, *value, attr, strict_mode, true, set_mode); 5132 js_object->ValidateElements(); 5133 if (result->IsFailure()) return result; 5134 return *value; 5135 } 5136 5137 if (key->IsName()) { 5138 MaybeObject* result; 5139 Handle<Name> name = Handle<Name>::cast(key); 5140 if (name->AsArrayIndex(&index)) { 5141 if (js_object->HasExternalArrayElements()) { 5142 if (!value->IsNumber() && !value->IsUndefined()) { 5143 bool has_exception; 5144 Handle<Object> number = Execution::ToNumber(value, &has_exception); 5145 if (has_exception) return Failure::Exception(); 5146 value = number; 5147 } 5148 } 5149 result = js_object->SetElement( 5150 index, *value, attr, strict_mode, true, set_mode); 5151 } else { 5152 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5153 result = js_object->SetProperty(*name, *value, attr, strict_mode); 5154 } 5155 if (result->IsFailure()) return result; 5156 return *value; 5157 } 5158 5159 // Call-back into JavaScript to convert the key to a string. 5160 bool has_pending_exception = false; 5161 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 5162 if (has_pending_exception) return Failure::Exception(); 5163 Handle<String> name = Handle<String>::cast(converted); 5164 5165 if (name->AsArrayIndex(&index)) { 5166 return js_object->SetElement( 5167 index, *value, attr, strict_mode, true, set_mode); 5168 } else { 5169 return js_object->SetProperty(*name, *value, attr, strict_mode); 5170 } 5171 } 5172 5173 5174 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, 5175 Handle<JSObject> js_object, 5176 Handle<Object> key, 5177 Handle<Object> value, 5178 PropertyAttributes attr) { 5179 HandleScope scope(isolate); 5180 5181 // Check if the given key is an array index. 5182 uint32_t index; 5183 if (key->ToArrayIndex(&index)) { 5184 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5185 // of a string using [] notation. We need to support this too in 5186 // JavaScript. 5187 // In the case of a String object we just need to redirect the assignment to 5188 // the underlying string if the index is in range. Since the underlying 5189 // string does nothing with the assignment then we can ignore such 5190 // assignments. 5191 if (js_object->IsStringObjectWithCharacterAt(index)) { 5192 return *value; 5193 } 5194 5195 return js_object->SetElement( 5196 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 5197 } 5198 5199 if (key->IsName()) { 5200 Handle<Name> name = Handle<Name>::cast(key); 5201 if (name->AsArrayIndex(&index)) { 5202 return js_object->SetElement( 5203 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 5204 } else { 5205 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5206 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); 5207 } 5208 } 5209 5210 // Call-back into JavaScript to convert the key to a string. 5211 bool has_pending_exception = false; 5212 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 5213 if (has_pending_exception) return Failure::Exception(); 5214 Handle<String> name = Handle<String>::cast(converted); 5215 5216 if (name->AsArrayIndex(&index)) { 5217 return js_object->SetElement( 5218 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); 5219 } else { 5220 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); 5221 } 5222 } 5223 5224 5225 MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate, 5226 Handle<JSReceiver> receiver, 5227 Handle<Object> key, 5228 JSReceiver::DeleteMode mode) { 5229 HandleScope scope(isolate); 5230 5231 // Check if the given key is an array index. 5232 uint32_t index; 5233 if (key->ToArrayIndex(&index)) { 5234 // In Firefox/SpiderMonkey, Safari and Opera you can access the 5235 // characters of a string using [] notation. In the case of a 5236 // String object we just need to redirect the deletion to the 5237 // underlying string if the index is in range. Since the 5238 // underlying string does nothing with the deletion, we can ignore 5239 // such deletions. 5240 if (receiver->IsStringObjectWithCharacterAt(index)) { 5241 return isolate->heap()->true_value(); 5242 } 5243 5244 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode); 5245 RETURN_IF_EMPTY_HANDLE(isolate, result); 5246 return *result; 5247 } 5248 5249 Handle<Name> name; 5250 if (key->IsName()) { 5251 name = Handle<Name>::cast(key); 5252 } else { 5253 // Call-back into JavaScript to convert the key to a string. 5254 bool has_pending_exception = false; 5255 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 5256 if (has_pending_exception) return Failure::Exception(); 5257 name = Handle<String>::cast(converted); 5258 } 5259 5260 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5261 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode); 5262 RETURN_IF_EMPTY_HANDLE(isolate, result); 5263 return *result; 5264 } 5265 5266 5267 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { 5268 SealHandleScope shs(isolate); 5269 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 5270 5271 Handle<Object> object = args.at<Object>(0); 5272 Handle<Object> key = args.at<Object>(1); 5273 Handle<Object> value = args.at<Object>(2); 5274 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); 5275 RUNTIME_ASSERT( 5276 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5277 // Compute attributes. 5278 PropertyAttributes attributes = 5279 static_cast<PropertyAttributes>(unchecked_attributes); 5280 5281 StrictModeFlag strict_mode = kNonStrictMode; 5282 if (args.length() == 5) { 5283 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4); 5284 strict_mode = strict_mode_flag; 5285 } 5286 5287 return Runtime::SetObjectProperty(isolate, 5288 object, 5289 key, 5290 value, 5291 attributes, 5292 strict_mode); 5293 } 5294 5295 5296 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) { 5297 HandleScope scope(isolate); 5298 RUNTIME_ASSERT(args.length() == 2); 5299 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 5300 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1); 5301 JSObject::TransitionElementsKind(array, map->elements_kind()); 5302 return *array; 5303 } 5304 5305 5306 // Set the native flag on the function. 5307 // This is used to decide if we should transform null and undefined 5308 // into the global object when doing call and apply. 5309 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { 5310 SealHandleScope shs(isolate); 5311 RUNTIME_ASSERT(args.length() == 1); 5312 5313 Handle<Object> object = args.at<Object>(0); 5314 5315 if (object->IsJSFunction()) { 5316 JSFunction* func = JSFunction::cast(*object); 5317 func->shared()->set_native(true); 5318 } 5319 return isolate->heap()->undefined_value(); 5320 } 5321 5322 5323 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { 5324 HandleScope scope(isolate); 5325 RUNTIME_ASSERT(args.length() == 5); 5326 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5327 CONVERT_SMI_ARG_CHECKED(store_index, 1); 5328 Handle<Object> value = args.at<Object>(2); 5329 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); 5330 CONVERT_SMI_ARG_CHECKED(literal_index, 4); 5331 5332 Object* raw_literal_cell = literals->get(literal_index); 5333 JSArray* boilerplate = NULL; 5334 if (raw_literal_cell->IsAllocationSite()) { 5335 AllocationSite* site = AllocationSite::cast(raw_literal_cell); 5336 boilerplate = JSArray::cast(site->transition_info()); 5337 } else { 5338 boilerplate = JSArray::cast(raw_literal_cell); 5339 } 5340 Handle<JSArray> boilerplate_object(boilerplate); 5341 ElementsKind elements_kind = object->GetElementsKind(); 5342 ASSERT(IsFastElementsKind(elements_kind)); 5343 // Smis should never trigger transitions. 5344 ASSERT(!value->IsSmi()); 5345 5346 if (value->IsNumber()) { 5347 ASSERT(IsFastSmiElementsKind(elements_kind)); 5348 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5349 ? FAST_HOLEY_DOUBLE_ELEMENTS 5350 : FAST_DOUBLE_ELEMENTS; 5351 if (IsMoreGeneralElementsKindTransition( 5352 boilerplate_object->GetElementsKind(), 5353 transitioned_kind)) { 5354 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5355 } 5356 JSObject::TransitionElementsKind(object, transitioned_kind); 5357 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind())); 5358 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements()); 5359 HeapNumber* number = HeapNumber::cast(*value); 5360 double_array->set(store_index, number->Number()); 5361 } else { 5362 ASSERT(IsFastSmiElementsKind(elements_kind) || 5363 IsFastDoubleElementsKind(elements_kind)); 5364 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5365 ? FAST_HOLEY_ELEMENTS 5366 : FAST_ELEMENTS; 5367 JSObject::TransitionElementsKind(object, transitioned_kind); 5368 if (IsMoreGeneralElementsKindTransition( 5369 boilerplate_object->GetElementsKind(), 5370 transitioned_kind)) { 5371 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5372 } 5373 FixedArray* object_array = FixedArray::cast(object->elements()); 5374 object_array->set(store_index, *value); 5375 } 5376 return *object; 5377 } 5378 5379 5380 // Check whether debugger and is about to step into the callback that is passed 5381 // to a built-in function such as Array.forEach. 5382 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) { 5383 SealHandleScope shs(isolate); 5384 #ifdef ENABLE_DEBUGGER_SUPPORT 5385 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) { 5386 return isolate->heap()->false_value(); 5387 } 5388 CONVERT_ARG_CHECKED(Object, callback, 0); 5389 // We do not step into the callback if it's a builtin or not even a function. 5390 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) { 5391 return isolate->heap()->false_value(); 5392 } 5393 return isolate->heap()->true_value(); 5394 #else 5395 return isolate->heap()->false_value(); 5396 #endif // ENABLE_DEBUGGER_SUPPORT 5397 } 5398 5399 5400 // Set one shot breakpoints for the callback function that is passed to a 5401 // built-in function such as Array.forEach to enable stepping into the callback. 5402 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) { 5403 SealHandleScope shs(isolate); 5404 #ifdef ENABLE_DEBUGGER_SUPPORT 5405 Debug* debug = isolate->debug(); 5406 if (!debug->IsStepping()) return isolate->heap()->undefined_value(); 5407 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0); 5408 HandleScope scope(isolate); 5409 // When leaving the callback, step out has been activated, but not performed 5410 // if we do not leave the builtin. To be able to step into the callback 5411 // again, we need to clear the step out at this point. 5412 debug->ClearStepOut(); 5413 debug->FloodWithOneShot(callback); 5414 #endif // ENABLE_DEBUGGER_SUPPORT 5415 return isolate->heap()->undefined_value(); 5416 } 5417 5418 5419 // Set a local property, even if it is READ_ONLY. If the property does not 5420 // exist, it will be added with attributes NONE. 5421 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { 5422 SealHandleScope shs(isolate); 5423 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 5424 CONVERT_ARG_CHECKED(JSObject, object, 0); 5425 CONVERT_ARG_CHECKED(Name, name, 1); 5426 // Compute attributes. 5427 PropertyAttributes attributes = NONE; 5428 if (args.length() == 4) { 5429 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3); 5430 // Only attribute bits should be set. 5431 RUNTIME_ASSERT( 5432 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5433 attributes = static_cast<PropertyAttributes>(unchecked_value); 5434 } 5435 5436 return object-> 5437 SetLocalPropertyIgnoreAttributes(name, args[2], attributes); 5438 } 5439 5440 5441 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { 5442 HandleScope scope(isolate); 5443 ASSERT(args.length() == 3); 5444 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5445 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5446 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); 5447 JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode) 5448 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION; 5449 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode); 5450 RETURN_IF_EMPTY_HANDLE(isolate, result); 5451 return *result; 5452 } 5453 5454 5455 static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate, 5456 Handle<JSObject> object, 5457 Handle<Name> key) { 5458 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value(); 5459 // Handle hidden prototypes. If there's a hidden prototype above this thing 5460 // then we have to check it for properties, because they are supposed to 5461 // look like they are on this object. 5462 Handle<Object> proto(object->GetPrototype(), isolate); 5463 if (proto->IsJSObject() && 5464 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 5465 return HasLocalPropertyImplementation(isolate, 5466 Handle<JSObject>::cast(proto), 5467 key); 5468 } 5469 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5470 return isolate->heap()->false_value(); 5471 } 5472 5473 5474 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { 5475 SealHandleScope shs(isolate); 5476 ASSERT(args.length() == 2); 5477 CONVERT_ARG_CHECKED(Name, key, 1); 5478 5479 uint32_t index; 5480 const bool key_is_array_index = key->AsArrayIndex(&index); 5481 5482 Object* obj = args[0]; 5483 // Only JS objects can have properties. 5484 if (obj->IsJSObject()) { 5485 JSObject* object = JSObject::cast(obj); 5486 // Fast case: either the key is a real named property or it is not 5487 // an array index and there are no interceptors or hidden 5488 // prototypes. 5489 if (object->HasRealNamedProperty(isolate, key)) { 5490 ASSERT(!isolate->has_scheduled_exception()); 5491 return isolate->heap()->true_value(); 5492 } else { 5493 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5494 } 5495 Map* map = object->map(); 5496 if (!key_is_array_index && 5497 !map->has_named_interceptor() && 5498 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) { 5499 return isolate->heap()->false_value(); 5500 } 5501 // Slow case. 5502 HandleScope scope(isolate); 5503 return HasLocalPropertyImplementation(isolate, 5504 Handle<JSObject>(object), 5505 Handle<Name>(key)); 5506 } else if (obj->IsString() && key_is_array_index) { 5507 // Well, there is one exception: Handle [] on strings. 5508 String* string = String::cast(obj); 5509 if (index < static_cast<uint32_t>(string->length())) { 5510 return isolate->heap()->true_value(); 5511 } 5512 } 5513 return isolate->heap()->false_value(); 5514 } 5515 5516 5517 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { 5518 SealHandleScope shs(isolate); 5519 ASSERT(args.length() == 2); 5520 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0); 5521 CONVERT_ARG_CHECKED(Name, key, 1); 5522 5523 bool result = receiver->HasProperty(key); 5524 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5525 if (isolate->has_pending_exception()) return Failure::Exception(); 5526 return isolate->heap()->ToBoolean(result); 5527 } 5528 5529 5530 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) { 5531 SealHandleScope shs(isolate); 5532 ASSERT(args.length() == 2); 5533 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0); 5534 CONVERT_SMI_ARG_CHECKED(index, 1); 5535 5536 bool result = receiver->HasElement(index); 5537 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5538 if (isolate->has_pending_exception()) return Failure::Exception(); 5539 return isolate->heap()->ToBoolean(result); 5540 } 5541 5542 5543 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { 5544 SealHandleScope shs(isolate); 5545 ASSERT(args.length() == 2); 5546 5547 CONVERT_ARG_CHECKED(JSObject, object, 0); 5548 CONVERT_ARG_CHECKED(Name, key, 1); 5549 5550 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 5551 if (att == ABSENT || (att & DONT_ENUM) != 0) { 5552 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5553 return isolate->heap()->false_value(); 5554 } 5555 ASSERT(!isolate->has_scheduled_exception()); 5556 return isolate->heap()->true_value(); 5557 } 5558 5559 5560 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { 5561 HandleScope scope(isolate); 5562 ASSERT(args.length() == 1); 5563 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5564 bool threw = false; 5565 Handle<JSArray> result = GetKeysFor(object, &threw); 5566 if (threw) return Failure::Exception(); 5567 return *result; 5568 } 5569 5570 5571 // Returns either a FixedArray as Runtime_GetPropertyNames, 5572 // or, if the given object has an enum cache that contains 5573 // all enumerable properties of the object and its prototypes 5574 // have none, the map of the object. This is used to speed up 5575 // the check for deletions during a for-in. 5576 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { 5577 SealHandleScope shs(isolate); 5578 ASSERT(args.length() == 1); 5579 5580 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0); 5581 5582 if (raw_object->IsSimpleEnum()) return raw_object->map(); 5583 5584 HandleScope scope(isolate); 5585 Handle<JSReceiver> object(raw_object); 5586 bool threw = false; 5587 Handle<FixedArray> content = 5588 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw); 5589 if (threw) return Failure::Exception(); 5590 5591 // Test again, since cache may have been built by preceding call. 5592 if (object->IsSimpleEnum()) return object->map(); 5593 5594 return *content; 5595 } 5596 5597 5598 // Find the length of the prototype chain that is to to handled as one. If a 5599 // prototype object is hidden it is to be viewed as part of the the object it 5600 // is prototype for. 5601 static int LocalPrototypeChainLength(JSObject* obj) { 5602 int count = 1; 5603 Object* proto = obj->GetPrototype(); 5604 while (proto->IsJSObject() && 5605 JSObject::cast(proto)->map()->is_hidden_prototype()) { 5606 count++; 5607 proto = JSObject::cast(proto)->GetPrototype(); 5608 } 5609 return count; 5610 } 5611 5612 5613 // Return the names of the local named properties. 5614 // args[0]: object 5615 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { 5616 HandleScope scope(isolate); 5617 ASSERT(args.length() == 2); 5618 if (!args[0]->IsJSObject()) { 5619 return isolate->heap()->undefined_value(); 5620 } 5621 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5622 CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1); 5623 PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC; 5624 5625 // Skip the global proxy as it has no properties and always delegates to the 5626 // real global object. 5627 if (obj->IsJSGlobalProxy()) { 5628 // Only collect names if access is permitted. 5629 if (obj->IsAccessCheckNeeded() && 5630 !isolate->MayNamedAccess(*obj, 5631 isolate->heap()->undefined_value(), 5632 v8::ACCESS_KEYS)) { 5633 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); 5634 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5635 return *isolate->factory()->NewJSArray(0); 5636 } 5637 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 5638 } 5639 5640 // Find the number of objects making up this. 5641 int length = LocalPrototypeChainLength(*obj); 5642 5643 // Find the number of local properties for each of the objects. 5644 ScopedVector<int> local_property_count(length); 5645 int total_property_count = 0; 5646 Handle<JSObject> jsproto = obj; 5647 for (int i = 0; i < length; i++) { 5648 // Only collect names if access is permitted. 5649 if (jsproto->IsAccessCheckNeeded() && 5650 !isolate->MayNamedAccess(*jsproto, 5651 isolate->heap()->undefined_value(), 5652 v8::ACCESS_KEYS)) { 5653 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); 5654 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5655 return *isolate->factory()->NewJSArray(0); 5656 } 5657 int n; 5658 n = jsproto->NumberOfLocalProperties(filter); 5659 local_property_count[i] = n; 5660 total_property_count += n; 5661 if (i < length - 1) { 5662 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5663 } 5664 } 5665 5666 // Allocate an array with storage for all the property names. 5667 Handle<FixedArray> names = 5668 isolate->factory()->NewFixedArray(total_property_count); 5669 5670 // Get the property names. 5671 jsproto = obj; 5672 int proto_with_hidden_properties = 0; 5673 int next_copy_index = 0; 5674 for (int i = 0; i < length; i++) { 5675 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter); 5676 next_copy_index += local_property_count[i]; 5677 if (jsproto->HasHiddenProperties()) { 5678 proto_with_hidden_properties++; 5679 } 5680 if (i < length - 1) { 5681 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5682 } 5683 } 5684 5685 // Filter out name of hidden properties object. 5686 if (proto_with_hidden_properties > 0) { 5687 Handle<FixedArray> old_names = names; 5688 names = isolate->factory()->NewFixedArray( 5689 names->length() - proto_with_hidden_properties); 5690 int dest_pos = 0; 5691 for (int i = 0; i < total_property_count; i++) { 5692 Object* name = old_names->get(i); 5693 if (name == isolate->heap()->hidden_string()) { 5694 continue; 5695 } 5696 names->set(dest_pos++, name); 5697 } 5698 } 5699 5700 return *isolate->factory()->NewJSArrayWithElements(names); 5701 } 5702 5703 5704 // Return the names of the local indexed properties. 5705 // args[0]: object 5706 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { 5707 HandleScope scope(isolate); 5708 ASSERT(args.length() == 1); 5709 if (!args[0]->IsJSObject()) { 5710 return isolate->heap()->undefined_value(); 5711 } 5712 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5713 5714 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); 5715 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); 5716 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 5717 return *isolate->factory()->NewJSArrayWithElements(names); 5718 } 5719 5720 5721 // Return information on whether an object has a named or indexed interceptor. 5722 // args[0]: object 5723 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { 5724 HandleScope scope(isolate); 5725 ASSERT(args.length() == 1); 5726 if (!args[0]->IsJSObject()) { 5727 return Smi::FromInt(0); 5728 } 5729 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5730 5731 int result = 0; 5732 if (obj->HasNamedInterceptor()) result |= 2; 5733 if (obj->HasIndexedInterceptor()) result |= 1; 5734 5735 return Smi::FromInt(result); 5736 } 5737 5738 5739 // Return property names from named interceptor. 5740 // args[0]: object 5741 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { 5742 HandleScope scope(isolate); 5743 ASSERT(args.length() == 1); 5744 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5745 5746 if (obj->HasNamedInterceptor()) { 5747 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); 5748 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5749 } 5750 return isolate->heap()->undefined_value(); 5751 } 5752 5753 5754 // Return element names from indexed interceptor. 5755 // args[0]: object 5756 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) { 5757 HandleScope scope(isolate); 5758 ASSERT(args.length() == 1); 5759 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5760 5761 if (obj->HasIndexedInterceptor()) { 5762 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); 5763 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5764 } 5765 return isolate->heap()->undefined_value(); 5766 } 5767 5768 5769 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { 5770 HandleScope scope(isolate); 5771 ASSERT_EQ(args.length(), 1); 5772 CONVERT_ARG_CHECKED(JSObject, raw_object, 0); 5773 Handle<JSObject> object(raw_object); 5774 5775 if (object->IsJSGlobalProxy()) { 5776 // Do access checks before going to the global object. 5777 if (object->IsAccessCheckNeeded() && 5778 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), 5779 v8::ACCESS_KEYS)) { 5780 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); 5781 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5782 return *isolate->factory()->NewJSArray(0); 5783 } 5784 5785 Handle<Object> proto(object->GetPrototype(), isolate); 5786 // If proxy is detached we simply return an empty array. 5787 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); 5788 object = Handle<JSObject>::cast(proto); 5789 } 5790 5791 bool threw = false; 5792 Handle<FixedArray> contents = 5793 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); 5794 if (threw) return Failure::Exception(); 5795 5796 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 5797 // property array and since the result is mutable we have to create 5798 // a fresh clone on each invocation. 5799 int length = contents->length(); 5800 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); 5801 for (int i = 0; i < length; i++) { 5802 Object* entry = contents->get(i); 5803 if (entry->IsString()) { 5804 copy->set(i, entry); 5805 } else { 5806 ASSERT(entry->IsNumber()); 5807 HandleScope scope(isolate); 5808 Handle<Object> entry_handle(entry, isolate); 5809 Handle<Object> entry_str = 5810 isolate->factory()->NumberToString(entry_handle); 5811 copy->set(i, *entry_str); 5812 } 5813 } 5814 return *isolate->factory()->NewJSArrayWithElements(copy); 5815 } 5816 5817 5818 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { 5819 SealHandleScope shs(isolate); 5820 ASSERT(args.length() == 1); 5821 5822 // Compute the frame holding the arguments. 5823 JavaScriptFrameIterator it(isolate); 5824 it.AdvanceToArgumentsFrame(); 5825 JavaScriptFrame* frame = it.frame(); 5826 5827 // Get the actual number of provided arguments. 5828 const uint32_t n = frame->ComputeParametersCount(); 5829 5830 // Try to convert the key to an index. If successful and within 5831 // index return the the argument from the frame. 5832 uint32_t index; 5833 if (args[0]->ToArrayIndex(&index) && index < n) { 5834 return frame->GetParameter(index); 5835 } 5836 5837 if (args[0]->IsSymbol()) { 5838 // Lookup in the initial Object.prototype object. 5839 return isolate->initial_object_prototype()->GetProperty( 5840 Symbol::cast(args[0])); 5841 } 5842 5843 // Convert the key to a string. 5844 HandleScope scope(isolate); 5845 bool exception = false; 5846 Handle<Object> converted = 5847 Execution::ToString(args.at<Object>(0), &exception); 5848 if (exception) return Failure::Exception(); 5849 Handle<String> key = Handle<String>::cast(converted); 5850 5851 // Try to convert the string key into an array index. 5852 if (key->AsArrayIndex(&index)) { 5853 if (index < n) { 5854 return frame->GetParameter(index); 5855 } else { 5856 return isolate->initial_object_prototype()->GetElement(index); 5857 } 5858 } 5859 5860 // Handle special arguments properties. 5861 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n); 5862 if (key->Equals(isolate->heap()->callee_string())) { 5863 JSFunction* function = frame->function(); 5864 if (!function->shared()->is_classic_mode()) { 5865 return isolate->Throw(*isolate->factory()->NewTypeError( 5866 "strict_arguments_callee", HandleVector<Object>(NULL, 0))); 5867 } 5868 return function; 5869 } 5870 5871 // Lookup in the initial Object.prototype object. 5872 return isolate->initial_object_prototype()->GetProperty(*key); 5873 } 5874 5875 5876 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { 5877 SealHandleScope shs(isolate); 5878 ASSERT(args.length() == 1); 5879 Object* object = args[0]; 5880 return (object->IsJSObject() && !object->IsGlobalObject()) 5881 ? JSObject::cast(object)->TransformToFastProperties(0) 5882 : object; 5883 } 5884 5885 5886 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { 5887 SealHandleScope shs(isolate); 5888 ASSERT(args.length() == 1); 5889 5890 return isolate->heap()->ToBoolean(args[0]->BooleanValue()); 5891 } 5892 5893 5894 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 5895 // Possible optimizations: put the type string into the oddballs. 5896 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { 5897 SealHandleScope shs(isolate); 5898 5899 Object* obj = args[0]; 5900 if (obj->IsNumber()) return isolate->heap()->number_string(); 5901 HeapObject* heap_obj = HeapObject::cast(obj); 5902 5903 // typeof an undetectable object is 'undefined' 5904 if (heap_obj->map()->is_undetectable()) { 5905 return isolate->heap()->undefined_string(); 5906 } 5907 5908 InstanceType instance_type = heap_obj->map()->instance_type(); 5909 if (instance_type < FIRST_NONSTRING_TYPE) { 5910 return isolate->heap()->string_string(); 5911 } 5912 5913 switch (instance_type) { 5914 case ODDBALL_TYPE: 5915 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 5916 return isolate->heap()->boolean_string(); 5917 } 5918 if (heap_obj->IsNull()) { 5919 return FLAG_harmony_typeof 5920 ? isolate->heap()->null_string() 5921 : isolate->heap()->object_string(); 5922 } 5923 ASSERT(heap_obj->IsUndefined()); 5924 return isolate->heap()->undefined_string(); 5925 case SYMBOL_TYPE: 5926 return isolate->heap()->symbol_string(); 5927 case JS_FUNCTION_TYPE: 5928 case JS_FUNCTION_PROXY_TYPE: 5929 return isolate->heap()->function_string(); 5930 default: 5931 // For any kind of object not handled above, the spec rule for 5932 // host objects gives that it is okay to return "object" 5933 return isolate->heap()->object_string(); 5934 } 5935 } 5936 5937 5938 static bool AreDigits(const uint8_t*s, int from, int to) { 5939 for (int i = from; i < to; i++) { 5940 if (s[i] < '0' || s[i] > '9') return false; 5941 } 5942 5943 return true; 5944 } 5945 5946 5947 static int ParseDecimalInteger(const uint8_t*s, int from, int to) { 5948 ASSERT(to - from < 10); // Overflow is not possible. 5949 ASSERT(from < to); 5950 int d = s[from] - '0'; 5951 5952 for (int i = from + 1; i < to; i++) { 5953 d = 10 * d + (s[i] - '0'); 5954 } 5955 5956 return d; 5957 } 5958 5959 5960 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { 5961 SealHandleScope shs(isolate); 5962 ASSERT(args.length() == 1); 5963 CONVERT_ARG_CHECKED(String, subject, 0); 5964 subject->TryFlatten(); 5965 5966 // Fast case: short integer or some sorts of junk values. 5967 int len = subject->length(); 5968 if (subject->IsSeqOneByteString()) { 5969 if (len == 0) return Smi::FromInt(0); 5970 5971 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars(); 5972 bool minus = (data[0] == '-'); 5973 int start_pos = (minus ? 1 : 0); 5974 5975 if (start_pos == len) { 5976 return isolate->heap()->nan_value(); 5977 } else if (data[start_pos] > '9') { 5978 // Fast check for a junk value. A valid string may start from a 5979 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or 5980 // the 'I' character ('Infinity'). All of that have codes not greater than 5981 // '9' except 'I' and . 5982 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 5983 return isolate->heap()->nan_value(); 5984 } 5985 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 5986 // The maximal/minimal smi has 10 digits. If the string has less digits we 5987 // know it will fit into the smi-data type. 5988 int d = ParseDecimalInteger(data, start_pos, len); 5989 if (minus) { 5990 if (d == 0) return isolate->heap()->minus_zero_value(); 5991 d = -d; 5992 } else if (!subject->HasHashCode() && 5993 len <= String::kMaxArrayIndexSize && 5994 (len == 1 || data[0] != '0')) { 5995 // String hash is not calculated yet but all the data are present. 5996 // Update the hash field to speed up sequential convertions. 5997 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 5998 #ifdef DEBUG 5999 subject->Hash(); // Force hash calculation. 6000 ASSERT_EQ(static_cast<int>(subject->hash_field()), 6001 static_cast<int>(hash)); 6002 #endif 6003 subject->set_hash_field(hash); 6004 } 6005 return Smi::FromInt(d); 6006 } 6007 } 6008 6009 // Slower case. 6010 int flags = ALLOW_HEX; 6011 if (FLAG_harmony_numeric_literals) { 6012 // The current spec draft has not updated "ToNumber Applied to the String 6013 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 6014 flags |= ALLOW_OCTAL | ALLOW_BINARY; 6015 } 6016 return isolate->heap()->NumberFromDouble( 6017 StringToDouble(isolate->unicode_cache(), subject, flags)); 6018 } 6019 6020 6021 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) { 6022 SealHandleScope shs(isolate); 6023 CONVERT_SMI_ARG_CHECKED(length, 0); 6024 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); 6025 if (length == 0) return isolate->heap()->empty_string(); 6026 if (is_one_byte) { 6027 return isolate->heap()->AllocateRawOneByteString(length); 6028 } else { 6029 return isolate->heap()->AllocateRawTwoByteString(length); 6030 } 6031 } 6032 6033 6034 RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) { 6035 HandleScope scope(isolate); 6036 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); 6037 CONVERT_SMI_ARG_CHECKED(new_length, 1); 6038 return *SeqString::Truncate(string, new_length); 6039 } 6040 6041 6042 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { 6043 HandleScope scope(isolate); 6044 ASSERT(args.length() == 1); 6045 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6046 Handle<String> string = FlattenGetString(source); 6047 ASSERT(string->IsFlat()); 6048 Handle<String> result = string->IsOneByteRepresentationUnderneath() 6049 ? URIEscape::Escape<uint8_t>(isolate, source) 6050 : URIEscape::Escape<uc16>(isolate, source); 6051 if (result.is_null()) return Failure::OutOfMemoryException(0x12); 6052 return *result; 6053 } 6054 6055 6056 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { 6057 HandleScope scope(isolate); 6058 ASSERT(args.length() == 1); 6059 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6060 Handle<String> string = FlattenGetString(source); 6061 ASSERT(string->IsFlat()); 6062 return string->IsOneByteRepresentationUnderneath() 6063 ? *URIUnescape::Unescape<uint8_t>(isolate, source) 6064 : *URIUnescape::Unescape<uc16>(isolate, source); 6065 } 6066 6067 6068 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { 6069 HandleScope scope(isolate); 6070 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 6071 ASSERT(args.length() == 1); 6072 return BasicJsonStringifier::StringifyString(isolate, string); 6073 } 6074 6075 6076 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { 6077 HandleScope scope(isolate); 6078 ASSERT(args.length() == 1); 6079 BasicJsonStringifier stringifier(isolate); 6080 return stringifier.Stringify(Handle<Object>(args[0], isolate)); 6081 } 6082 6083 6084 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 6085 SealHandleScope shs(isolate); 6086 6087 CONVERT_ARG_CHECKED(String, s, 0); 6088 CONVERT_SMI_ARG_CHECKED(radix, 1); 6089 6090 s->TryFlatten(); 6091 6092 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 6093 double value = StringToInt(isolate->unicode_cache(), s, radix); 6094 return isolate->heap()->NumberFromDouble(value); 6095 } 6096 6097 6098 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { 6099 SealHandleScope shs(isolate); 6100 CONVERT_ARG_CHECKED(String, str, 0); 6101 6102 // ECMA-262 section 15.1.2.3, empty string is NaN 6103 double value = StringToDouble(isolate->unicode_cache(), 6104 str, ALLOW_TRAILING_JUNK, OS::nan_value()); 6105 6106 // Create a number object from the value. 6107 return isolate->heap()->NumberFromDouble(value); 6108 } 6109 6110 6111 template <class Converter> 6112 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( 6113 Isolate* isolate, 6114 String* s, 6115 int length, 6116 int input_string_length, 6117 unibrow::Mapping<Converter, 128>* mapping) { 6118 // We try this twice, once with the assumption that the result is no longer 6119 // than the input and, if that assumption breaks, again with the exact 6120 // length. This may not be pretty, but it is nicer than what was here before 6121 // and I hereby claim my vaffel-is. 6122 // 6123 // Allocate the resulting string. 6124 // 6125 // NOTE: This assumes that the upper/lower case of an ASCII 6126 // character is also ASCII. This is currently the case, but it 6127 // might break in the future if we implement more context and locale 6128 // dependent upper/lower conversions. 6129 Object* o; 6130 { MaybeObject* maybe_o = s->IsOneByteRepresentation() 6131 ? isolate->heap()->AllocateRawOneByteString(length) 6132 : isolate->heap()->AllocateRawTwoByteString(length); 6133 if (!maybe_o->ToObject(&o)) return maybe_o; 6134 } 6135 String* result = String::cast(o); 6136 bool has_changed_character = false; 6137 6138 // Convert all characters to upper case, assuming that they will fit 6139 // in the buffer 6140 Access<ConsStringIteratorOp> op( 6141 isolate->runtime_state()->string_iterator()); 6142 StringCharacterStream stream(s, op.value()); 6143 unibrow::uchar chars[Converter::kMaxWidth]; 6144 // We can assume that the string is not empty 6145 uc32 current = stream.GetNext(); 6146 for (int i = 0; i < length;) { 6147 bool has_next = stream.HasMore(); 6148 uc32 next = has_next ? stream.GetNext() : 0; 6149 int char_length = mapping->get(current, next, chars); 6150 if (char_length == 0) { 6151 // The case conversion of this character is the character itself. 6152 result->Set(i, current); 6153 i++; 6154 } else if (char_length == 1) { 6155 // Common case: converting the letter resulted in one character. 6156 ASSERT(static_cast<uc32>(chars[0]) != current); 6157 result->Set(i, chars[0]); 6158 has_changed_character = true; 6159 i++; 6160 } else if (length == input_string_length) { 6161 // We've assumed that the result would be as long as the 6162 // input but here is a character that converts to several 6163 // characters. No matter, we calculate the exact length 6164 // of the result and try the whole thing again. 6165 // 6166 // Note that this leaves room for optimization. We could just 6167 // memcpy what we already have to the result string. Also, 6168 // the result string is the last object allocated we could 6169 // "realloc" it and probably, in the vast majority of cases, 6170 // extend the existing string to be able to hold the full 6171 // result. 6172 int next_length = 0; 6173 if (has_next) { 6174 next_length = mapping->get(next, 0, chars); 6175 if (next_length == 0) next_length = 1; 6176 } 6177 int current_length = i + char_length + next_length; 6178 while (stream.HasMore()) { 6179 current = stream.GetNext(); 6180 // NOTE: we use 0 as the next character here because, while 6181 // the next character may affect what a character converts to, 6182 // it does not in any case affect the length of what it convert 6183 // to. 6184 int char_length = mapping->get(current, 0, chars); 6185 if (char_length == 0) char_length = 1; 6186 current_length += char_length; 6187 if (current_length > Smi::kMaxValue) { 6188 isolate->context()->mark_out_of_memory(); 6189 return Failure::OutOfMemoryException(0x13); 6190 } 6191 } 6192 // Try again with the real length. 6193 return Smi::FromInt(current_length); 6194 } else { 6195 for (int j = 0; j < char_length; j++) { 6196 result->Set(i, chars[j]); 6197 i++; 6198 } 6199 has_changed_character = true; 6200 } 6201 current = next; 6202 } 6203 if (has_changed_character) { 6204 return result; 6205 } else { 6206 // If we didn't actually change anything in doing the conversion 6207 // we simple return the result and let the converted string 6208 // become garbage; there is no reason to keep two identical strings 6209 // alive. 6210 return s; 6211 } 6212 } 6213 6214 6215 namespace { 6216 6217 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; 6218 static const uintptr_t kAsciiMask = kOneInEveryByte << 7; 6219 6220 // Given a word and two range boundaries returns a word with high bit 6221 // set in every byte iff the corresponding input byte was strictly in 6222 // the range (m, n). All the other bits in the result are cleared. 6223 // This function is only useful when it can be inlined and the 6224 // boundaries are statically known. 6225 // Requires: all bytes in the input word and the boundaries must be 6226 // ASCII (less than 0x7F). 6227 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { 6228 // Use strict inequalities since in edge cases the function could be 6229 // further simplified. 6230 ASSERT(0 < m && m < n); 6231 // Has high bit set in every w byte less than n. 6232 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; 6233 // Has high bit set in every w byte greater than m. 6234 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); 6235 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); 6236 } 6237 6238 6239 enum AsciiCaseConversion { 6240 ASCII_TO_LOWER, 6241 ASCII_TO_UPPER 6242 }; 6243 6244 6245 template <AsciiCaseConversion dir> 6246 struct FastAsciiConverter { 6247 static bool Convert(char* dst, char* src, int length, bool* changed_out) { 6248 #ifdef DEBUG 6249 char* saved_dst = dst; 6250 char* saved_src = src; 6251 #endif 6252 // We rely on the distance between upper and lower case letters 6253 // being a known power of 2. 6254 ASSERT('a' - 'A' == (1 << 5)); 6255 // Boundaries for the range of input characters than require conversion. 6256 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1; 6257 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1; 6258 bool changed = false; 6259 uintptr_t or_acc = 0; 6260 char* const limit = src + length; 6261 #ifdef V8_HOST_CAN_READ_UNALIGNED 6262 // Process the prefix of the input that requires no conversion one 6263 // (machine) word at a time. 6264 while (src <= limit - sizeof(uintptr_t)) { 6265 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6266 or_acc |= w; 6267 if (AsciiRangeMask(w, lo, hi) != 0) { 6268 changed = true; 6269 break; 6270 } 6271 *reinterpret_cast<uintptr_t*>(dst) = w; 6272 src += sizeof(uintptr_t); 6273 dst += sizeof(uintptr_t); 6274 } 6275 // Process the remainder of the input performing conversion when 6276 // required one word at a time. 6277 while (src <= limit - sizeof(uintptr_t)) { 6278 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6279 or_acc |= w; 6280 uintptr_t m = AsciiRangeMask(w, lo, hi); 6281 // The mask has high (7th) bit set in every byte that needs 6282 // conversion and we know that the distance between cases is 6283 // 1 << 5. 6284 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); 6285 src += sizeof(uintptr_t); 6286 dst += sizeof(uintptr_t); 6287 } 6288 #endif 6289 // Process the last few bytes of the input (or the whole input if 6290 // unaligned access is not supported). 6291 while (src < limit) { 6292 char c = *src; 6293 or_acc |= c; 6294 if (lo < c && c < hi) { 6295 c ^= (1 << 5); 6296 changed = true; 6297 } 6298 *dst = c; 6299 ++src; 6300 ++dst; 6301 } 6302 if ((or_acc & kAsciiMask) != 0) { 6303 return false; 6304 } 6305 #ifdef DEBUG 6306 CheckConvert(saved_dst, saved_src, length, changed); 6307 #endif 6308 *changed_out = changed; 6309 return true; 6310 } 6311 6312 #ifdef DEBUG 6313 static void CheckConvert(char* dst, char* src, int length, bool changed) { 6314 bool expected_changed = false; 6315 for (int i = 0; i < length; i++) { 6316 if (dst[i] == src[i]) continue; 6317 expected_changed = true; 6318 if (dir == ASCII_TO_LOWER) { 6319 ASSERT('A' <= src[i] && src[i] <= 'Z'); 6320 ASSERT(dst[i] == src[i] + ('a' - 'A')); 6321 } else { 6322 ASSERT(dir == ASCII_TO_UPPER); 6323 ASSERT('a' <= src[i] && src[i] <= 'z'); 6324 ASSERT(dst[i] == src[i] - ('a' - 'A')); 6325 } 6326 } 6327 ASSERT(expected_changed == changed); 6328 } 6329 #endif 6330 }; 6331 6332 6333 struct ToLowerTraits { 6334 typedef unibrow::ToLowercase UnibrowConverter; 6335 6336 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter; 6337 }; 6338 6339 6340 struct ToUpperTraits { 6341 typedef unibrow::ToUppercase UnibrowConverter; 6342 6343 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter; 6344 }; 6345 6346 } // namespace 6347 6348 6349 template <typename ConvertTraits> 6350 MUST_USE_RESULT static MaybeObject* ConvertCase( 6351 Arguments args, 6352 Isolate* isolate, 6353 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) { 6354 SealHandleScope shs(isolate); 6355 CONVERT_ARG_CHECKED(String, s, 0); 6356 s = s->TryFlattenGetString(); 6357 6358 const int length = s->length(); 6359 // Assume that the string is not empty; we need this assumption later 6360 if (length == 0) return s; 6361 6362 // Simpler handling of ASCII strings. 6363 // 6364 // NOTE: This assumes that the upper/lower case of an ASCII 6365 // character is also ASCII. This is currently the case, but it 6366 // might break in the future if we implement more context and locale 6367 // dependent upper/lower conversions. 6368 if (s->IsSeqOneByteString()) { 6369 Object* o; 6370 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); 6371 if (!maybe_o->ToObject(&o)) return maybe_o; 6372 } 6373 SeqOneByteString* result = SeqOneByteString::cast(o); 6374 bool has_changed_character; 6375 bool is_ascii = ConvertTraits::AsciiConverter::Convert( 6376 reinterpret_cast<char*>(result->GetChars()), 6377 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()), 6378 length, 6379 &has_changed_character); 6380 // If not ASCII, we discard the result and take the 2 byte path. 6381 if (is_ascii) { 6382 return has_changed_character ? result : s; 6383 } 6384 } 6385 6386 Object* answer; 6387 { MaybeObject* maybe_answer = 6388 ConvertCaseHelper(isolate, s, length, length, mapping); 6389 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6390 } 6391 if (answer->IsSmi()) { 6392 // Retry with correct length. 6393 { MaybeObject* maybe_answer = 6394 ConvertCaseHelper(isolate, 6395 s, Smi::cast(answer)->value(), length, mapping); 6396 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6397 } 6398 } 6399 return answer; 6400 } 6401 6402 6403 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { 6404 return ConvertCase<ToLowerTraits>( 6405 args, isolate, isolate->runtime_state()->to_lower_mapping()); 6406 } 6407 6408 6409 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { 6410 return ConvertCase<ToUpperTraits>( 6411 args, isolate, isolate->runtime_state()->to_upper_mapping()); 6412 } 6413 6414 6415 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { 6416 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; 6417 } 6418 6419 6420 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { 6421 SealHandleScope shs(isolate); 6422 ASSERT(args.length() == 3); 6423 6424 CONVERT_ARG_CHECKED(String, s, 0); 6425 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); 6426 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); 6427 6428 s->TryFlatten(); 6429 int length = s->length(); 6430 6431 int left = 0; 6432 if (trimLeft) { 6433 while (left < length && IsTrimWhiteSpace(s->Get(left))) { 6434 left++; 6435 } 6436 } 6437 6438 int right = length; 6439 if (trimRight) { 6440 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { 6441 right--; 6442 } 6443 } 6444 return s->SubString(left, right); 6445 } 6446 6447 6448 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { 6449 HandleScope handle_scope(isolate); 6450 ASSERT(args.length() == 3); 6451 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6452 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 6453 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); 6454 6455 int subject_length = subject->length(); 6456 int pattern_length = pattern->length(); 6457 RUNTIME_ASSERT(pattern_length > 0); 6458 6459 if (limit == 0xffffffffu) { 6460 Handle<Object> cached_answer( 6461 RegExpResultsCache::Lookup(isolate->heap(), 6462 *subject, 6463 *pattern, 6464 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS), 6465 isolate); 6466 if (*cached_answer != Smi::FromInt(0)) { 6467 // The cache FixedArray is a COW-array and can therefore be reused. 6468 Handle<JSArray> result = 6469 isolate->factory()->NewJSArrayWithElements( 6470 Handle<FixedArray>::cast(cached_answer)); 6471 return *result; 6472 } 6473 } 6474 6475 // The limit can be very large (0xffffffffu), but since the pattern 6476 // isn't empty, we can never create more parts than ~half the length 6477 // of the subject. 6478 6479 if (!subject->IsFlat()) FlattenString(subject); 6480 6481 static const int kMaxInitialListCapacity = 16; 6482 6483 ZoneScope zone_scope(isolate->runtime_zone()); 6484 6485 // Find (up to limit) indices of separator and end-of-string in subject 6486 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); 6487 ZoneList<int> indices(initial_capacity, zone_scope.zone()); 6488 if (!pattern->IsFlat()) FlattenString(pattern); 6489 6490 FindStringIndicesDispatch(isolate, *subject, *pattern, 6491 &indices, limit, zone_scope.zone()); 6492 6493 if (static_cast<uint32_t>(indices.length()) < limit) { 6494 indices.Add(subject_length, zone_scope.zone()); 6495 } 6496 6497 // The list indices now contains the end of each part to create. 6498 6499 // Create JSArray of substrings separated by separator. 6500 int part_count = indices.length(); 6501 6502 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); 6503 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements(); 6504 if (maybe_result->IsFailure()) return maybe_result; 6505 result->set_length(Smi::FromInt(part_count)); 6506 6507 ASSERT(result->HasFastObjectElements()); 6508 6509 if (part_count == 1 && indices.at(0) == subject_length) { 6510 FixedArray::cast(result->elements())->set(0, *subject); 6511 return *result; 6512 } 6513 6514 Handle<FixedArray> elements(FixedArray::cast(result->elements())); 6515 int part_start = 0; 6516 for (int i = 0; i < part_count; i++) { 6517 HandleScope local_loop_handle(isolate); 6518 int part_end = indices.at(i); 6519 Handle<String> substring = 6520 isolate->factory()->NewProperSubString(subject, part_start, part_end); 6521 elements->set(i, *substring); 6522 part_start = part_end + pattern_length; 6523 } 6524 6525 if (limit == 0xffffffffu) { 6526 if (result->HasFastObjectElements()) { 6527 RegExpResultsCache::Enter(isolate->heap(), 6528 *subject, 6529 *pattern, 6530 *elements, 6531 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); 6532 } 6533 } 6534 6535 return *result; 6536 } 6537 6538 6539 // Copies ASCII characters to the given fixed array looking up 6540 // one-char strings in the cache. Gives up on the first char that is 6541 // not in the cache and fills the remainder with smi zeros. Returns 6542 // the length of the successfully copied prefix. 6543 static int CopyCachedAsciiCharsToArray(Heap* heap, 6544 const uint8_t* chars, 6545 FixedArray* elements, 6546 int length) { 6547 DisallowHeapAllocation no_gc; 6548 FixedArray* ascii_cache = heap->single_character_string_cache(); 6549 Object* undefined = heap->undefined_value(); 6550 int i; 6551 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 6552 for (i = 0; i < length; ++i) { 6553 Object* value = ascii_cache->get(chars[i]); 6554 if (value == undefined) break; 6555 elements->set(i, value, mode); 6556 } 6557 if (i < length) { 6558 ASSERT(Smi::FromInt(0) == 0); 6559 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 6560 } 6561 #ifdef DEBUG 6562 for (int j = 0; j < length; ++j) { 6563 Object* element = elements->get(j); 6564 ASSERT(element == Smi::FromInt(0) || 6565 (element->IsString() && String::cast(element)->LooksValid())); 6566 } 6567 #endif 6568 return i; 6569 } 6570 6571 6572 // Converts a String to JSArray. 6573 // For example, "foo" => ["f", "o", "o"]. 6574 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { 6575 HandleScope scope(isolate); 6576 ASSERT(args.length() == 2); 6577 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6578 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 6579 6580 s = FlattenGetString(s); 6581 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); 6582 6583 Handle<FixedArray> elements; 6584 int position = 0; 6585 if (s->IsFlat() && s->IsOneByteRepresentation()) { 6586 // Try using cached chars where possible. 6587 Object* obj; 6588 { MaybeObject* maybe_obj = 6589 isolate->heap()->AllocateUninitializedFixedArray(length); 6590 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6591 } 6592 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate); 6593 DisallowHeapAllocation no_gc; 6594 String::FlatContent content = s->GetFlatContent(); 6595 if (content.IsAscii()) { 6596 Vector<const uint8_t> chars = content.ToOneByteVector(); 6597 // Note, this will initialize all elements (not only the prefix) 6598 // to prevent GC from seeing partially initialized array. 6599 position = CopyCachedAsciiCharsToArray(isolate->heap(), 6600 chars.start(), 6601 *elements, 6602 length); 6603 } else { 6604 MemsetPointer(elements->data_start(), 6605 isolate->heap()->undefined_value(), 6606 length); 6607 } 6608 } else { 6609 elements = isolate->factory()->NewFixedArray(length); 6610 } 6611 for (int i = position; i < length; ++i) { 6612 Handle<Object> str = 6613 LookupSingleCharacterStringFromCode(isolate, s->Get(i)); 6614 elements->set(i, *str); 6615 } 6616 6617 #ifdef DEBUG 6618 for (int i = 0; i < length; ++i) { 6619 ASSERT(String::cast(elements->get(i))->length() == 1); 6620 } 6621 #endif 6622 6623 return *isolate->factory()->NewJSArrayWithElements(elements); 6624 } 6625 6626 6627 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) { 6628 SealHandleScope shs(isolate); 6629 ASSERT(args.length() == 1); 6630 CONVERT_ARG_CHECKED(String, value, 0); 6631 return value->ToObject(); 6632 } 6633 6634 6635 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { 6636 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 6637 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); 6638 return char_length == 0; 6639 } 6640 6641 6642 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) { 6643 SealHandleScope shs(isolate); 6644 ASSERT(args.length() == 1); 6645 6646 Object* number = args[0]; 6647 RUNTIME_ASSERT(number->IsNumber()); 6648 6649 return isolate->heap()->NumberToString(number); 6650 } 6651 6652 6653 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) { 6654 SealHandleScope shs(isolate); 6655 ASSERT(args.length() == 1); 6656 6657 Object* number = args[0]; 6658 RUNTIME_ASSERT(number->IsNumber()); 6659 6660 return isolate->heap()->NumberToString( 6661 number, false, isolate->heap()->GetPretenureMode()); 6662 } 6663 6664 6665 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { 6666 SealHandleScope shs(isolate); 6667 ASSERT(args.length() == 1); 6668 6669 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6670 6671 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6672 if (number > 0 && number <= Smi::kMaxValue) { 6673 return Smi::FromInt(static_cast<int>(number)); 6674 } 6675 return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); 6676 } 6677 6678 6679 // ES6 draft 9.1.11 6680 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) { 6681 SealHandleScope shs(isolate); 6682 ASSERT(args.length() == 1); 6683 6684 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6685 6686 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6687 if (number > 0 && number <= Smi::kMaxValue) { 6688 return Smi::FromInt(static_cast<int>(number)); 6689 } 6690 if (number <= 0) { 6691 return Smi::FromInt(0); 6692 } 6693 return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); 6694 } 6695 6696 6697 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { 6698 SealHandleScope shs(isolate); 6699 ASSERT(args.length() == 1); 6700 6701 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6702 6703 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6704 if (number > 0 && number <= Smi::kMaxValue) { 6705 return Smi::FromInt(static_cast<int>(number)); 6706 } 6707 6708 double double_value = DoubleToInteger(number); 6709 // Map both -0 and +0 to +0. 6710 if (double_value == 0) double_value = 0; 6711 6712 return isolate->heap()->NumberFromDouble(double_value); 6713 } 6714 6715 6716 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) { 6717 SealHandleScope shs(isolate); 6718 ASSERT(args.length() == 1); 6719 6720 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); 6721 return isolate->heap()->NumberFromUint32(number); 6722 } 6723 6724 6725 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) { 6726 SealHandleScope shs(isolate); 6727 ASSERT(args.length() == 1); 6728 6729 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6730 6731 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6732 if (number > 0 && number <= Smi::kMaxValue) { 6733 return Smi::FromInt(static_cast<int>(number)); 6734 } 6735 return isolate->heap()->NumberFromInt32(DoubleToInt32(number)); 6736 } 6737 6738 6739 // Converts a Number to a Smi, if possible. Returns NaN if the number is not 6740 // a small integer. 6741 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { 6742 SealHandleScope shs(isolate); 6743 ASSERT(args.length() == 1); 6744 6745 Object* obj = args[0]; 6746 if (obj->IsSmi()) { 6747 return obj; 6748 } 6749 if (obj->IsHeapNumber()) { 6750 double value = HeapNumber::cast(obj)->value(); 6751 int int_value = FastD2I(value); 6752 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 6753 return Smi::FromInt(int_value); 6754 } 6755 } 6756 return isolate->heap()->nan_value(); 6757 } 6758 6759 6760 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { 6761 SealHandleScope shs(isolate); 6762 ASSERT(args.length() == 0); 6763 return isolate->heap()->AllocateHeapNumber(0); 6764 } 6765 6766 6767 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { 6768 SealHandleScope shs(isolate); 6769 ASSERT(args.length() == 2); 6770 6771 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6772 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6773 return isolate->heap()->NumberFromDouble(x + y); 6774 } 6775 6776 6777 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) { 6778 SealHandleScope shs(isolate); 6779 ASSERT(args.length() == 2); 6780 6781 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6782 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6783 return isolate->heap()->NumberFromDouble(x - y); 6784 } 6785 6786 6787 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) { 6788 SealHandleScope shs(isolate); 6789 ASSERT(args.length() == 2); 6790 6791 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6792 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6793 return isolate->heap()->NumberFromDouble(x * y); 6794 } 6795 6796 6797 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) { 6798 SealHandleScope shs(isolate); 6799 ASSERT(args.length() == 1); 6800 6801 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6802 return isolate->heap()->NumberFromDouble(-x); 6803 } 6804 6805 6806 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) { 6807 SealHandleScope shs(isolate); 6808 ASSERT(args.length() == 0); 6809 6810 return isolate->heap()->NumberFromDouble(9876543210.0); 6811 } 6812 6813 6814 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) { 6815 SealHandleScope shs(isolate); 6816 ASSERT(args.length() == 2); 6817 6818 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6819 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6820 return isolate->heap()->NumberFromDouble(x / y); 6821 } 6822 6823 6824 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) { 6825 SealHandleScope shs(isolate); 6826 ASSERT(args.length() == 2); 6827 6828 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6829 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6830 6831 x = modulo(x, y); 6832 // NumberFromDouble may return a Smi instead of a Number object 6833 return isolate->heap()->NumberFromDouble(x); 6834 } 6835 6836 6837 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) { 6838 SealHandleScope shs(isolate); 6839 ASSERT(args.length() == 2); 6840 6841 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 6842 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 6843 return isolate->heap()->NumberFromInt32(x * y); 6844 } 6845 6846 6847 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { 6848 SealHandleScope shs(isolate); 6849 ASSERT(args.length() == 2); 6850 CONVERT_ARG_CHECKED(String, str1, 0); 6851 CONVERT_ARG_CHECKED(String, str2, 1); 6852 isolate->counters()->string_add_runtime()->Increment(); 6853 return isolate->heap()->AllocateConsString(str1, str2); 6854 } 6855 6856 6857 template <typename sinkchar> 6858 static inline void StringBuilderConcatHelper(String* special, 6859 sinkchar* sink, 6860 FixedArray* fixed_array, 6861 int array_length) { 6862 int position = 0; 6863 for (int i = 0; i < array_length; i++) { 6864 Object* element = fixed_array->get(i); 6865 if (element->IsSmi()) { 6866 // Smi encoding of position and length. 6867 int encoded_slice = Smi::cast(element)->value(); 6868 int pos; 6869 int len; 6870 if (encoded_slice > 0) { 6871 // Position and length encoded in one smi. 6872 pos = StringBuilderSubstringPosition::decode(encoded_slice); 6873 len = StringBuilderSubstringLength::decode(encoded_slice); 6874 } else { 6875 // Position and length encoded in two smis. 6876 Object* obj = fixed_array->get(++i); 6877 ASSERT(obj->IsSmi()); 6878 pos = Smi::cast(obj)->value(); 6879 len = -encoded_slice; 6880 } 6881 String::WriteToFlat(special, 6882 sink + position, 6883 pos, 6884 pos + len); 6885 position += len; 6886 } else { 6887 String* string = String::cast(element); 6888 int element_length = string->length(); 6889 String::WriteToFlat(string, sink + position, 0, element_length); 6890 position += element_length; 6891 } 6892 } 6893 } 6894 6895 6896 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { 6897 SealHandleScope shs(isolate); 6898 ASSERT(args.length() == 3); 6899 CONVERT_ARG_CHECKED(JSArray, array, 0); 6900 if (!args[1]->IsSmi()) { 6901 isolate->context()->mark_out_of_memory(); 6902 return Failure::OutOfMemoryException(0x14); 6903 } 6904 int array_length = args.smi_at(1); 6905 CONVERT_ARG_CHECKED(String, special, 2); 6906 6907 // This assumption is used by the slice encoding in one or two smis. 6908 ASSERT(Smi::kMaxValue >= String::kMaxLength); 6909 6910 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements(); 6911 if (maybe_result->IsFailure()) return maybe_result; 6912 6913 int special_length = special->length(); 6914 if (!array->HasFastObjectElements()) { 6915 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6916 } 6917 FixedArray* fixed_array = FixedArray::cast(array->elements()); 6918 if (fixed_array->length() < array_length) { 6919 array_length = fixed_array->length(); 6920 } 6921 6922 if (array_length == 0) { 6923 return isolate->heap()->empty_string(); 6924 } else if (array_length == 1) { 6925 Object* first = fixed_array->get(0); 6926 if (first->IsString()) return first; 6927 } 6928 6929 bool one_byte = special->HasOnlyOneByteChars(); 6930 int position = 0; 6931 for (int i = 0; i < array_length; i++) { 6932 int increment = 0; 6933 Object* elt = fixed_array->get(i); 6934 if (elt->IsSmi()) { 6935 // Smi encoding of position and length. 6936 int smi_value = Smi::cast(elt)->value(); 6937 int pos; 6938 int len; 6939 if (smi_value > 0) { 6940 // Position and length encoded in one smi. 6941 pos = StringBuilderSubstringPosition::decode(smi_value); 6942 len = StringBuilderSubstringLength::decode(smi_value); 6943 } else { 6944 // Position and length encoded in two smis. 6945 len = -smi_value; 6946 // Get the position and check that it is a positive smi. 6947 i++; 6948 if (i >= array_length) { 6949 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6950 } 6951 Object* next_smi = fixed_array->get(i); 6952 if (!next_smi->IsSmi()) { 6953 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6954 } 6955 pos = Smi::cast(next_smi)->value(); 6956 if (pos < 0) { 6957 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6958 } 6959 } 6960 ASSERT(pos >= 0); 6961 ASSERT(len >= 0); 6962 if (pos > special_length || len > special_length - pos) { 6963 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6964 } 6965 increment = len; 6966 } else if (elt->IsString()) { 6967 String* element = String::cast(elt); 6968 int element_length = element->length(); 6969 increment = element_length; 6970 if (one_byte && !element->HasOnlyOneByteChars()) { 6971 one_byte = false; 6972 } 6973 } else { 6974 ASSERT(!elt->IsTheHole()); 6975 return isolate->Throw(isolate->heap()->illegal_argument_string()); 6976 } 6977 if (increment > String::kMaxLength - position) { 6978 isolate->context()->mark_out_of_memory(); 6979 return Failure::OutOfMemoryException(0x15); 6980 } 6981 position += increment; 6982 } 6983 6984 int length = position; 6985 Object* object; 6986 6987 if (one_byte) { 6988 { MaybeObject* maybe_object = 6989 isolate->heap()->AllocateRawOneByteString(length); 6990 if (!maybe_object->ToObject(&object)) return maybe_object; 6991 } 6992 SeqOneByteString* answer = SeqOneByteString::cast(object); 6993 StringBuilderConcatHelper(special, 6994 answer->GetChars(), 6995 fixed_array, 6996 array_length); 6997 return answer; 6998 } else { 6999 { MaybeObject* maybe_object = 7000 isolate->heap()->AllocateRawTwoByteString(length); 7001 if (!maybe_object->ToObject(&object)) return maybe_object; 7002 } 7003 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 7004 StringBuilderConcatHelper(special, 7005 answer->GetChars(), 7006 fixed_array, 7007 array_length); 7008 return answer; 7009 } 7010 } 7011 7012 7013 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { 7014 SealHandleScope shs(isolate); 7015 ASSERT(args.length() == 3); 7016 CONVERT_ARG_CHECKED(JSArray, array, 0); 7017 if (!args[1]->IsSmi()) { 7018 isolate->context()->mark_out_of_memory(); 7019 return Failure::OutOfMemoryException(0x16); 7020 } 7021 int array_length = args.smi_at(1); 7022 CONVERT_ARG_CHECKED(String, separator, 2); 7023 7024 if (!array->HasFastObjectElements()) { 7025 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7026 } 7027 FixedArray* fixed_array = FixedArray::cast(array->elements()); 7028 if (fixed_array->length() < array_length) { 7029 array_length = fixed_array->length(); 7030 } 7031 7032 if (array_length == 0) { 7033 return isolate->heap()->empty_string(); 7034 } else if (array_length == 1) { 7035 Object* first = fixed_array->get(0); 7036 if (first->IsString()) return first; 7037 } 7038 7039 int separator_length = separator->length(); 7040 int max_nof_separators = 7041 (String::kMaxLength + separator_length - 1) / separator_length; 7042 if (max_nof_separators < (array_length - 1)) { 7043 isolate->context()->mark_out_of_memory(); 7044 return Failure::OutOfMemoryException(0x17); 7045 } 7046 int length = (array_length - 1) * separator_length; 7047 for (int i = 0; i < array_length; i++) { 7048 Object* element_obj = fixed_array->get(i); 7049 if (!element_obj->IsString()) { 7050 // TODO(1161): handle this case. 7051 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7052 } 7053 String* element = String::cast(element_obj); 7054 int increment = element->length(); 7055 if (increment > String::kMaxLength - length) { 7056 isolate->context()->mark_out_of_memory(); 7057 return Failure::OutOfMemoryException(0x18); 7058 } 7059 length += increment; 7060 } 7061 7062 Object* object; 7063 { MaybeObject* maybe_object = 7064 isolate->heap()->AllocateRawTwoByteString(length); 7065 if (!maybe_object->ToObject(&object)) return maybe_object; 7066 } 7067 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 7068 7069 uc16* sink = answer->GetChars(); 7070 #ifdef DEBUG 7071 uc16* end = sink + length; 7072 #endif 7073 7074 String* first = String::cast(fixed_array->get(0)); 7075 int first_length = first->length(); 7076 String::WriteToFlat(first, sink, 0, first_length); 7077 sink += first_length; 7078 7079 for (int i = 1; i < array_length; i++) { 7080 ASSERT(sink + separator_length <= end); 7081 String::WriteToFlat(separator, sink, 0, separator_length); 7082 sink += separator_length; 7083 7084 String* element = String::cast(fixed_array->get(i)); 7085 int element_length = element->length(); 7086 ASSERT(sink + element_length <= end); 7087 String::WriteToFlat(element, sink, 0, element_length); 7088 sink += element_length; 7089 } 7090 ASSERT(sink == end); 7091 7092 // Use %_FastAsciiArrayJoin instead. 7093 ASSERT(!answer->IsOneByteRepresentation()); 7094 return answer; 7095 } 7096 7097 template <typename Char> 7098 static void JoinSparseArrayWithSeparator(FixedArray* elements, 7099 int elements_length, 7100 uint32_t array_length, 7101 String* separator, 7102 Vector<Char> buffer) { 7103 int previous_separator_position = 0; 7104 int separator_length = separator->length(); 7105 int cursor = 0; 7106 for (int i = 0; i < elements_length; i += 2) { 7107 int position = NumberToInt32(elements->get(i)); 7108 String* string = String::cast(elements->get(i + 1)); 7109 int string_length = string->length(); 7110 if (string->length() > 0) { 7111 while (previous_separator_position < position) { 7112 String::WriteToFlat<Char>(separator, &buffer[cursor], 7113 0, separator_length); 7114 cursor += separator_length; 7115 previous_separator_position++; 7116 } 7117 String::WriteToFlat<Char>(string, &buffer[cursor], 7118 0, string_length); 7119 cursor += string->length(); 7120 } 7121 } 7122 if (separator_length > 0) { 7123 // Array length must be representable as a signed 32-bit number, 7124 // otherwise the total string length would have been too large. 7125 ASSERT(array_length <= 0x7fffffff); // Is int32_t. 7126 int last_array_index = static_cast<int>(array_length - 1); 7127 while (previous_separator_position < last_array_index) { 7128 String::WriteToFlat<Char>(separator, &buffer[cursor], 7129 0, separator_length); 7130 cursor += separator_length; 7131 previous_separator_position++; 7132 } 7133 } 7134 ASSERT(cursor <= buffer.length()); 7135 } 7136 7137 7138 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { 7139 SealHandleScope shs(isolate); 7140 ASSERT(args.length() == 3); 7141 CONVERT_ARG_CHECKED(JSArray, elements_array, 0); 7142 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); 7143 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); 7144 CONVERT_ARG_CHECKED(String, separator, 2); 7145 // elements_array is fast-mode JSarray of alternating positions 7146 // (increasing order) and strings. 7147 // array_length is length of original array (used to add separators); 7148 // separator is string to put between elements. Assumed to be non-empty. 7149 7150 // Find total length of join result. 7151 int string_length = 0; 7152 bool is_ascii = separator->IsOneByteRepresentation(); 7153 int max_string_length; 7154 if (is_ascii) { 7155 max_string_length = SeqOneByteString::kMaxLength; 7156 } else { 7157 max_string_length = SeqTwoByteString::kMaxLength; 7158 } 7159 bool overflow = false; 7160 CONVERT_NUMBER_CHECKED(int, elements_length, 7161 Int32, elements_array->length()); 7162 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. 7163 FixedArray* elements = FixedArray::cast(elements_array->elements()); 7164 for (int i = 0; i < elements_length; i += 2) { 7165 RUNTIME_ASSERT(elements->get(i)->IsNumber()); 7166 RUNTIME_ASSERT(elements->get(i + 1)->IsString()); 7167 String* string = String::cast(elements->get(i + 1)); 7168 int length = string->length(); 7169 if (is_ascii && !string->IsOneByteRepresentation()) { 7170 is_ascii = false; 7171 max_string_length = SeqTwoByteString::kMaxLength; 7172 } 7173 if (length > max_string_length || 7174 max_string_length - length < string_length) { 7175 overflow = true; 7176 break; 7177 } 7178 string_length += length; 7179 } 7180 int separator_length = separator->length(); 7181 if (!overflow && separator_length > 0) { 7182 if (array_length <= 0x7fffffffu) { 7183 int separator_count = static_cast<int>(array_length) - 1; 7184 int remaining_length = max_string_length - string_length; 7185 if ((remaining_length / separator_length) >= separator_count) { 7186 string_length += separator_length * (array_length - 1); 7187 } else { 7188 // Not room for the separators within the maximal string length. 7189 overflow = true; 7190 } 7191 } else { 7192 // Nonempty separator and at least 2^31-1 separators necessary 7193 // means that the string is too large to create. 7194 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); 7195 overflow = true; 7196 } 7197 } 7198 if (overflow) { 7199 // Throw OutOfMemory exception for creating too large a string. 7200 V8::FatalProcessOutOfMemory("Array join result too large."); 7201 } 7202 7203 if (is_ascii) { 7204 MaybeObject* result_allocation = 7205 isolate->heap()->AllocateRawOneByteString(string_length); 7206 if (result_allocation->IsFailure()) return result_allocation; 7207 SeqOneByteString* result_string = 7208 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); 7209 JoinSparseArrayWithSeparator<uint8_t>(elements, 7210 elements_length, 7211 array_length, 7212 separator, 7213 Vector<uint8_t>( 7214 result_string->GetChars(), 7215 string_length)); 7216 return result_string; 7217 } else { 7218 MaybeObject* result_allocation = 7219 isolate->heap()->AllocateRawTwoByteString(string_length); 7220 if (result_allocation->IsFailure()) return result_allocation; 7221 SeqTwoByteString* result_string = 7222 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked()); 7223 JoinSparseArrayWithSeparator<uc16>(elements, 7224 elements_length, 7225 array_length, 7226 separator, 7227 Vector<uc16>(result_string->GetChars(), 7228 string_length)); 7229 return result_string; 7230 } 7231 } 7232 7233 7234 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) { 7235 SealHandleScope shs(isolate); 7236 ASSERT(args.length() == 2); 7237 7238 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7239 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7240 return isolate->heap()->NumberFromInt32(x | y); 7241 } 7242 7243 7244 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) { 7245 SealHandleScope shs(isolate); 7246 ASSERT(args.length() == 2); 7247 7248 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7249 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7250 return isolate->heap()->NumberFromInt32(x & y); 7251 } 7252 7253 7254 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { 7255 SealHandleScope shs(isolate); 7256 ASSERT(args.length() == 2); 7257 7258 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7259 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7260 return isolate->heap()->NumberFromInt32(x ^ y); 7261 } 7262 7263 7264 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { 7265 SealHandleScope shs(isolate); 7266 ASSERT(args.length() == 2); 7267 7268 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7269 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7270 return isolate->heap()->NumberFromInt32(x << (y & 0x1f)); 7271 } 7272 7273 7274 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) { 7275 SealHandleScope shs(isolate); 7276 ASSERT(args.length() == 2); 7277 7278 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 7279 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7280 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f)); 7281 } 7282 7283 7284 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) { 7285 SealHandleScope shs(isolate); 7286 ASSERT(args.length() == 2); 7287 7288 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7289 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7290 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); 7291 } 7292 7293 7294 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { 7295 SealHandleScope shs(isolate); 7296 ASSERT(args.length() == 2); 7297 7298 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7299 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7300 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL); 7301 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL); 7302 if (x == y) return Smi::FromInt(EQUAL); 7303 Object* result; 7304 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 7305 result = Smi::FromInt(EQUAL); 7306 } else { 7307 result = Smi::FromInt(NOT_EQUAL); 7308 } 7309 return result; 7310 } 7311 7312 7313 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { 7314 SealHandleScope shs(isolate); 7315 ASSERT(args.length() == 2); 7316 7317 CONVERT_ARG_CHECKED(String, x, 0); 7318 CONVERT_ARG_CHECKED(String, y, 1); 7319 7320 bool not_equal = !x->Equals(y); 7321 // This is slightly convoluted because the value that signifies 7322 // equality is 0 and inequality is 1 so we have to negate the result 7323 // from String::Equals. 7324 ASSERT(not_equal == 0 || not_equal == 1); 7325 STATIC_CHECK(EQUAL == 0); 7326 STATIC_CHECK(NOT_EQUAL == 1); 7327 return Smi::FromInt(not_equal); 7328 } 7329 7330 7331 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { 7332 SealHandleScope shs(isolate); 7333 ASSERT(args.length() == 3); 7334 7335 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7336 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7337 if (std::isnan(x) || std::isnan(y)) return args[2]; 7338 if (x == y) return Smi::FromInt(EQUAL); 7339 if (isless(x, y)) return Smi::FromInt(LESS); 7340 return Smi::FromInt(GREATER); 7341 } 7342 7343 7344 // Compare two Smis as if they were converted to strings and then 7345 // compared lexicographically. 7346 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { 7347 SealHandleScope shs(isolate); 7348 ASSERT(args.length() == 2); 7349 CONVERT_SMI_ARG_CHECKED(x_value, 0); 7350 CONVERT_SMI_ARG_CHECKED(y_value, 1); 7351 7352 // If the integers are equal so are the string representations. 7353 if (x_value == y_value) return Smi::FromInt(EQUAL); 7354 7355 // If one of the integers is zero the normal integer order is the 7356 // same as the lexicographic order of the string representations. 7357 if (x_value == 0 || y_value == 0) 7358 return Smi::FromInt(x_value < y_value ? LESS : GREATER); 7359 7360 // If only one of the integers is negative the negative number is 7361 // smallest because the char code of '-' is less than the char code 7362 // of any digit. Otherwise, we make both values positive. 7363 7364 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on 7365 // architectures using 32-bit Smis. 7366 uint32_t x_scaled = x_value; 7367 uint32_t y_scaled = y_value; 7368 if (x_value < 0 || y_value < 0) { 7369 if (y_value >= 0) return Smi::FromInt(LESS); 7370 if (x_value >= 0) return Smi::FromInt(GREATER); 7371 x_scaled = -x_value; 7372 y_scaled = -y_value; 7373 } 7374 7375 static const uint32_t kPowersOf10[] = { 7376 1, 10, 100, 1000, 10*1000, 100*1000, 7377 1000*1000, 10*1000*1000, 100*1000*1000, 7378 1000*1000*1000 7379 }; 7380 7381 // If the integers have the same number of decimal digits they can be 7382 // compared directly as the numeric order is the same as the 7383 // lexicographic order. If one integer has fewer digits, it is scaled 7384 // by some power of 10 to have the same number of digits as the longer 7385 // integer. If the scaled integers are equal it means the shorter 7386 // integer comes first in the lexicographic order. 7387 7388 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 7389 int x_log2 = IntegerLog2(x_scaled); 7390 int x_log10 = ((x_log2 + 1) * 1233) >> 12; 7391 x_log10 -= x_scaled < kPowersOf10[x_log10]; 7392 7393 int y_log2 = IntegerLog2(y_scaled); 7394 int y_log10 = ((y_log2 + 1) * 1233) >> 12; 7395 y_log10 -= y_scaled < kPowersOf10[y_log10]; 7396 7397 int tie = EQUAL; 7398 7399 if (x_log10 < y_log10) { 7400 // X has fewer digits. We would like to simply scale up X but that 7401 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would 7402 // be scaled up to 9_000_000_000. So we scale up by the next 7403 // smallest power and scale down Y to drop one digit. It is OK to 7404 // drop one digit from the longer integer since the final digit is 7405 // past the length of the shorter integer. 7406 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; 7407 y_scaled /= 10; 7408 tie = LESS; 7409 } else if (y_log10 < x_log10) { 7410 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; 7411 x_scaled /= 10; 7412 tie = GREATER; 7413 } 7414 7415 if (x_scaled < y_scaled) return Smi::FromInt(LESS); 7416 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); 7417 return Smi::FromInt(tie); 7418 } 7419 7420 7421 static Object* StringCharacterStreamCompare(RuntimeState* state, 7422 String* x, 7423 String* y) { 7424 StringCharacterStream stream_x(x, state->string_iterator_compare_x()); 7425 StringCharacterStream stream_y(y, state->string_iterator_compare_y()); 7426 while (stream_x.HasMore() && stream_y.HasMore()) { 7427 int d = stream_x.GetNext() - stream_y.GetNext(); 7428 if (d < 0) return Smi::FromInt(LESS); 7429 else if (d > 0) return Smi::FromInt(GREATER); 7430 } 7431 7432 // x is (non-trivial) prefix of y: 7433 if (stream_y.HasMore()) return Smi::FromInt(LESS); 7434 // y is prefix of x: 7435 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL); 7436 } 7437 7438 7439 static Object* FlatStringCompare(String* x, String* y) { 7440 ASSERT(x->IsFlat()); 7441 ASSERT(y->IsFlat()); 7442 Object* equal_prefix_result = Smi::FromInt(EQUAL); 7443 int prefix_length = x->length(); 7444 if (y->length() < prefix_length) { 7445 prefix_length = y->length(); 7446 equal_prefix_result = Smi::FromInt(GREATER); 7447 } else if (y->length() > prefix_length) { 7448 equal_prefix_result = Smi::FromInt(LESS); 7449 } 7450 int r; 7451 DisallowHeapAllocation no_gc; 7452 String::FlatContent x_content = x->GetFlatContent(); 7453 String::FlatContent y_content = y->GetFlatContent(); 7454 if (x_content.IsAscii()) { 7455 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 7456 if (y_content.IsAscii()) { 7457 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7458 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7459 } else { 7460 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7461 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7462 } 7463 } else { 7464 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 7465 if (y_content.IsAscii()) { 7466 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7467 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7468 } else { 7469 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7470 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7471 } 7472 } 7473 Object* result; 7474 if (r == 0) { 7475 result = equal_prefix_result; 7476 } else { 7477 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); 7478 } 7479 ASSERT(result == 7480 StringCharacterStreamCompare(Isolate::Current()->runtime_state(), x, y)); 7481 return result; 7482 } 7483 7484 7485 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { 7486 SealHandleScope shs(isolate); 7487 ASSERT(args.length() == 2); 7488 7489 CONVERT_ARG_CHECKED(String, x, 0); 7490 CONVERT_ARG_CHECKED(String, y, 1); 7491 7492 isolate->counters()->string_compare_runtime()->Increment(); 7493 7494 // A few fast case tests before we flatten. 7495 if (x == y) return Smi::FromInt(EQUAL); 7496 if (y->length() == 0) { 7497 if (x->length() == 0) return Smi::FromInt(EQUAL); 7498 return Smi::FromInt(GREATER); 7499 } else if (x->length() == 0) { 7500 return Smi::FromInt(LESS); 7501 } 7502 7503 int d = x->Get(0) - y->Get(0); 7504 if (d < 0) return Smi::FromInt(LESS); 7505 else if (d > 0) return Smi::FromInt(GREATER); 7506 7507 Object* obj; 7508 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); 7509 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7510 } 7511 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); 7512 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7513 } 7514 7515 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) 7516 : StringCharacterStreamCompare(isolate->runtime_state(), x, y); 7517 } 7518 7519 7520 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { 7521 SealHandleScope shs(isolate); 7522 ASSERT(args.length() == 1); 7523 isolate->counters()->math_acos()->Increment(); 7524 7525 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7526 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); 7527 } 7528 7529 7530 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) { 7531 SealHandleScope shs(isolate); 7532 ASSERT(args.length() == 1); 7533 isolate->counters()->math_asin()->Increment(); 7534 7535 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7536 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x); 7537 } 7538 7539 7540 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) { 7541 SealHandleScope shs(isolate); 7542 ASSERT(args.length() == 1); 7543 isolate->counters()->math_atan()->Increment(); 7544 7545 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7546 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x); 7547 } 7548 7549 7550 static const double kPiDividedBy4 = 0.78539816339744830962; 7551 7552 7553 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { 7554 SealHandleScope shs(isolate); 7555 ASSERT(args.length() == 2); 7556 isolate->counters()->math_atan2()->Increment(); 7557 7558 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7559 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7560 double result; 7561 if (std::isinf(x) && std::isinf(y)) { 7562 // Make sure that the result in case of two infinite arguments 7563 // is a multiple of Pi / 4. The sign of the result is determined 7564 // by the first argument (x) and the sign of the second argument 7565 // determines the multiplier: one or three. 7566 int multiplier = (x < 0) ? -1 : 1; 7567 if (y < 0) multiplier *= 3; 7568 result = multiplier * kPiDividedBy4; 7569 } else { 7570 result = atan2(x, y); 7571 } 7572 return isolate->heap()->AllocateHeapNumber(result); 7573 } 7574 7575 7576 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) { 7577 SealHandleScope shs(isolate); 7578 ASSERT(args.length() == 1); 7579 isolate->counters()->math_ceil()->Increment(); 7580 7581 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7582 return isolate->heap()->NumberFromDouble(ceiling(x)); 7583 } 7584 7585 7586 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) { 7587 SealHandleScope shs(isolate); 7588 ASSERT(args.length() == 1); 7589 isolate->counters()->math_cos()->Increment(); 7590 7591 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7592 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x); 7593 } 7594 7595 7596 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { 7597 SealHandleScope shs(isolate); 7598 ASSERT(args.length() == 1); 7599 isolate->counters()->math_exp()->Increment(); 7600 7601 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7602 lazily_initialize_fast_exp(); 7603 return isolate->heap()->NumberFromDouble(fast_exp(x)); 7604 } 7605 7606 7607 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) { 7608 SealHandleScope shs(isolate); 7609 ASSERT(args.length() == 1); 7610 isolate->counters()->math_floor()->Increment(); 7611 7612 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7613 return isolate->heap()->NumberFromDouble(floor(x)); 7614 } 7615 7616 7617 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { 7618 SealHandleScope shs(isolate); 7619 ASSERT(args.length() == 1); 7620 isolate->counters()->math_log()->Increment(); 7621 7622 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7623 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); 7624 } 7625 7626 7627 // Slow version of Math.pow. We check for fast paths for special cases. 7628 // Used if SSE2/VFP3 is not available. 7629 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { 7630 SealHandleScope shs(isolate); 7631 ASSERT(args.length() == 2); 7632 isolate->counters()->math_pow()->Increment(); 7633 7634 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7635 7636 // If the second argument is a smi, it is much faster to call the 7637 // custom powi() function than the generic pow(). 7638 if (args[1]->IsSmi()) { 7639 int y = args.smi_at(1); 7640 return isolate->heap()->NumberFromDouble(power_double_int(x, y)); 7641 } 7642 7643 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7644 double result = power_helper(x, y); 7645 if (std::isnan(result)) return isolate->heap()->nan_value(); 7646 return isolate->heap()->AllocateHeapNumber(result); 7647 } 7648 7649 7650 // Fast version of Math.pow if we know that y is not an integer and y is not 7651 // -0.5 or 0.5. Used as slow case from full codegen. 7652 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { 7653 SealHandleScope shs(isolate); 7654 ASSERT(args.length() == 2); 7655 isolate->counters()->math_pow()->Increment(); 7656 7657 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7658 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7659 if (y == 0) { 7660 return Smi::FromInt(1); 7661 } else { 7662 double result = power_double_double(x, y); 7663 if (std::isnan(result)) return isolate->heap()->nan_value(); 7664 return isolate->heap()->AllocateHeapNumber(result); 7665 } 7666 } 7667 7668 7669 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { 7670 SealHandleScope shs(isolate); 7671 ASSERT(args.length() == 1); 7672 isolate->counters()->math_round()->Increment(); 7673 7674 if (!args[0]->IsHeapNumber()) { 7675 // Must be smi. Return the argument unchanged for all the other types 7676 // to make fuzz-natives test happy. 7677 return args[0]; 7678 } 7679 7680 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); 7681 7682 double value = number->value(); 7683 int exponent = number->get_exponent(); 7684 int sign = number->get_sign(); 7685 7686 if (exponent < -1) { 7687 // Number in range ]-0.5..0.5[. These always round to +/-zero. 7688 if (sign) return isolate->heap()->minus_zero_value(); 7689 return Smi::FromInt(0); 7690 } 7691 7692 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and 7693 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar 7694 // argument holds for 32-bit smis). 7695 if (!sign && exponent < kSmiValueSize - 2) { 7696 return Smi::FromInt(static_cast<int>(value + 0.5)); 7697 } 7698 7699 // If the magnitude is big enough, there's no place for fraction part. If we 7700 // try to add 0.5 to this number, 1.0 will be added instead. 7701 if (exponent >= 52) { 7702 return number; 7703 } 7704 7705 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); 7706 7707 // Do not call NumberFromDouble() to avoid extra checks. 7708 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5)); 7709 } 7710 7711 7712 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) { 7713 SealHandleScope shs(isolate); 7714 ASSERT(args.length() == 1); 7715 isolate->counters()->math_sin()->Increment(); 7716 7717 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7718 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x); 7719 } 7720 7721 7722 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { 7723 SealHandleScope shs(isolate); 7724 ASSERT(args.length() == 1); 7725 isolate->counters()->math_sqrt()->Increment(); 7726 7727 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7728 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x)); 7729 } 7730 7731 7732 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { 7733 SealHandleScope shs(isolate); 7734 ASSERT(args.length() == 1); 7735 isolate->counters()->math_tan()->Increment(); 7736 7737 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7738 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x); 7739 } 7740 7741 7742 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { 7743 SealHandleScope shs(isolate); 7744 ASSERT(args.length() == 2); 7745 7746 CONVERT_SMI_ARG_CHECKED(year, 0); 7747 CONVERT_SMI_ARG_CHECKED(month, 1); 7748 7749 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month)); 7750 } 7751 7752 7753 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { 7754 HandleScope scope(isolate); 7755 ASSERT(args.length() == 3); 7756 7757 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); 7758 CONVERT_DOUBLE_ARG_CHECKED(time, 1); 7759 CONVERT_SMI_ARG_CHECKED(is_utc, 2); 7760 7761 DateCache* date_cache = isolate->date_cache(); 7762 7763 Object* value = NULL; 7764 bool is_value_nan = false; 7765 if (std::isnan(time)) { 7766 value = isolate->heap()->nan_value(); 7767 is_value_nan = true; 7768 } else if (!is_utc && 7769 (time < -DateCache::kMaxTimeBeforeUTCInMs || 7770 time > DateCache::kMaxTimeBeforeUTCInMs)) { 7771 value = isolate->heap()->nan_value(); 7772 is_value_nan = true; 7773 } else { 7774 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); 7775 if (time < -DateCache::kMaxTimeInMs || 7776 time > DateCache::kMaxTimeInMs) { 7777 value = isolate->heap()->nan_value(); 7778 is_value_nan = true; 7779 } else { 7780 MaybeObject* maybe_result = 7781 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time)); 7782 if (!maybe_result->ToObject(&value)) return maybe_result; 7783 } 7784 } 7785 date->SetValue(value, is_value_nan); 7786 return value; 7787 } 7788 7789 7790 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { 7791 HandleScope scope(isolate); 7792 ASSERT(args.length() == 3); 7793 7794 Handle<JSFunction> callee = args.at<JSFunction>(0); 7795 Object** parameters = reinterpret_cast<Object**>(args[1]); 7796 const int argument_count = Smi::cast(args[2])->value(); 7797 7798 Handle<JSObject> result = 7799 isolate->factory()->NewArgumentsObject(callee, argument_count); 7800 // Allocate the elements if needed. 7801 int parameter_count = callee->shared()->formal_parameter_count(); 7802 if (argument_count > 0) { 7803 if (parameter_count > 0) { 7804 int mapped_count = Min(argument_count, parameter_count); 7805 Handle<FixedArray> parameter_map = 7806 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); 7807 parameter_map->set_map( 7808 isolate->heap()->non_strict_arguments_elements_map()); 7809 7810 Handle<Map> old_map(result->map()); 7811 Handle<Map> new_map = isolate->factory()->CopyMap(old_map); 7812 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); 7813 7814 result->set_map(*new_map); 7815 result->set_elements(*parameter_map); 7816 7817 // Store the context and the arguments array at the beginning of the 7818 // parameter map. 7819 Handle<Context> context(isolate->context()); 7820 Handle<FixedArray> arguments = 7821 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 7822 parameter_map->set(0, *context); 7823 parameter_map->set(1, *arguments); 7824 7825 // Loop over the actual parameters backwards. 7826 int index = argument_count - 1; 7827 while (index >= mapped_count) { 7828 // These go directly in the arguments array and have no 7829 // corresponding slot in the parameter map. 7830 arguments->set(index, *(parameters - index - 1)); 7831 --index; 7832 } 7833 7834 Handle<ScopeInfo> scope_info(callee->shared()->scope_info()); 7835 while (index >= 0) { 7836 // Detect duplicate names to the right in the parameter list. 7837 Handle<String> name(scope_info->ParameterName(index)); 7838 int context_local_count = scope_info->ContextLocalCount(); 7839 bool duplicate = false; 7840 for (int j = index + 1; j < parameter_count; ++j) { 7841 if (scope_info->ParameterName(j) == *name) { 7842 duplicate = true; 7843 break; 7844 } 7845 } 7846 7847 if (duplicate) { 7848 // This goes directly in the arguments array with a hole in the 7849 // parameter map. 7850 arguments->set(index, *(parameters - index - 1)); 7851 parameter_map->set_the_hole(index + 2); 7852 } else { 7853 // The context index goes in the parameter map with a hole in the 7854 // arguments array. 7855 int context_index = -1; 7856 for (int j = 0; j < context_local_count; ++j) { 7857 if (scope_info->ContextLocalName(j) == *name) { 7858 context_index = j; 7859 break; 7860 } 7861 } 7862 ASSERT(context_index >= 0); 7863 arguments->set_the_hole(index); 7864 parameter_map->set(index + 2, Smi::FromInt( 7865 Context::MIN_CONTEXT_SLOTS + context_index)); 7866 } 7867 7868 --index; 7869 } 7870 } else { 7871 // If there is no aliasing, the arguments object elements are not 7872 // special in any way. 7873 Handle<FixedArray> elements = 7874 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 7875 result->set_elements(*elements); 7876 for (int i = 0; i < argument_count; ++i) { 7877 elements->set(i, *(parameters - i - 1)); 7878 } 7879 } 7880 } 7881 return *result; 7882 } 7883 7884 7885 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) { 7886 SealHandleScope shs(isolate); 7887 ASSERT(args.length() == 3); 7888 7889 JSFunction* callee = JSFunction::cast(args[0]); 7890 Object** parameters = reinterpret_cast<Object**>(args[1]); 7891 const int length = args.smi_at(2); 7892 7893 Object* result; 7894 { MaybeObject* maybe_result = 7895 isolate->heap()->AllocateArgumentsObject(callee, length); 7896 if (!maybe_result->ToObject(&result)) return maybe_result; 7897 } 7898 // Allocate the elements if needed. 7899 if (length > 0) { 7900 // Allocate the fixed array. 7901 Object* obj; 7902 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length); 7903 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7904 } 7905 7906 DisallowHeapAllocation no_gc; 7907 FixedArray* array = reinterpret_cast<FixedArray*>(obj); 7908 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map()); 7909 array->set_length(length); 7910 7911 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 7912 for (int i = 0; i < length; i++) { 7913 array->set(i, *--parameters, mode); 7914 } 7915 JSObject::cast(result)->set_elements(FixedArray::cast(obj)); 7916 } 7917 return result; 7918 } 7919 7920 7921 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { 7922 HandleScope scope(isolate); 7923 ASSERT(args.length() == 3); 7924 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 7925 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1); 7926 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2); 7927 7928 // The caller ensures that we pretenure closures that are assigned 7929 // directly to properties. 7930 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 7931 Handle<JSFunction> result = 7932 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 7933 context, 7934 pretenure_flag); 7935 return *result; 7936 } 7937 7938 7939 // Find the arguments of the JavaScript function invocation that called 7940 // into C++ code. Collect these in a newly allocated array of handles (possibly 7941 // prefixed by a number of empty handles). 7942 static SmartArrayPointer<Handle<Object> > GetCallerArguments( 7943 Isolate* isolate, 7944 int prefix_argc, 7945 int* total_argc) { 7946 // Find frame containing arguments passed to the caller. 7947 JavaScriptFrameIterator it(isolate); 7948 JavaScriptFrame* frame = it.frame(); 7949 List<JSFunction*> functions(2); 7950 frame->GetFunctions(&functions); 7951 if (functions.length() > 1) { 7952 int inlined_jsframe_index = functions.length() - 1; 7953 JSFunction* inlined_function = functions[inlined_jsframe_index]; 7954 Vector<SlotRef> args_slots = 7955 SlotRef::ComputeSlotMappingForArguments( 7956 frame, 7957 inlined_jsframe_index, 7958 inlined_function->shared()->formal_parameter_count()); 7959 7960 int args_count = args_slots.length(); 7961 7962 *total_argc = prefix_argc + args_count; 7963 SmartArrayPointer<Handle<Object> > param_data( 7964 NewArray<Handle<Object> >(*total_argc)); 7965 for (int i = 0; i < args_count; i++) { 7966 Handle<Object> val = args_slots[i].GetValue(isolate); 7967 param_data[prefix_argc + i] = val; 7968 } 7969 7970 args_slots.Dispose(); 7971 7972 return param_data; 7973 } else { 7974 it.AdvanceToArgumentsFrame(); 7975 frame = it.frame(); 7976 int args_count = frame->ComputeParametersCount(); 7977 7978 *total_argc = prefix_argc + args_count; 7979 SmartArrayPointer<Handle<Object> > param_data( 7980 NewArray<Handle<Object> >(*total_argc)); 7981 for (int i = 0; i < args_count; i++) { 7982 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate); 7983 param_data[prefix_argc + i] = val; 7984 } 7985 return param_data; 7986 } 7987 } 7988 7989 7990 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { 7991 HandleScope scope(isolate); 7992 ASSERT(args.length() == 4); 7993 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); 7994 RUNTIME_ASSERT(args[3]->IsNumber()); 7995 Handle<Object> bindee = args.at<Object>(1); 7996 7997 // TODO(lrn): Create bound function in C++ code from premade shared info. 7998 bound_function->shared()->set_bound(true); 7999 // Get all arguments of calling function (Function.prototype.bind). 8000 int argc = 0; 8001 SmartArrayPointer<Handle<Object> > arguments = 8002 GetCallerArguments(isolate, 0, &argc); 8003 // Don't count the this-arg. 8004 if (argc > 0) { 8005 ASSERT(*arguments[0] == args[2]); 8006 argc--; 8007 } else { 8008 ASSERT(args[2]->IsUndefined()); 8009 } 8010 // Initialize array of bindings (function, this, and any existing arguments 8011 // if the function was already bound). 8012 Handle<FixedArray> new_bindings; 8013 int i; 8014 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { 8015 Handle<FixedArray> old_bindings( 8016 JSFunction::cast(*bindee)->function_bindings()); 8017 new_bindings = 8018 isolate->factory()->NewFixedArray(old_bindings->length() + argc); 8019 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex), 8020 isolate); 8021 i = 0; 8022 for (int n = old_bindings->length(); i < n; i++) { 8023 new_bindings->set(i, old_bindings->get(i)); 8024 } 8025 } else { 8026 int array_size = JSFunction::kBoundArgumentsStartIndex + argc; 8027 new_bindings = isolate->factory()->NewFixedArray(array_size); 8028 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); 8029 new_bindings->set(JSFunction::kBoundThisIndex, args[2]); 8030 i = 2; 8031 } 8032 // Copy arguments, skipping the first which is "this_arg". 8033 for (int j = 0; j < argc; j++, i++) { 8034 new_bindings->set(i, *arguments[j + 1]); 8035 } 8036 new_bindings->set_map_no_write_barrier( 8037 isolate->heap()->fixed_cow_array_map()); 8038 bound_function->set_function_bindings(*new_bindings); 8039 8040 // Update length. 8041 Handle<String> length_string = isolate->factory()->length_string(); 8042 Handle<Object> new_length(args.at<Object>(3)); 8043 PropertyAttributes attr = 8044 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); 8045 ForceSetProperty(bound_function, length_string, new_length, attr); 8046 return *bound_function; 8047 } 8048 8049 8050 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { 8051 HandleScope handles(isolate); 8052 ASSERT(args.length() == 1); 8053 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); 8054 if (callable->IsJSFunction()) { 8055 Handle<JSFunction> function = Handle<JSFunction>::cast(callable); 8056 if (function->shared()->bound()) { 8057 Handle<FixedArray> bindings(function->function_bindings()); 8058 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); 8059 return *isolate->factory()->NewJSArrayWithElements(bindings); 8060 } 8061 } 8062 return isolate->heap()->undefined_value(); 8063 } 8064 8065 8066 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { 8067 HandleScope scope(isolate); 8068 ASSERT(args.length() == 1); 8069 // First argument is a function to use as a constructor. 8070 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8071 RUNTIME_ASSERT(function->shared()->bound()); 8072 8073 // The argument is a bound function. Extract its bound arguments 8074 // and callable. 8075 Handle<FixedArray> bound_args = 8076 Handle<FixedArray>(FixedArray::cast(function->function_bindings())); 8077 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; 8078 Handle<Object> bound_function( 8079 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)), 8080 isolate); 8081 ASSERT(!bound_function->IsJSFunction() || 8082 !Handle<JSFunction>::cast(bound_function)->shared()->bound()); 8083 8084 int total_argc = 0; 8085 SmartArrayPointer<Handle<Object> > param_data = 8086 GetCallerArguments(isolate, bound_argc, &total_argc); 8087 for (int i = 0; i < bound_argc; i++) { 8088 param_data[i] = Handle<Object>(bound_args->get( 8089 JSFunction::kBoundArgumentsStartIndex + i), isolate); 8090 } 8091 8092 if (!bound_function->IsJSFunction()) { 8093 bool exception_thrown; 8094 bound_function = Execution::TryGetConstructorDelegate(bound_function, 8095 &exception_thrown); 8096 if (exception_thrown) return Failure::Exception(); 8097 } 8098 ASSERT(bound_function->IsJSFunction()); 8099 8100 bool exception = false; 8101 Handle<Object> result = 8102 Execution::New(Handle<JSFunction>::cast(bound_function), 8103 total_argc, *param_data, &exception); 8104 if (exception) { 8105 return Failure::Exception(); 8106 } 8107 ASSERT(!result.is_null()); 8108 return *result; 8109 } 8110 8111 8112 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { 8113 HandleScope scope(isolate); 8114 ASSERT(args.length() == 1); 8115 8116 Handle<Object> constructor = args.at<Object>(0); 8117 8118 // If the constructor isn't a proper function we throw a type error. 8119 if (!constructor->IsJSFunction()) { 8120 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8121 Handle<Object> type_error = 8122 isolate->factory()->NewTypeError("not_constructor", arguments); 8123 return isolate->Throw(*type_error); 8124 } 8125 8126 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 8127 8128 // If function should not have prototype, construction is not allowed. In this 8129 // case generated code bailouts here, since function has no initial_map. 8130 if (!function->should_have_prototype() && !function->shared()->bound()) { 8131 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8132 Handle<Object> type_error = 8133 isolate->factory()->NewTypeError("not_constructor", arguments); 8134 return isolate->Throw(*type_error); 8135 } 8136 8137 #ifdef ENABLE_DEBUGGER_SUPPORT 8138 Debug* debug = isolate->debug(); 8139 // Handle stepping into constructors if step into is active. 8140 if (debug->StepInActive()) { 8141 debug->HandleStepIn(function, Handle<Object>::null(), 0, true); 8142 } 8143 #endif 8144 8145 if (function->has_initial_map()) { 8146 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 8147 // The 'Function' function ignores the receiver object when 8148 // called using 'new' and creates a new JSFunction object that 8149 // is returned. The receiver object is only used for error 8150 // reporting if an error occurs when constructing the new 8151 // JSFunction. Factory::NewJSObject() should not be used to 8152 // allocate JSFunctions since it does not properly initialize 8153 // the shared part of the function. Since the receiver is 8154 // ignored anyway, we use the global object as the receiver 8155 // instead of a new JSFunction object. This way, errors are 8156 // reported the same way whether or not 'Function' is called 8157 // using 'new'. 8158 return isolate->context()->global_object(); 8159 } 8160 } 8161 8162 // The function should be compiled for the optimization hints to be 8163 // available. 8164 JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION); 8165 8166 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 8167 if (!function->has_initial_map() && 8168 shared->IsInobjectSlackTrackingInProgress()) { 8169 // The tracking is already in progress for another function. We can only 8170 // track one initial_map at a time, so we force the completion before the 8171 // function is called as a constructor for the first time. 8172 shared->CompleteInobjectSlackTracking(); 8173 } 8174 8175 Handle<JSObject> result = isolate->factory()->NewJSObject(function); 8176 RETURN_IF_EMPTY_HANDLE(isolate, result); 8177 8178 isolate->counters()->constructed_objects()->Increment(); 8179 isolate->counters()->constructed_objects_runtime()->Increment(); 8180 8181 return *result; 8182 } 8183 8184 8185 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { 8186 HandleScope scope(isolate); 8187 ASSERT(args.length() == 1); 8188 8189 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8190 function->shared()->CompleteInobjectSlackTracking(); 8191 8192 return isolate->heap()->undefined_value(); 8193 } 8194 8195 8196 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { 8197 HandleScope scope(isolate); 8198 ASSERT(args.length() == 1); 8199 8200 Handle<JSFunction> function = args.at<JSFunction>(0); 8201 #ifdef DEBUG 8202 if (FLAG_trace_lazy && !function->shared()->is_compiled()) { 8203 PrintF("[lazy: "); 8204 function->PrintName(); 8205 PrintF("]\n"); 8206 } 8207 #endif 8208 8209 // Compile the target function. 8210 ASSERT(!function->is_compiled()); 8211 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) { 8212 return Failure::Exception(); 8213 } 8214 8215 // All done. Return the compiled code. 8216 ASSERT(function->is_compiled()); 8217 return function->code(); 8218 } 8219 8220 8221 bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { 8222 // If the function is not compiled ignore the lazy 8223 // recompilation. This can happen if the debugger is activated and 8224 // the function is returned to the not compiled state. 8225 if (!function->shared()->is_compiled()) return false; 8226 8227 // If the function is not optimizable or debugger is active continue using the 8228 // code from the full compiler. 8229 if (!FLAG_crankshaft || 8230 function->shared()->optimization_disabled() || 8231 isolate->DebuggerHasBreakPoints()) { 8232 if (FLAG_trace_opt) { 8233 PrintF("[failed to optimize "); 8234 function->PrintName(); 8235 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", 8236 function->shared()->optimization_disabled() ? "F" : "T", 8237 isolate->DebuggerHasBreakPoints() ? "T" : "F"); 8238 } 8239 return false; 8240 } 8241 return true; 8242 } 8243 8244 8245 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { 8246 HandleScope scope(isolate); 8247 ASSERT(args.length() == 1); 8248 Handle<JSFunction> function = args.at<JSFunction>(0); 8249 8250 if (!AllowOptimization(isolate, function)) { 8251 function->ReplaceCode(function->shared()->code()); 8252 return function->code(); 8253 } 8254 function->shared()->code()->set_profiler_ticks(0); 8255 if (JSFunction::CompileOptimized(function, 8256 BailoutId::None(), 8257 CLEAR_EXCEPTION)) { 8258 return function->code(); 8259 } 8260 if (FLAG_trace_opt) { 8261 PrintF("[failed to optimize "); 8262 function->PrintName(); 8263 PrintF(": optimized compilation failed]\n"); 8264 } 8265 function->ReplaceCode(function->shared()->code()); 8266 return function->code(); 8267 } 8268 8269 8270 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParallelRecompile) { 8271 HandleScope handle_scope(isolate); 8272 ASSERT(args.length() == 1); 8273 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8274 if (!AllowOptimization(isolate, function)) { 8275 function->ReplaceCode(function->shared()->code()); 8276 return isolate->heap()->undefined_value(); 8277 } 8278 function->shared()->code()->set_profiler_ticks(0); 8279 ASSERT(FLAG_parallel_recompilation); 8280 Compiler::RecompileParallel(function); 8281 return isolate->heap()->undefined_value(); 8282 } 8283 8284 8285 RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) { 8286 HandleScope handle_scope(isolate); 8287 ASSERT(args.length() == 1); 8288 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8289 ASSERT(V8::UseCrankshaft() && FLAG_parallel_recompilation); 8290 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 8291 return function->code(); 8292 } 8293 8294 8295 class ActivationsFinder : public ThreadVisitor { 8296 public: 8297 Code* code_; 8298 bool has_code_activations_; 8299 8300 explicit ActivationsFinder(Code* code) 8301 : code_(code), 8302 has_code_activations_(false) { } 8303 8304 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 8305 JavaScriptFrameIterator it(isolate, top); 8306 VisitFrames(&it); 8307 } 8308 8309 void VisitFrames(JavaScriptFrameIterator* it) { 8310 for (; !it->done(); it->Advance()) { 8311 JavaScriptFrame* frame = it->frame(); 8312 if (code_->contains(frame->pc())) has_code_activations_ = true; 8313 } 8314 } 8315 }; 8316 8317 8318 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) { 8319 HandleScope scope(isolate); 8320 ASSERT(args.length() == 0); 8321 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8322 ASSERT(AllowHeapAllocation::IsAllowed()); 8323 delete deoptimizer; 8324 return isolate->heap()->undefined_value(); 8325 } 8326 8327 8328 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { 8329 HandleScope scope(isolate); 8330 ASSERT(args.length() == 1); 8331 RUNTIME_ASSERT(args[0]->IsSmi()); 8332 Deoptimizer::BailoutType type = 8333 static_cast<Deoptimizer::BailoutType>(args.smi_at(0)); 8334 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8335 ASSERT(AllowHeapAllocation::IsAllowed()); 8336 8337 Handle<JSFunction> function = deoptimizer->function(); 8338 Handle<Code> optimized_code = deoptimizer->compiled_code(); 8339 8340 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION); 8341 ASSERT(type == deoptimizer->bailout_type()); 8342 8343 // Make sure to materialize objects before causing any allocation. 8344 JavaScriptFrameIterator it(isolate); 8345 deoptimizer->MaterializeHeapObjects(&it); 8346 delete deoptimizer; 8347 8348 JavaScriptFrame* frame = it.frame(); 8349 RUNTIME_ASSERT(frame->function()->IsJSFunction()); 8350 8351 // Avoid doing too much work when running with --always-opt and keep 8352 // the optimized code around. 8353 if (FLAG_always_opt || type == Deoptimizer::LAZY) { 8354 return isolate->heap()->undefined_value(); 8355 } 8356 8357 // Search for other activations of the same function and code. 8358 ActivationsFinder activations_finder(*optimized_code); 8359 activations_finder.VisitFrames(&it); 8360 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); 8361 8362 if (!activations_finder.has_code_activations_) { 8363 if (function->code() == *optimized_code) { 8364 if (FLAG_trace_deopt) { 8365 PrintF("[removing optimized code for: "); 8366 function->PrintName(); 8367 PrintF("]\n"); 8368 } 8369 function->ReplaceCode(function->shared()->code()); 8370 } 8371 } else { 8372 // TODO(titzer): we should probably do DeoptimizeCodeList(code) 8373 // unconditionally if the code is not already marked for deoptimization. 8374 // If there is an index by shared function info, all the better. 8375 Deoptimizer::DeoptimizeFunction(*function); 8376 } 8377 // Evict optimized code for this function from the cache so that it doesn't 8378 // get used for new closures. 8379 function->shared()->EvictFromOptimizedCodeMap(*optimized_code, 8380 "notify deoptimized"); 8381 8382 return isolate->heap()->undefined_value(); 8383 } 8384 8385 8386 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) { 8387 SealHandleScope shs(isolate); 8388 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8389 delete deoptimizer; 8390 return isolate->heap()->undefined_value(); 8391 } 8392 8393 8394 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { 8395 HandleScope scope(isolate); 8396 ASSERT(args.length() == 1); 8397 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8398 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 8399 8400 Deoptimizer::DeoptimizeFunction(*function); 8401 8402 return isolate->heap()->undefined_value(); 8403 } 8404 8405 8406 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) { 8407 HandleScope scope(isolate); 8408 ASSERT(args.length() == 1); 8409 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8410 Code* unoptimized = function->shared()->code(); 8411 if (unoptimized->kind() == Code::FUNCTION) { 8412 unoptimized->ClearInlineCaches(); 8413 unoptimized->ClearTypeFeedbackCells(isolate->heap()); 8414 } 8415 return isolate->heap()->undefined_value(); 8416 } 8417 8418 8419 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { 8420 SealHandleScope shs(isolate); 8421 #if defined(USE_SIMULATOR) 8422 return isolate->heap()->true_value(); 8423 #else 8424 return isolate->heap()->false_value(); 8425 #endif 8426 } 8427 8428 8429 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsParallelRecompilationSupported) { 8430 HandleScope scope(isolate); 8431 return FLAG_parallel_recompilation 8432 ? isolate->heap()->true_value() : isolate->heap()->false_value(); 8433 } 8434 8435 8436 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { 8437 HandleScope scope(isolate); 8438 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8439 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8440 8441 if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); 8442 function->MarkForLazyRecompilation(); 8443 8444 Code* unoptimized = function->shared()->code(); 8445 if (args.length() == 2 && 8446 unoptimized->kind() == Code::FUNCTION) { 8447 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 8448 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) { 8449 for (int i = 0; i <= Code::kMaxLoopNestingMarker; i++) { 8450 unoptimized->set_allow_osr_at_loop_nesting_level(i); 8451 isolate->runtime_profiler()->AttemptOnStackReplacement(*function); 8452 } 8453 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("parallel"))) { 8454 function->MarkForParallelRecompilation(); 8455 } 8456 } 8457 8458 return isolate->heap()->undefined_value(); 8459 } 8460 8461 8462 RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) { 8463 HandleScope scope(isolate); 8464 ASSERT(args.length() == 1); 8465 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8466 ASSERT(!function->IsOptimized()); 8467 function->shared()->set_optimization_disabled(true); 8468 return isolate->heap()->undefined_value(); 8469 } 8470 8471 8472 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { 8473 HandleScope scope(isolate); 8474 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8475 if (!V8::UseCrankshaft()) { 8476 return Smi::FromInt(4); // 4 == "never". 8477 } 8478 bool sync_with_compiler_thread = true; 8479 if (args.length() == 2) { 8480 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1); 8481 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) { 8482 sync_with_compiler_thread = false; 8483 } 8484 } 8485 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8486 if (FLAG_parallel_recompilation && sync_with_compiler_thread) { 8487 while (function->IsInRecompileQueue() || 8488 function->IsMarkedForInstallingRecompiledCode()) { 8489 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 8490 OS::Sleep(50); 8491 } 8492 } 8493 if (FLAG_always_opt) { 8494 // We may have always opt, but that is more best-effort than a real 8495 // promise, so we still say "no" if it is not optimized. 8496 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always". 8497 : Smi::FromInt(2); // 2 == "no". 8498 } 8499 if (FLAG_deopt_every_n_times) { 8500 return Smi::FromInt(6); // 6 == "maybe deopted". 8501 } 8502 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". 8503 : Smi::FromInt(2); // 2 == "no". 8504 } 8505 8506 8507 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { 8508 HandleScope scope(isolate); 8509 ASSERT(args.length() == 1); 8510 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8511 return Smi::FromInt(function->shared()->opt_count()); 8512 } 8513 8514 8515 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { 8516 HandleScope scope(isolate); 8517 ASSERT(args.length() == 1); 8518 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8519 8520 // We're not prepared to handle a function with arguments object. 8521 ASSERT(!function->shared()->uses_arguments()); 8522 8523 // We have hit a back edge in an unoptimized frame for a function that was 8524 // selected for on-stack replacement. Find the unoptimized code object. 8525 Handle<Code> unoptimized(function->shared()->code(), isolate); 8526 // Keep track of whether we've succeeded in optimizing. 8527 bool succeeded = unoptimized->optimizable(); 8528 if (succeeded) { 8529 // If we are trying to do OSR when there are already optimized 8530 // activations of the function, it means (a) the function is directly or 8531 // indirectly recursive and (b) an optimized invocation has been 8532 // deoptimized so that we are currently in an unoptimized activation. 8533 // Check for optimized activations of this function. 8534 JavaScriptFrameIterator it(isolate); 8535 while (succeeded && !it.done()) { 8536 JavaScriptFrame* frame = it.frame(); 8537 succeeded = !frame->is_optimized() || frame->function() != *function; 8538 it.Advance(); 8539 } 8540 } 8541 8542 BailoutId ast_id = BailoutId::None(); 8543 if (succeeded) { 8544 // The top JS function is this one, the PC is somewhere in the 8545 // unoptimized code. 8546 JavaScriptFrameIterator it(isolate); 8547 JavaScriptFrame* frame = it.frame(); 8548 ASSERT(frame->function() == *function); 8549 ASSERT(frame->LookupCode() == *unoptimized); 8550 ASSERT(unoptimized->contains(frame->pc())); 8551 8552 // Use linear search of the unoptimized code's back edge table to find 8553 // the AST id matching the PC. 8554 uint32_t target_pc_offset = 8555 static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start()); 8556 uint32_t loop_depth = 0; 8557 8558 for (FullCodeGenerator::BackEdgeTableIterator back_edges(*unoptimized); 8559 !back_edges.Done(); 8560 back_edges.Next()) { 8561 if (back_edges.pc_offset() == target_pc_offset) { 8562 ast_id = back_edges.ast_id(); 8563 loop_depth = back_edges.loop_depth(); 8564 break; 8565 } 8566 } 8567 ASSERT(!ast_id.IsNone()); 8568 8569 if (FLAG_trace_osr) { 8570 PrintF("[replacing on-stack at AST id %d, loop depth %d in ", 8571 ast_id.ToInt(), loop_depth); 8572 function->PrintName(); 8573 PrintF("]\n"); 8574 } 8575 8576 // Try to compile the optimized code. A true return value from 8577 // CompileOptimized means that compilation succeeded, not necessarily 8578 // that optimization succeeded. 8579 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) && 8580 function->IsOptimized()) { 8581 DeoptimizationInputData* data = DeoptimizationInputData::cast( 8582 function->code()->deoptimization_data()); 8583 if (data->OsrPcOffset()->value() >= 0) { 8584 if (FLAG_trace_osr) { 8585 PrintF("[on-stack replacement offset %d in optimized code]\n", 8586 data->OsrPcOffset()->value()); 8587 } 8588 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id); 8589 } else { 8590 // We may never generate the desired OSR entry if we emit an 8591 // early deoptimize. 8592 succeeded = false; 8593 } 8594 } else { 8595 succeeded = false; 8596 } 8597 } 8598 8599 // Revert to the original interrupt calls in the original unoptimized code. 8600 if (FLAG_trace_osr) { 8601 PrintF("[restoring original interrupt calls in "); 8602 function->PrintName(); 8603 PrintF("]\n"); 8604 } 8605 InterruptStub interrupt_stub; 8606 Handle<Code> interrupt_code = interrupt_stub.GetCode(isolate); 8607 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement(); 8608 Deoptimizer::RevertInterruptCode(*unoptimized, 8609 *interrupt_code, 8610 *replacement_code); 8611 8612 // If the optimization attempt succeeded, return the AST id tagged as a 8613 // smi. This tells the builtin that we need to translate the unoptimized 8614 // frame to an optimized one. 8615 if (succeeded) { 8616 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); 8617 return Smi::FromInt(ast_id.ToInt()); 8618 } else { 8619 if (function->IsMarkedForLazyRecompilation()) { 8620 function->ReplaceCode(function->shared()->code()); 8621 } 8622 return Smi::FromInt(-1); 8623 } 8624 } 8625 8626 8627 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) { 8628 SealHandleScope shs(isolate); 8629 ASSERT(args.length() == 2); 8630 #ifdef DEBUG 8631 CONVERT_SMI_ARG_CHECKED(interval, 0); 8632 CONVERT_SMI_ARG_CHECKED(timeout, 1); 8633 isolate->heap()->set_allocation_timeout(timeout); 8634 FLAG_gc_interval = interval; 8635 #endif 8636 return isolate->heap()->undefined_value(); 8637 } 8638 8639 8640 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { 8641 SealHandleScope shs(isolate); 8642 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8643 return isolate->heap()->undefined_value(); 8644 } 8645 8646 8647 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) { 8648 SealHandleScope shs(isolate); 8649 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8650 return isolate->heap()->nan_value(); 8651 } 8652 8653 8654 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { 8655 HandleScope scope(isolate); 8656 ASSERT(args.length() >= 2); 8657 int argc = args.length() - 2; 8658 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1); 8659 Object* receiver = args[0]; 8660 8661 // If there are too many arguments, allocate argv via malloc. 8662 const int argv_small_size = 10; 8663 Handle<Object> argv_small_buffer[argv_small_size]; 8664 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8665 Handle<Object>* argv = argv_small_buffer; 8666 if (argc > argv_small_size) { 8667 argv = new Handle<Object>[argc]; 8668 if (argv == NULL) return isolate->StackOverflow(); 8669 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8670 } 8671 8672 for (int i = 0; i < argc; ++i) { 8673 MaybeObject* maybe = args[1 + i]; 8674 Object* object; 8675 if (!maybe->To<Object>(&object)) return maybe; 8676 argv[i] = Handle<Object>(object, isolate); 8677 } 8678 8679 bool threw; 8680 Handle<JSReceiver> hfun(fun); 8681 Handle<Object> hreceiver(receiver, isolate); 8682 Handle<Object> result = 8683 Execution::Call(hfun, hreceiver, argc, argv, &threw, true); 8684 8685 if (threw) return Failure::Exception(); 8686 return *result; 8687 } 8688 8689 8690 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { 8691 HandleScope scope(isolate); 8692 ASSERT(args.length() == 5); 8693 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); 8694 Handle<Object> receiver = args.at<Object>(1); 8695 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); 8696 CONVERT_SMI_ARG_CHECKED(offset, 3); 8697 CONVERT_SMI_ARG_CHECKED(argc, 4); 8698 RUNTIME_ASSERT(offset >= 0); 8699 RUNTIME_ASSERT(argc >= 0); 8700 8701 // If there are too many arguments, allocate argv via malloc. 8702 const int argv_small_size = 10; 8703 Handle<Object> argv_small_buffer[argv_small_size]; 8704 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8705 Handle<Object>* argv = argv_small_buffer; 8706 if (argc > argv_small_size) { 8707 argv = new Handle<Object>[argc]; 8708 if (argv == NULL) return isolate->StackOverflow(); 8709 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8710 } 8711 8712 for (int i = 0; i < argc; ++i) { 8713 argv[i] = Object::GetElement(arguments, offset + i); 8714 } 8715 8716 bool threw; 8717 Handle<Object> result = 8718 Execution::Call(fun, receiver, argc, argv, &threw, true); 8719 8720 if (threw) return Failure::Exception(); 8721 return *result; 8722 } 8723 8724 8725 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { 8726 HandleScope scope(isolate); 8727 ASSERT(args.length() == 1); 8728 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8729 return *Execution::GetFunctionDelegate(args.at<Object>(0)); 8730 } 8731 8732 8733 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) { 8734 HandleScope scope(isolate); 8735 ASSERT(args.length() == 1); 8736 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8737 return *Execution::GetConstructorDelegate(args.at<Object>(0)); 8738 } 8739 8740 8741 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) { 8742 SealHandleScope shs(isolate); 8743 ASSERT(args.length() == 2); 8744 8745 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8746 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1); 8747 Context* result; 8748 MaybeObject* maybe_result = 8749 isolate->heap()->AllocateGlobalContext(function, scope_info); 8750 if (!maybe_result->To(&result)) return maybe_result; 8751 8752 ASSERT(function->context() == isolate->context()); 8753 ASSERT(function->context()->global_object() == result->global_object()); 8754 isolate->set_context(result); 8755 result->global_object()->set_global_context(result); 8756 8757 return result; // non-failure 8758 } 8759 8760 8761 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) { 8762 SealHandleScope shs(isolate); 8763 ASSERT(args.length() == 1); 8764 8765 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8766 int length = function->shared()->scope_info()->ContextLength(); 8767 Context* result; 8768 MaybeObject* maybe_result = 8769 isolate->heap()->AllocateFunctionContext(length, function); 8770 if (!maybe_result->To(&result)) return maybe_result; 8771 8772 isolate->set_context(result); 8773 8774 return result; // non-failure 8775 } 8776 8777 8778 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) { 8779 SealHandleScope shs(isolate); 8780 ASSERT(args.length() == 2); 8781 JSReceiver* extension_object; 8782 if (args[0]->IsJSReceiver()) { 8783 extension_object = JSReceiver::cast(args[0]); 8784 } else { 8785 // Convert the object to a proper JavaScript object. 8786 MaybeObject* maybe_js_object = args[0]->ToObject(); 8787 if (!maybe_js_object->To(&extension_object)) { 8788 if (Failure::cast(maybe_js_object)->IsInternalError()) { 8789 HandleScope scope(isolate); 8790 Handle<Object> handle = args.at<Object>(0); 8791 Handle<Object> result = 8792 isolate->factory()->NewTypeError("with_expression", 8793 HandleVector(&handle, 1)); 8794 return isolate->Throw(*result); 8795 } else { 8796 return maybe_js_object; 8797 } 8798 } 8799 } 8800 8801 JSFunction* function; 8802 if (args[1]->IsSmi()) { 8803 // A smi sentinel indicates a context nested inside global code rather 8804 // than some function. There is a canonical empty function that can be 8805 // gotten from the native context. 8806 function = isolate->context()->native_context()->closure(); 8807 } else { 8808 function = JSFunction::cast(args[1]); 8809 } 8810 8811 Context* context; 8812 MaybeObject* maybe_context = 8813 isolate->heap()->AllocateWithContext(function, 8814 isolate->context(), 8815 extension_object); 8816 if (!maybe_context->To(&context)) return maybe_context; 8817 isolate->set_context(context); 8818 return context; 8819 } 8820 8821 8822 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { 8823 SealHandleScope shs(isolate); 8824 ASSERT(args.length() == 3); 8825 String* name = String::cast(args[0]); 8826 Object* thrown_object = args[1]; 8827 JSFunction* function; 8828 if (args[2]->IsSmi()) { 8829 // A smi sentinel indicates a context nested inside global code rather 8830 // than some function. There is a canonical empty function that can be 8831 // gotten from the native context. 8832 function = isolate->context()->native_context()->closure(); 8833 } else { 8834 function = JSFunction::cast(args[2]); 8835 } 8836 Context* context; 8837 MaybeObject* maybe_context = 8838 isolate->heap()->AllocateCatchContext(function, 8839 isolate->context(), 8840 name, 8841 thrown_object); 8842 if (!maybe_context->To(&context)) return maybe_context; 8843 isolate->set_context(context); 8844 return context; 8845 } 8846 8847 8848 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { 8849 SealHandleScope shs(isolate); 8850 ASSERT(args.length() == 2); 8851 ScopeInfo* scope_info = ScopeInfo::cast(args[0]); 8852 JSFunction* function; 8853 if (args[1]->IsSmi()) { 8854 // A smi sentinel indicates a context nested inside global code rather 8855 // than some function. There is a canonical empty function that can be 8856 // gotten from the native context. 8857 function = isolate->context()->native_context()->closure(); 8858 } else { 8859 function = JSFunction::cast(args[1]); 8860 } 8861 Context* context; 8862 MaybeObject* maybe_context = 8863 isolate->heap()->AllocateBlockContext(function, 8864 isolate->context(), 8865 scope_info); 8866 if (!maybe_context->To(&context)) return maybe_context; 8867 isolate->set_context(context); 8868 return context; 8869 } 8870 8871 8872 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) { 8873 SealHandleScope shs(isolate); 8874 ASSERT(args.length() == 1); 8875 Object* obj = args[0]; 8876 return isolate->heap()->ToBoolean(obj->IsJSModule()); 8877 } 8878 8879 8880 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { 8881 SealHandleScope shs(isolate); 8882 ASSERT(args.length() == 2); 8883 CONVERT_SMI_ARG_CHECKED(index, 0); 8884 8885 if (!args[1]->IsScopeInfo()) { 8886 // Module already initialized. Find hosting context and retrieve context. 8887 Context* host = Context::cast(isolate->context())->global_context(); 8888 Context* context = Context::cast(host->get(index)); 8889 ASSERT(context->previous() == isolate->context()); 8890 isolate->set_context(context); 8891 return context; 8892 } 8893 8894 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); 8895 8896 // Allocate module context. 8897 HandleScope scope(isolate); 8898 Factory* factory = isolate->factory(); 8899 Handle<Context> context = factory->NewModuleContext(scope_info); 8900 Handle<JSModule> module = factory->NewJSModule(context, scope_info); 8901 context->set_module(*module); 8902 Context* previous = isolate->context(); 8903 context->set_previous(previous); 8904 context->set_closure(previous->closure()); 8905 context->set_global_object(previous->global_object()); 8906 isolate->set_context(*context); 8907 8908 // Find hosting scope and initialize internal variable holding module there. 8909 previous->global_context()->set(index, *context); 8910 8911 return *context; 8912 } 8913 8914 8915 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { 8916 HandleScope scope(isolate); 8917 ASSERT(args.length() == 1); 8918 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); 8919 Context* host_context = isolate->context(); 8920 8921 for (int i = 0; i < descriptions->length(); ++i) { 8922 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i))); 8923 int host_index = description->host_index(); 8924 Handle<Context> context(Context::cast(host_context->get(host_index))); 8925 Handle<JSModule> module(context->module()); 8926 8927 for (int j = 0; j < description->length(); ++j) { 8928 Handle<String> name(description->name(j)); 8929 VariableMode mode = description->mode(j); 8930 int index = description->index(j); 8931 switch (mode) { 8932 case VAR: 8933 case LET: 8934 case CONST: 8935 case CONST_HARMONY: { 8936 PropertyAttributes attr = 8937 IsImmutableVariableMode(mode) ? FROZEN : SEALED; 8938 Handle<AccessorInfo> info = 8939 Accessors::MakeModuleExport(name, index, attr); 8940 Handle<Object> result = SetAccessor(module, info); 8941 ASSERT(!(result.is_null() || result->IsUndefined())); 8942 USE(result); 8943 break; 8944 } 8945 case MODULE: { 8946 Object* referenced_context = Context::cast(host_context)->get(index); 8947 Handle<JSModule> value(Context::cast(referenced_context)->module()); 8948 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode); 8949 break; 8950 } 8951 case INTERNAL: 8952 case TEMPORARY: 8953 case DYNAMIC: 8954 case DYNAMIC_GLOBAL: 8955 case DYNAMIC_LOCAL: 8956 UNREACHABLE(); 8957 } 8958 } 8959 8960 JSObject::PreventExtensions(module); 8961 } 8962 8963 ASSERT(!isolate->has_pending_exception()); 8964 return isolate->heap()->undefined_value(); 8965 } 8966 8967 8968 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { 8969 HandleScope scope(isolate); 8970 ASSERT(args.length() == 2); 8971 8972 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 8973 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 8974 8975 int index; 8976 PropertyAttributes attributes; 8977 ContextLookupFlags flags = FOLLOW_CHAINS; 8978 BindingFlags binding_flags; 8979 Handle<Object> holder = context->Lookup(name, 8980 flags, 8981 &index, 8982 &attributes, 8983 &binding_flags); 8984 8985 // If the slot was not found the result is true. 8986 if (holder.is_null()) { 8987 return isolate->heap()->true_value(); 8988 } 8989 8990 // If the slot was found in a context, it should be DONT_DELETE. 8991 if (holder->IsContext()) { 8992 return isolate->heap()->false_value(); 8993 } 8994 8995 // The slot was found in a JSObject, either a context extension object, 8996 // the global object, or the subject of a with. Try to delete it 8997 // (respecting DONT_DELETE). 8998 Handle<JSObject> object = Handle<JSObject>::cast(holder); 8999 Handle<Object> result = JSReceiver::DeleteProperty(object, name); 9000 RETURN_IF_EMPTY_HANDLE(isolate, result); 9001 return *result; 9002 } 9003 9004 9005 // A mechanism to return a pair of Object pointers in registers (if possible). 9006 // How this is achieved is calling convention-dependent. 9007 // All currently supported x86 compiles uses calling conventions that are cdecl 9008 // variants where a 64-bit value is returned in two 32-bit registers 9009 // (edx:eax on ia32, r1:r0 on ARM). 9010 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 9011 // In Win64 calling convention, a struct of two pointers is returned in memory, 9012 // allocated by the caller, and passed as a pointer in a hidden first parameter. 9013 #ifdef V8_HOST_ARCH_64_BIT 9014 struct ObjectPair { 9015 MaybeObject* x; 9016 MaybeObject* y; 9017 }; 9018 9019 9020 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 9021 ObjectPair result = {x, y}; 9022 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 9023 // In Win64 they are assigned to a hidden first argument. 9024 return result; 9025 } 9026 #else 9027 typedef uint64_t ObjectPair; 9028 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 9029 return reinterpret_cast<uint32_t>(x) | 9030 (reinterpret_cast<ObjectPair>(y) << 32); 9031 } 9032 #endif 9033 9034 9035 static inline MaybeObject* Unhole(Heap* heap, 9036 MaybeObject* x, 9037 PropertyAttributes attributes) { 9038 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 9039 USE(attributes); 9040 return x->IsTheHole() ? heap->undefined_value() : x; 9041 } 9042 9043 9044 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, 9045 JSObject* holder) { 9046 ASSERT(!holder->IsGlobalObject()); 9047 Context* top = isolate->context(); 9048 // Get the context extension function. 9049 JSFunction* context_extension_function = 9050 top->native_context()->context_extension_function(); 9051 // If the holder isn't a context extension object, we just return it 9052 // as the receiver. This allows arguments objects to be used as 9053 // receivers, but only if they are put in the context scope chain 9054 // explicitly via a with-statement. 9055 Object* constructor = holder->map()->constructor(); 9056 if (constructor != context_extension_function) return holder; 9057 // Fall back to using the global object as the implicit receiver if 9058 // the property turns out to be a local variable allocated in a 9059 // context extension object - introduced via eval. Implicit global 9060 // receivers are indicated with the hole value. 9061 return isolate->heap()->the_hole_value(); 9062 } 9063 9064 9065 static ObjectPair LoadContextSlotHelper(Arguments args, 9066 Isolate* isolate, 9067 bool throw_error) { 9068 HandleScope scope(isolate); 9069 ASSERT_EQ(2, args.length()); 9070 9071 if (!args[0]->IsContext() || !args[1]->IsString()) { 9072 return MakePair(isolate->ThrowIllegalOperation(), NULL); 9073 } 9074 Handle<Context> context = args.at<Context>(0); 9075 Handle<String> name = args.at<String>(1); 9076 9077 int index; 9078 PropertyAttributes attributes; 9079 ContextLookupFlags flags = FOLLOW_CHAINS; 9080 BindingFlags binding_flags; 9081 Handle<Object> holder = context->Lookup(name, 9082 flags, 9083 &index, 9084 &attributes, 9085 &binding_flags); 9086 if (isolate->has_pending_exception()) { 9087 return MakePair(Failure::Exception(), NULL); 9088 } 9089 9090 // If the index is non-negative, the slot has been found in a context. 9091 if (index >= 0) { 9092 ASSERT(holder->IsContext()); 9093 // If the "property" we were looking for is a local variable, the 9094 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. 9095 // 9096 // Use the hole as the receiver to signal that the receiver is implicit 9097 // and that the global receiver should be used (as distinguished from an 9098 // explicit receiver that happens to be a global object). 9099 Handle<Object> receiver = isolate->factory()->the_hole_value(); 9100 Object* value = Context::cast(*holder)->get(index); 9101 // Check for uninitialized bindings. 9102 switch (binding_flags) { 9103 case MUTABLE_CHECK_INITIALIZED: 9104 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: 9105 if (value->IsTheHole()) { 9106 Handle<Object> reference_error = 9107 isolate->factory()->NewReferenceError("not_defined", 9108 HandleVector(&name, 1)); 9109 return MakePair(isolate->Throw(*reference_error), NULL); 9110 } 9111 // FALLTHROUGH 9112 case MUTABLE_IS_INITIALIZED: 9113 case IMMUTABLE_IS_INITIALIZED: 9114 case IMMUTABLE_IS_INITIALIZED_HARMONY: 9115 ASSERT(!value->IsTheHole()); 9116 return MakePair(value, *receiver); 9117 case IMMUTABLE_CHECK_INITIALIZED: 9118 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); 9119 case MISSING_BINDING: 9120 UNREACHABLE(); 9121 return MakePair(NULL, NULL); 9122 } 9123 } 9124 9125 // Otherwise, if the slot was found the holder is a context extension 9126 // object, subject of a with, or a global object. We read the named 9127 // property from it. 9128 if (!holder.is_null()) { 9129 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); 9130 ASSERT(object->IsJSProxy() || object->HasProperty(*name)); 9131 // GetProperty below can cause GC. 9132 Handle<Object> receiver_handle( 9133 object->IsGlobalObject() 9134 ? GlobalObject::cast(*object)->global_receiver() 9135 : object->IsJSProxy() ? static_cast<Object*>(*object) 9136 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)), 9137 isolate); 9138 9139 // No need to unhole the value here. This is taken care of by the 9140 // GetProperty function. 9141 MaybeObject* value = object->GetProperty(*name); 9142 return MakePair(value, *receiver_handle); 9143 } 9144 9145 if (throw_error) { 9146 // The property doesn't exist - throw exception. 9147 Handle<Object> reference_error = 9148 isolate->factory()->NewReferenceError("not_defined", 9149 HandleVector(&name, 1)); 9150 return MakePair(isolate->Throw(*reference_error), NULL); 9151 } else { 9152 // The property doesn't exist - return undefined. 9153 return MakePair(isolate->heap()->undefined_value(), 9154 isolate->heap()->undefined_value()); 9155 } 9156 } 9157 9158 9159 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) { 9160 return LoadContextSlotHelper(args, isolate, true); 9161 } 9162 9163 9164 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) { 9165 return LoadContextSlotHelper(args, isolate, false); 9166 } 9167 9168 9169 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { 9170 HandleScope scope(isolate); 9171 ASSERT(args.length() == 4); 9172 9173 Handle<Object> value(args[0], isolate); 9174 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); 9175 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); 9176 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 9177 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE) 9178 ? kNonStrictMode : kStrictMode; 9179 9180 int index; 9181 PropertyAttributes attributes; 9182 ContextLookupFlags flags = FOLLOW_CHAINS; 9183 BindingFlags binding_flags; 9184 Handle<Object> holder = context->Lookup(name, 9185 flags, 9186 &index, 9187 &attributes, 9188 &binding_flags); 9189 if (isolate->has_pending_exception()) return Failure::Exception(); 9190 9191 if (index >= 0) { 9192 // The property was found in a context slot. 9193 Handle<Context> context = Handle<Context>::cast(holder); 9194 if (binding_flags == MUTABLE_CHECK_INITIALIZED && 9195 context->get(index)->IsTheHole()) { 9196 Handle<Object> error = 9197 isolate->factory()->NewReferenceError("not_defined", 9198 HandleVector(&name, 1)); 9199 return isolate->Throw(*error); 9200 } 9201 // Ignore if read_only variable. 9202 if ((attributes & READ_ONLY) == 0) { 9203 // Context is a fixed array and set cannot fail. 9204 context->set(index, *value); 9205 } else if (strict_mode == kStrictMode) { 9206 // Setting read only property in strict mode. 9207 Handle<Object> error = 9208 isolate->factory()->NewTypeError("strict_cannot_assign", 9209 HandleVector(&name, 1)); 9210 return isolate->Throw(*error); 9211 } 9212 return *value; 9213 } 9214 9215 // Slow case: The property is not in a context slot. It is either in a 9216 // context extension object, a property of the subject of a with, or a 9217 // property of the global object. 9218 Handle<JSReceiver> object; 9219 9220 if (!holder.is_null()) { 9221 // The property exists on the holder. 9222 object = Handle<JSReceiver>::cast(holder); 9223 } else { 9224 // The property was not found. 9225 ASSERT(attributes == ABSENT); 9226 9227 if (strict_mode == kStrictMode) { 9228 // Throw in strict mode (assignment to undefined variable). 9229 Handle<Object> error = 9230 isolate->factory()->NewReferenceError( 9231 "not_defined", HandleVector(&name, 1)); 9232 return isolate->Throw(*error); 9233 } 9234 // In non-strict mode, the property is added to the global object. 9235 attributes = NONE; 9236 object = Handle<JSReceiver>(isolate->context()->global_object()); 9237 } 9238 9239 // Set the property if it's not read only or doesn't yet exist. 9240 if ((attributes & READ_ONLY) == 0 || 9241 (object->GetLocalPropertyAttribute(*name) == ABSENT)) { 9242 RETURN_IF_EMPTY_HANDLE( 9243 isolate, 9244 JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); 9245 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { 9246 // Setting read only property in strict mode. 9247 Handle<Object> error = 9248 isolate->factory()->NewTypeError( 9249 "strict_cannot_assign", HandleVector(&name, 1)); 9250 return isolate->Throw(*error); 9251 } 9252 return *value; 9253 } 9254 9255 9256 RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { 9257 HandleScope scope(isolate); 9258 ASSERT(args.length() == 1); 9259 9260 return isolate->Throw(args[0]); 9261 } 9262 9263 9264 RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { 9265 HandleScope scope(isolate); 9266 ASSERT(args.length() == 1); 9267 9268 return isolate->ReThrow(args[0]); 9269 } 9270 9271 9272 RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) { 9273 SealHandleScope shs(isolate); 9274 ASSERT_EQ(0, args.length()); 9275 return isolate->PromoteScheduledException(); 9276 } 9277 9278 9279 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { 9280 HandleScope scope(isolate); 9281 ASSERT(args.length() == 1); 9282 9283 Handle<Object> name(args[0], isolate); 9284 Handle<Object> reference_error = 9285 isolate->factory()->NewReferenceError("not_defined", 9286 HandleVector(&name, 1)); 9287 return isolate->Throw(*reference_error); 9288 } 9289 9290 9291 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) { 9292 HandleScope scope(isolate); 9293 ASSERT(args.length() == 0); 9294 return isolate->Throw(*isolate->factory()->NewTypeError( 9295 "not_date_object", HandleVector<Object>(NULL, 0))); 9296 } 9297 9298 9299 9300 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { 9301 SealHandleScope shs(isolate); 9302 ASSERT(args.length() == 0); 9303 9304 // First check if this is a real stack overflow. 9305 if (isolate->stack_guard()->IsStackOverflow()) { 9306 SealHandleScope shs(isolate); 9307 return isolate->StackOverflow(); 9308 } 9309 9310 return Execution::HandleStackGuardInterrupt(isolate); 9311 } 9312 9313 9314 RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) { 9315 SealHandleScope shs(isolate); 9316 ASSERT(args.length() == 0); 9317 return Execution::HandleStackGuardInterrupt(isolate); 9318 } 9319 9320 9321 static int StackSize(Isolate* isolate) { 9322 int n = 0; 9323 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; 9324 return n; 9325 } 9326 9327 9328 static void PrintTransition(Isolate* isolate, Object* result) { 9329 // indentation 9330 { const int nmax = 80; 9331 int n = StackSize(isolate); 9332 if (n <= nmax) 9333 PrintF("%4d:%*s", n, n, ""); 9334 else 9335 PrintF("%4d:%*s", n, nmax, "..."); 9336 } 9337 9338 if (result == NULL) { 9339 JavaScriptFrame::PrintTop(isolate, stdout, true, false); 9340 PrintF(" {\n"); 9341 } else { 9342 // function result 9343 PrintF("} -> "); 9344 result->ShortPrint(); 9345 PrintF("\n"); 9346 } 9347 } 9348 9349 9350 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { 9351 SealHandleScope shs(isolate); 9352 ASSERT(args.length() == 0); 9353 PrintTransition(isolate, NULL); 9354 return isolate->heap()->undefined_value(); 9355 } 9356 9357 9358 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) { 9359 SealHandleScope shs(isolate); 9360 PrintTransition(isolate, args[0]); 9361 return args[0]; // return TOS 9362 } 9363 9364 9365 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { 9366 SealHandleScope shs(isolate); 9367 ASSERT(args.length() == 1); 9368 9369 #ifdef DEBUG 9370 if (args[0]->IsString()) { 9371 // If we have a string, assume it's a code "marker" 9372 // and print some interesting cpu debugging info. 9373 JavaScriptFrameIterator it(isolate); 9374 JavaScriptFrame* frame = it.frame(); 9375 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 9376 frame->fp(), frame->sp(), frame->caller_sp()); 9377 } else { 9378 PrintF("DebugPrint: "); 9379 } 9380 args[0]->Print(); 9381 if (args[0]->IsHeapObject()) { 9382 PrintF("\n"); 9383 HeapObject::cast(args[0])->map()->Print(); 9384 } 9385 #else 9386 // ShortPrint is available in release mode. Print is not. 9387 args[0]->ShortPrint(); 9388 #endif 9389 PrintF("\n"); 9390 Flush(); 9391 9392 return args[0]; // return TOS 9393 } 9394 9395 9396 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { 9397 SealHandleScope shs(isolate); 9398 ASSERT(args.length() == 0); 9399 isolate->PrintStack(stdout); 9400 return isolate->heap()->undefined_value(); 9401 } 9402 9403 9404 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) { 9405 SealHandleScope shs(isolate); 9406 ASSERT(args.length() == 0); 9407 9408 // According to ECMA-262, section 15.9.1, page 117, the precision of 9409 // the number in a Date object representing a particular instant in 9410 // time is milliseconds. Therefore, we floor the result of getting 9411 // the OS time. 9412 double millis = floor(OS::TimeCurrentMillis()); 9413 return isolate->heap()->NumberFromDouble(millis); 9414 } 9415 9416 9417 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { 9418 HandleScope scope(isolate); 9419 ASSERT(args.length() == 2); 9420 9421 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 9422 FlattenString(str); 9423 9424 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); 9425 9426 MaybeObject* maybe_result_array = 9427 output->EnsureCanContainHeapObjectElements(); 9428 if (maybe_result_array->IsFailure()) return maybe_result_array; 9429 RUNTIME_ASSERT(output->HasFastObjectElements()); 9430 9431 DisallowHeapAllocation no_gc; 9432 9433 FixedArray* output_array = FixedArray::cast(output->elements()); 9434 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 9435 bool result; 9436 String::FlatContent str_content = str->GetFlatContent(); 9437 if (str_content.IsAscii()) { 9438 result = DateParser::Parse(str_content.ToOneByteVector(), 9439 output_array, 9440 isolate->unicode_cache()); 9441 } else { 9442 ASSERT(str_content.IsTwoByte()); 9443 result = DateParser::Parse(str_content.ToUC16Vector(), 9444 output_array, 9445 isolate->unicode_cache()); 9446 } 9447 9448 if (result) { 9449 return *output; 9450 } else { 9451 return isolate->heap()->null_value(); 9452 } 9453 } 9454 9455 9456 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) { 9457 SealHandleScope shs(isolate); 9458 ASSERT(args.length() == 1); 9459 9460 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9461 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x)); 9462 const char* zone = OS::LocalTimezone(static_cast<double>(time)); 9463 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone)); 9464 } 9465 9466 9467 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) { 9468 SealHandleScope shs(isolate); 9469 ASSERT(args.length() == 1); 9470 9471 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9472 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); 9473 9474 return isolate->heap()->NumberFromDouble(static_cast<double>(time)); 9475 } 9476 9477 9478 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) { 9479 SealHandleScope shs(isolate); 9480 ASSERT(args.length() == 1); 9481 Object* global = args[0]; 9482 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); 9483 return JSGlobalObject::cast(global)->global_receiver(); 9484 } 9485 9486 9487 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { 9488 HandleScope scope(isolate); 9489 ASSERT_EQ(1, args.length()); 9490 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9491 9492 source = Handle<String>(FlattenGetString(source)); 9493 // Optimized fast case where we only have ASCII characters. 9494 Handle<Object> result; 9495 if (source->IsSeqOneByteString()) { 9496 result = JsonParser<true>::Parse(source); 9497 } else { 9498 result = JsonParser<false>::Parse(source); 9499 } 9500 if (result.is_null()) { 9501 // Syntax error or stack overflow in scanner. 9502 ASSERT(isolate->has_pending_exception()); 9503 return Failure::Exception(); 9504 } 9505 return *result; 9506 } 9507 9508 9509 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 9510 Handle<Context> context) { 9511 ASSERT(context->allow_code_gen_from_strings()->IsFalse()); 9512 // Check with callback if set. 9513 AllowCodeGenerationFromStringsCallback callback = 9514 isolate->allow_code_gen_callback(); 9515 if (callback == NULL) { 9516 // No callback set and code generation disallowed. 9517 return false; 9518 } else { 9519 // Callback set. Let it decide if code generation is allowed. 9520 VMState<EXTERNAL> state(isolate); 9521 return callback(v8::Utils::ToLocal(context)); 9522 } 9523 } 9524 9525 9526 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { 9527 HandleScope scope(isolate); 9528 ASSERT_EQ(2, args.length()); 9529 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9530 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); 9531 9532 // Extract native context. 9533 Handle<Context> context(isolate->context()->native_context()); 9534 9535 // Check if native context allows code generation from 9536 // strings. Throw an exception if it doesn't. 9537 if (context->allow_code_gen_from_strings()->IsFalse() && 9538 !CodeGenerationFromStringsAllowed(isolate, context)) { 9539 Handle<Object> error_message = 9540 context->ErrorMessageForCodeGenerationFromStrings(); 9541 return isolate->Throw(*isolate->factory()->NewEvalError( 9542 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9543 } 9544 9545 // Compile source string in the native context. 9546 ParseRestriction restriction = function_literal_only 9547 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; 9548 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9549 source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); 9550 RETURN_IF_EMPTY_HANDLE(isolate, shared); 9551 Handle<JSFunction> fun = 9552 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 9553 context, 9554 NOT_TENURED); 9555 return *fun; 9556 } 9557 9558 9559 static ObjectPair CompileGlobalEval(Isolate* isolate, 9560 Handle<String> source, 9561 Handle<Object> receiver, 9562 LanguageMode language_mode, 9563 int scope_position) { 9564 Handle<Context> context = Handle<Context>(isolate->context()); 9565 Handle<Context> native_context = Handle<Context>(context->native_context()); 9566 9567 // Check if native context allows code generation from 9568 // strings. Throw an exception if it doesn't. 9569 if (native_context->allow_code_gen_from_strings()->IsFalse() && 9570 !CodeGenerationFromStringsAllowed(isolate, native_context)) { 9571 Handle<Object> error_message = 9572 native_context->ErrorMessageForCodeGenerationFromStrings(); 9573 isolate->Throw(*isolate->factory()->NewEvalError( 9574 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9575 return MakePair(Failure::Exception(), NULL); 9576 } 9577 9578 // Deal with a normal eval call with a string argument. Compile it 9579 // and return the compiled function bound in the local context. 9580 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9581 source, 9582 context, 9583 context->IsNativeContext(), 9584 language_mode, 9585 NO_PARSE_RESTRICTION, 9586 scope_position); 9587 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared, 9588 MakePair(Failure::Exception(), NULL)); 9589 Handle<JSFunction> compiled = 9590 isolate->factory()->NewFunctionFromSharedFunctionInfo( 9591 shared, context, NOT_TENURED); 9592 return MakePair(*compiled, *receiver); 9593 } 9594 9595 9596 RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { 9597 HandleScope scope(isolate); 9598 ASSERT(args.length() == 5); 9599 9600 Handle<Object> callee = args.at<Object>(0); 9601 9602 // If "eval" didn't refer to the original GlobalEval, it's not a 9603 // direct call to eval. 9604 // (And even if it is, but the first argument isn't a string, just let 9605 // execution default to an indirect call to eval, which will also return 9606 // the first argument without doing anything). 9607 if (*callee != isolate->native_context()->global_eval_fun() || 9608 !args[1]->IsString()) { 9609 return MakePair(*callee, isolate->heap()->the_hole_value()); 9610 } 9611 9612 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 9613 ASSERT(args[4]->IsSmi()); 9614 return CompileGlobalEval(isolate, 9615 args.at<String>(1), 9616 args.at<Object>(2), 9617 language_mode, 9618 args.smi_at(4)); 9619 } 9620 9621 9622 static MaybeObject* Allocate(Isolate* isolate, 9623 int size, 9624 AllocationSpace space) { 9625 // Allocate a block of memory in the given space (filled with a filler). 9626 // Use as fallback for allocation in generated code when the space 9627 // is full. 9628 SealHandleScope shs(isolate); 9629 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); 9630 RUNTIME_ASSERT(size > 0); 9631 Heap* heap = isolate->heap(); 9632 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize()); 9633 Object* allocation; 9634 { MaybeObject* maybe_allocation; 9635 if (space == NEW_SPACE) { 9636 maybe_allocation = heap->new_space()->AllocateRaw(size); 9637 } else { 9638 ASSERT(space == OLD_POINTER_SPACE || space == OLD_DATA_SPACE); 9639 maybe_allocation = heap->paged_space(space)->AllocateRaw(size); 9640 } 9641 if (maybe_allocation->ToObject(&allocation)) { 9642 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size); 9643 } 9644 return maybe_allocation; 9645 } 9646 } 9647 9648 9649 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { 9650 SealHandleScope shs(isolate); 9651 ASSERT(args.length() == 1); 9652 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0); 9653 return Allocate(isolate, size_smi->value(), NEW_SPACE); 9654 } 9655 9656 9657 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInOldPointerSpace) { 9658 SealHandleScope shs(isolate); 9659 ASSERT(args.length() == 1); 9660 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0); 9661 return Allocate(isolate, size_smi->value(), OLD_POINTER_SPACE); 9662 } 9663 9664 9665 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInOldDataSpace) { 9666 SealHandleScope shs(isolate); 9667 ASSERT(args.length() == 1); 9668 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0); 9669 return Allocate(isolate, size_smi->value(), OLD_DATA_SPACE); 9670 } 9671 9672 9673 // Push an object unto an array of objects if it is not already in the 9674 // array. Returns true if the element was pushed on the stack and 9675 // false otherwise. 9676 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { 9677 SealHandleScope shs(isolate); 9678 ASSERT(args.length() == 2); 9679 CONVERT_ARG_CHECKED(JSArray, array, 0); 9680 CONVERT_ARG_CHECKED(JSReceiver, element, 1); 9681 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements()); 9682 int length = Smi::cast(array->length())->value(); 9683 FixedArray* elements = FixedArray::cast(array->elements()); 9684 for (int i = 0; i < length; i++) { 9685 if (elements->get(i) == element) return isolate->heap()->false_value(); 9686 } 9687 Object* obj; 9688 // Strict not needed. Used for cycle detection in Array join implementation. 9689 { MaybeObject* maybe_obj = 9690 array->SetFastElement(length, element, kNonStrictMode, true); 9691 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 9692 } 9693 return isolate->heap()->true_value(); 9694 } 9695 9696 9697 /** 9698 * A simple visitor visits every element of Array's. 9699 * The backend storage can be a fixed array for fast elements case, 9700 * or a dictionary for sparse array. Since Dictionary is a subtype 9701 * of FixedArray, the class can be used by both fast and slow cases. 9702 * The second parameter of the constructor, fast_elements, specifies 9703 * whether the storage is a FixedArray or Dictionary. 9704 * 9705 * An index limit is used to deal with the situation that a result array 9706 * length overflows 32-bit non-negative integer. 9707 */ 9708 class ArrayConcatVisitor { 9709 public: 9710 ArrayConcatVisitor(Isolate* isolate, 9711 Handle<FixedArray> storage, 9712 bool fast_elements) : 9713 isolate_(isolate), 9714 storage_(Handle<FixedArray>::cast( 9715 isolate->global_handles()->Create(*storage))), 9716 index_offset_(0u), 9717 fast_elements_(fast_elements), 9718 exceeds_array_limit_(false) { } 9719 9720 ~ArrayConcatVisitor() { 9721 clear_storage(); 9722 } 9723 9724 void visit(uint32_t i, Handle<Object> elm) { 9725 if (i > JSObject::kMaxElementCount - index_offset_) { 9726 exceeds_array_limit_ = true; 9727 return; 9728 } 9729 uint32_t index = index_offset_ + i; 9730 9731 if (fast_elements_) { 9732 if (index < static_cast<uint32_t>(storage_->length())) { 9733 storage_->set(index, *elm); 9734 return; 9735 } 9736 // Our initial estimate of length was foiled, possibly by 9737 // getters on the arrays increasing the length of later arrays 9738 // during iteration. 9739 // This shouldn't happen in anything but pathological cases. 9740 SetDictionaryMode(index); 9741 // Fall-through to dictionary mode. 9742 } 9743 ASSERT(!fast_elements_); 9744 Handle<SeededNumberDictionary> dict( 9745 SeededNumberDictionary::cast(*storage_)); 9746 Handle<SeededNumberDictionary> result = 9747 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); 9748 if (!result.is_identical_to(dict)) { 9749 // Dictionary needed to grow. 9750 clear_storage(); 9751 set_storage(*result); 9752 } 9753 } 9754 9755 void increase_index_offset(uint32_t delta) { 9756 if (JSObject::kMaxElementCount - index_offset_ < delta) { 9757 index_offset_ = JSObject::kMaxElementCount; 9758 } else { 9759 index_offset_ += delta; 9760 } 9761 } 9762 9763 bool exceeds_array_limit() { 9764 return exceeds_array_limit_; 9765 } 9766 9767 Handle<JSArray> ToArray() { 9768 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 9769 Handle<Object> length = 9770 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 9771 Handle<Map> map; 9772 if (fast_elements_) { 9773 map = isolate_->factory()->GetElementsTransitionMap(array, 9774 FAST_HOLEY_ELEMENTS); 9775 } else { 9776 map = isolate_->factory()->GetElementsTransitionMap(array, 9777 DICTIONARY_ELEMENTS); 9778 } 9779 array->set_map(*map); 9780 array->set_length(*length); 9781 array->set_elements(*storage_); 9782 return array; 9783 } 9784 9785 private: 9786 // Convert storage to dictionary mode. 9787 void SetDictionaryMode(uint32_t index) { 9788 ASSERT(fast_elements_); 9789 Handle<FixedArray> current_storage(*storage_); 9790 Handle<SeededNumberDictionary> slow_storage( 9791 isolate_->factory()->NewSeededNumberDictionary( 9792 current_storage->length())); 9793 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 9794 for (uint32_t i = 0; i < current_length; i++) { 9795 HandleScope loop_scope(isolate_); 9796 Handle<Object> element(current_storage->get(i), isolate_); 9797 if (!element->IsTheHole()) { 9798 Handle<SeededNumberDictionary> new_storage = 9799 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); 9800 if (!new_storage.is_identical_to(slow_storage)) { 9801 slow_storage = loop_scope.CloseAndEscape(new_storage); 9802 } 9803 } 9804 } 9805 clear_storage(); 9806 set_storage(*slow_storage); 9807 fast_elements_ = false; 9808 } 9809 9810 inline void clear_storage() { 9811 isolate_->global_handles()->Destroy( 9812 Handle<Object>::cast(storage_).location()); 9813 } 9814 9815 inline void set_storage(FixedArray* storage) { 9816 storage_ = Handle<FixedArray>::cast( 9817 isolate_->global_handles()->Create(storage)); 9818 } 9819 9820 Isolate* isolate_; 9821 Handle<FixedArray> storage_; // Always a global handle. 9822 // Index after last seen index. Always less than or equal to 9823 // JSObject::kMaxElementCount. 9824 uint32_t index_offset_; 9825 bool fast_elements_ : 1; 9826 bool exceeds_array_limit_ : 1; 9827 }; 9828 9829 9830 static uint32_t EstimateElementCount(Handle<JSArray> array) { 9831 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 9832 int element_count = 0; 9833 switch (array->GetElementsKind()) { 9834 case FAST_SMI_ELEMENTS: 9835 case FAST_HOLEY_SMI_ELEMENTS: 9836 case FAST_ELEMENTS: 9837 case FAST_HOLEY_ELEMENTS: { 9838 // Fast elements can't have lengths that are not representable by 9839 // a 32-bit signed integer. 9840 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); 9841 int fast_length = static_cast<int>(length); 9842 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 9843 for (int i = 0; i < fast_length; i++) { 9844 if (!elements->get(i)->IsTheHole()) element_count++; 9845 } 9846 break; 9847 } 9848 case FAST_DOUBLE_ELEMENTS: 9849 case FAST_HOLEY_DOUBLE_ELEMENTS: { 9850 // Fast elements can't have lengths that are not representable by 9851 // a 32-bit signed integer. 9852 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); 9853 int fast_length = static_cast<int>(length); 9854 if (array->elements()->IsFixedArray()) { 9855 ASSERT(FixedArray::cast(array->elements())->length() == 0); 9856 break; 9857 } 9858 Handle<FixedDoubleArray> elements( 9859 FixedDoubleArray::cast(array->elements())); 9860 for (int i = 0; i < fast_length; i++) { 9861 if (!elements->is_the_hole(i)) element_count++; 9862 } 9863 break; 9864 } 9865 case DICTIONARY_ELEMENTS: { 9866 Handle<SeededNumberDictionary> dictionary( 9867 SeededNumberDictionary::cast(array->elements())); 9868 int capacity = dictionary->Capacity(); 9869 for (int i = 0; i < capacity; i++) { 9870 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate()); 9871 if (dictionary->IsKey(*key)) { 9872 element_count++; 9873 } 9874 } 9875 break; 9876 } 9877 case NON_STRICT_ARGUMENTS_ELEMENTS: 9878 case EXTERNAL_BYTE_ELEMENTS: 9879 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 9880 case EXTERNAL_SHORT_ELEMENTS: 9881 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 9882 case EXTERNAL_INT_ELEMENTS: 9883 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 9884 case EXTERNAL_FLOAT_ELEMENTS: 9885 case EXTERNAL_DOUBLE_ELEMENTS: 9886 case EXTERNAL_PIXEL_ELEMENTS: 9887 // External arrays are always dense. 9888 return length; 9889 } 9890 // As an estimate, we assume that the prototype doesn't contain any 9891 // inherited elements. 9892 return element_count; 9893 } 9894 9895 9896 9897 template<class ExternalArrayClass, class ElementType> 9898 static void IterateExternalArrayElements(Isolate* isolate, 9899 Handle<JSObject> receiver, 9900 bool elements_are_ints, 9901 bool elements_are_guaranteed_smis, 9902 ArrayConcatVisitor* visitor) { 9903 Handle<ExternalArrayClass> array( 9904 ExternalArrayClass::cast(receiver->elements())); 9905 uint32_t len = static_cast<uint32_t>(array->length()); 9906 9907 ASSERT(visitor != NULL); 9908 if (elements_are_ints) { 9909 if (elements_are_guaranteed_smis) { 9910 for (uint32_t j = 0; j < len; j++) { 9911 HandleScope loop_scope(isolate); 9912 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), 9913 isolate); 9914 visitor->visit(j, e); 9915 } 9916 } else { 9917 for (uint32_t j = 0; j < len; j++) { 9918 HandleScope loop_scope(isolate); 9919 int64_t val = static_cast<int64_t>(array->get_scalar(j)); 9920 if (Smi::IsValid(static_cast<intptr_t>(val))) { 9921 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); 9922 visitor->visit(j, e); 9923 } else { 9924 Handle<Object> e = 9925 isolate->factory()->NewNumber(static_cast<ElementType>(val)); 9926 visitor->visit(j, e); 9927 } 9928 } 9929 } 9930 } else { 9931 for (uint32_t j = 0; j < len; j++) { 9932 HandleScope loop_scope(isolate); 9933 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); 9934 visitor->visit(j, e); 9935 } 9936 } 9937 } 9938 9939 9940 // Used for sorting indices in a List<uint32_t>. 9941 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 9942 uint32_t a = *ap; 9943 uint32_t b = *bp; 9944 return (a == b) ? 0 : (a < b) ? -1 : 1; 9945 } 9946 9947 9948 static void CollectElementIndices(Handle<JSObject> object, 9949 uint32_t range, 9950 List<uint32_t>* indices) { 9951 Isolate* isolate = object->GetIsolate(); 9952 ElementsKind kind = object->GetElementsKind(); 9953 switch (kind) { 9954 case FAST_SMI_ELEMENTS: 9955 case FAST_ELEMENTS: 9956 case FAST_HOLEY_SMI_ELEMENTS: 9957 case FAST_HOLEY_ELEMENTS: { 9958 Handle<FixedArray> elements(FixedArray::cast(object->elements())); 9959 uint32_t length = static_cast<uint32_t>(elements->length()); 9960 if (range < length) length = range; 9961 for (uint32_t i = 0; i < length; i++) { 9962 if (!elements->get(i)->IsTheHole()) { 9963 indices->Add(i); 9964 } 9965 } 9966 break; 9967 } 9968 case FAST_HOLEY_DOUBLE_ELEMENTS: 9969 case FAST_DOUBLE_ELEMENTS: { 9970 // TODO(1810): Decide if it's worthwhile to implement this. 9971 UNREACHABLE(); 9972 break; 9973 } 9974 case DICTIONARY_ELEMENTS: { 9975 Handle<SeededNumberDictionary> dict( 9976 SeededNumberDictionary::cast(object->elements())); 9977 uint32_t capacity = dict->Capacity(); 9978 for (uint32_t j = 0; j < capacity; j++) { 9979 HandleScope loop_scope(isolate); 9980 Handle<Object> k(dict->KeyAt(j), isolate); 9981 if (dict->IsKey(*k)) { 9982 ASSERT(k->IsNumber()); 9983 uint32_t index = static_cast<uint32_t>(k->Number()); 9984 if (index < range) { 9985 indices->Add(index); 9986 } 9987 } 9988 } 9989 break; 9990 } 9991 default: { 9992 int dense_elements_length; 9993 switch (kind) { 9994 case EXTERNAL_PIXEL_ELEMENTS: { 9995 dense_elements_length = 9996 ExternalPixelArray::cast(object->elements())->length(); 9997 break; 9998 } 9999 case EXTERNAL_BYTE_ELEMENTS: { 10000 dense_elements_length = 10001 ExternalByteArray::cast(object->elements())->length(); 10002 break; 10003 } 10004 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 10005 dense_elements_length = 10006 ExternalUnsignedByteArray::cast(object->elements())->length(); 10007 break; 10008 } 10009 case EXTERNAL_SHORT_ELEMENTS: { 10010 dense_elements_length = 10011 ExternalShortArray::cast(object->elements())->length(); 10012 break; 10013 } 10014 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 10015 dense_elements_length = 10016 ExternalUnsignedShortArray::cast(object->elements())->length(); 10017 break; 10018 } 10019 case EXTERNAL_INT_ELEMENTS: { 10020 dense_elements_length = 10021 ExternalIntArray::cast(object->elements())->length(); 10022 break; 10023 } 10024 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 10025 dense_elements_length = 10026 ExternalUnsignedIntArray::cast(object->elements())->length(); 10027 break; 10028 } 10029 case EXTERNAL_FLOAT_ELEMENTS: { 10030 dense_elements_length = 10031 ExternalFloatArray::cast(object->elements())->length(); 10032 break; 10033 } 10034 case EXTERNAL_DOUBLE_ELEMENTS: { 10035 dense_elements_length = 10036 ExternalDoubleArray::cast(object->elements())->length(); 10037 break; 10038 } 10039 default: 10040 UNREACHABLE(); 10041 dense_elements_length = 0; 10042 break; 10043 } 10044 uint32_t length = static_cast<uint32_t>(dense_elements_length); 10045 if (range <= length) { 10046 length = range; 10047 // We will add all indices, so we might as well clear it first 10048 // and avoid duplicates. 10049 indices->Clear(); 10050 } 10051 for (uint32_t i = 0; i < length; i++) { 10052 indices->Add(i); 10053 } 10054 if (length == range) return; // All indices accounted for already. 10055 break; 10056 } 10057 } 10058 10059 Handle<Object> prototype(object->GetPrototype(), isolate); 10060 if (prototype->IsJSObject()) { 10061 // The prototype will usually have no inherited element indices, 10062 // but we have to check. 10063 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); 10064 } 10065 } 10066 10067 10068 /** 10069 * A helper function that visits elements of a JSArray in numerical 10070 * order. 10071 * 10072 * The visitor argument called for each existing element in the array 10073 * with the element index and the element's value. 10074 * Afterwards it increments the base-index of the visitor by the array 10075 * length. 10076 * Returns false if any access threw an exception, otherwise true. 10077 */ 10078 static bool IterateElements(Isolate* isolate, 10079 Handle<JSArray> receiver, 10080 ArrayConcatVisitor* visitor) { 10081 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); 10082 switch (receiver->GetElementsKind()) { 10083 case FAST_SMI_ELEMENTS: 10084 case FAST_ELEMENTS: 10085 case FAST_HOLEY_SMI_ELEMENTS: 10086 case FAST_HOLEY_ELEMENTS: { 10087 // Run through the elements FixedArray and use HasElement and GetElement 10088 // to check the prototype for missing elements. 10089 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 10090 int fast_length = static_cast<int>(length); 10091 ASSERT(fast_length <= elements->length()); 10092 for (int j = 0; j < fast_length; j++) { 10093 HandleScope loop_scope(isolate); 10094 Handle<Object> element_value(elements->get(j), isolate); 10095 if (!element_value->IsTheHole()) { 10096 visitor->visit(j, element_value); 10097 } else if (receiver->HasElement(j)) { 10098 // Call GetElement on receiver, not its prototype, or getters won't 10099 // have the correct receiver. 10100 element_value = Object::GetElement(receiver, j); 10101 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); 10102 visitor->visit(j, element_value); 10103 } 10104 } 10105 break; 10106 } 10107 case FAST_HOLEY_DOUBLE_ELEMENTS: 10108 case FAST_DOUBLE_ELEMENTS: { 10109 // Run through the elements FixedArray and use HasElement and GetElement 10110 // to check the prototype for missing elements. 10111 Handle<FixedDoubleArray> elements( 10112 FixedDoubleArray::cast(receiver->elements())); 10113 int fast_length = static_cast<int>(length); 10114 ASSERT(fast_length <= elements->length()); 10115 for (int j = 0; j < fast_length; j++) { 10116 HandleScope loop_scope(isolate); 10117 if (!elements->is_the_hole(j)) { 10118 double double_value = elements->get_scalar(j); 10119 Handle<Object> element_value = 10120 isolate->factory()->NewNumber(double_value); 10121 visitor->visit(j, element_value); 10122 } else if (receiver->HasElement(j)) { 10123 // Call GetElement on receiver, not its prototype, or getters won't 10124 // have the correct receiver. 10125 Handle<Object> element_value = Object::GetElement(receiver, j); 10126 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); 10127 visitor->visit(j, element_value); 10128 } 10129 } 10130 break; 10131 } 10132 case DICTIONARY_ELEMENTS: { 10133 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); 10134 List<uint32_t> indices(dict->Capacity() / 2); 10135 // Collect all indices in the object and the prototypes less 10136 // than length. This might introduce duplicates in the indices list. 10137 CollectElementIndices(receiver, length, &indices); 10138 indices.Sort(&compareUInt32); 10139 int j = 0; 10140 int n = indices.length(); 10141 while (j < n) { 10142 HandleScope loop_scope(isolate); 10143 uint32_t index = indices[j]; 10144 Handle<Object> element = Object::GetElement(receiver, index); 10145 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false); 10146 visitor->visit(index, element); 10147 // Skip to next different index (i.e., omit duplicates). 10148 do { 10149 j++; 10150 } while (j < n && indices[j] == index); 10151 } 10152 break; 10153 } 10154 case EXTERNAL_PIXEL_ELEMENTS: { 10155 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast( 10156 receiver->elements())); 10157 for (uint32_t j = 0; j < length; j++) { 10158 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); 10159 visitor->visit(j, e); 10160 } 10161 break; 10162 } 10163 case EXTERNAL_BYTE_ELEMENTS: { 10164 IterateExternalArrayElements<ExternalByteArray, int8_t>( 10165 isolate, receiver, true, true, visitor); 10166 break; 10167 } 10168 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 10169 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( 10170 isolate, receiver, true, true, visitor); 10171 break; 10172 } 10173 case EXTERNAL_SHORT_ELEMENTS: { 10174 IterateExternalArrayElements<ExternalShortArray, int16_t>( 10175 isolate, receiver, true, true, visitor); 10176 break; 10177 } 10178 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 10179 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( 10180 isolate, receiver, true, true, visitor); 10181 break; 10182 } 10183 case EXTERNAL_INT_ELEMENTS: { 10184 IterateExternalArrayElements<ExternalIntArray, int32_t>( 10185 isolate, receiver, true, false, visitor); 10186 break; 10187 } 10188 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 10189 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( 10190 isolate, receiver, true, false, visitor); 10191 break; 10192 } 10193 case EXTERNAL_FLOAT_ELEMENTS: { 10194 IterateExternalArrayElements<ExternalFloatArray, float>( 10195 isolate, receiver, false, false, visitor); 10196 break; 10197 } 10198 case EXTERNAL_DOUBLE_ELEMENTS: { 10199 IterateExternalArrayElements<ExternalDoubleArray, double>( 10200 isolate, receiver, false, false, visitor); 10201 break; 10202 } 10203 default: 10204 UNREACHABLE(); 10205 break; 10206 } 10207 visitor->increase_index_offset(length); 10208 return true; 10209 } 10210 10211 10212 /** 10213 * Array::concat implementation. 10214 * See ECMAScript 262, 15.4.4.4. 10215 * TODO(581): Fix non-compliance for very large concatenations and update to 10216 * following the ECMAScript 5 specification. 10217 */ 10218 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { 10219 HandleScope handle_scope(isolate); 10220 ASSERT(args.length() == 1); 10221 10222 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); 10223 int argument_count = static_cast<int>(arguments->length()->Number()); 10224 RUNTIME_ASSERT(arguments->HasFastObjectElements()); 10225 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); 10226 10227 // Pass 1: estimate the length and number of elements of the result. 10228 // The actual length can be larger if any of the arguments have getters 10229 // that mutate other arguments (but will otherwise be precise). 10230 // The number of elements is precise if there are no inherited elements. 10231 10232 ElementsKind kind = FAST_SMI_ELEMENTS; 10233 10234 uint32_t estimate_result_length = 0; 10235 uint32_t estimate_nof_elements = 0; 10236 for (int i = 0; i < argument_count; i++) { 10237 HandleScope loop_scope(isolate); 10238 Handle<Object> obj(elements->get(i), isolate); 10239 uint32_t length_estimate; 10240 uint32_t element_estimate; 10241 if (obj->IsJSArray()) { 10242 Handle<JSArray> array(Handle<JSArray>::cast(obj)); 10243 length_estimate = static_cast<uint32_t>(array->length()->Number()); 10244 if (length_estimate != 0) { 10245 ElementsKind array_kind = 10246 GetPackedElementsKind(array->map()->elements_kind()); 10247 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { 10248 kind = array_kind; 10249 } 10250 } 10251 element_estimate = EstimateElementCount(array); 10252 } else { 10253 if (obj->IsHeapObject()) { 10254 if (obj->IsNumber()) { 10255 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { 10256 kind = FAST_DOUBLE_ELEMENTS; 10257 } 10258 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { 10259 kind = FAST_ELEMENTS; 10260 } 10261 } 10262 length_estimate = 1; 10263 element_estimate = 1; 10264 } 10265 // Avoid overflows by capping at kMaxElementCount. 10266 if (JSObject::kMaxElementCount - estimate_result_length < 10267 length_estimate) { 10268 estimate_result_length = JSObject::kMaxElementCount; 10269 } else { 10270 estimate_result_length += length_estimate; 10271 } 10272 if (JSObject::kMaxElementCount - estimate_nof_elements < 10273 element_estimate) { 10274 estimate_nof_elements = JSObject::kMaxElementCount; 10275 } else { 10276 estimate_nof_elements += element_estimate; 10277 } 10278 } 10279 10280 // If estimated number of elements is more than half of length, a 10281 // fixed array (fast case) is more time and space-efficient than a 10282 // dictionary. 10283 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; 10284 10285 Handle<FixedArray> storage; 10286 if (fast_case) { 10287 if (kind == FAST_DOUBLE_ELEMENTS) { 10288 Handle<FixedDoubleArray> double_storage = 10289 isolate->factory()->NewFixedDoubleArray(estimate_result_length); 10290 int j = 0; 10291 bool failure = false; 10292 for (int i = 0; i < argument_count; i++) { 10293 Handle<Object> obj(elements->get(i), isolate); 10294 if (obj->IsSmi()) { 10295 double_storage->set(j, Smi::cast(*obj)->value()); 10296 j++; 10297 } else if (obj->IsNumber()) { 10298 double_storage->set(j, obj->Number()); 10299 j++; 10300 } else { 10301 JSArray* array = JSArray::cast(*obj); 10302 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 10303 switch (array->map()->elements_kind()) { 10304 case FAST_HOLEY_DOUBLE_ELEMENTS: 10305 case FAST_DOUBLE_ELEMENTS: { 10306 // Empty fixed array indicates that there are no elements. 10307 if (array->elements()->IsFixedArray()) break; 10308 FixedDoubleArray* elements = 10309 FixedDoubleArray::cast(array->elements()); 10310 for (uint32_t i = 0; i < length; i++) { 10311 if (elements->is_the_hole(i)) { 10312 failure = true; 10313 break; 10314 } 10315 double double_value = elements->get_scalar(i); 10316 double_storage->set(j, double_value); 10317 j++; 10318 } 10319 break; 10320 } 10321 case FAST_HOLEY_SMI_ELEMENTS: 10322 case FAST_SMI_ELEMENTS: { 10323 FixedArray* elements( 10324 FixedArray::cast(array->elements())); 10325 for (uint32_t i = 0; i < length; i++) { 10326 Object* element = elements->get(i); 10327 if (element->IsTheHole()) { 10328 failure = true; 10329 break; 10330 } 10331 int32_t int_value = Smi::cast(element)->value(); 10332 double_storage->set(j, int_value); 10333 j++; 10334 } 10335 break; 10336 } 10337 case FAST_HOLEY_ELEMENTS: 10338 ASSERT_EQ(0, length); 10339 break; 10340 default: 10341 UNREACHABLE(); 10342 } 10343 } 10344 if (failure) break; 10345 } 10346 Handle<JSArray> array = isolate->factory()->NewJSArray(0); 10347 Smi* length = Smi::FromInt(j); 10348 Handle<Map> map; 10349 map = isolate->factory()->GetElementsTransitionMap(array, kind); 10350 array->set_map(*map); 10351 array->set_length(length); 10352 array->set_elements(*double_storage); 10353 return *array; 10354 } 10355 // The backing storage array must have non-existing elements to preserve 10356 // holes across concat operations. 10357 storage = isolate->factory()->NewFixedArrayWithHoles( 10358 estimate_result_length); 10359 } else { 10360 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 10361 uint32_t at_least_space_for = estimate_nof_elements + 10362 (estimate_nof_elements >> 2); 10363 storage = Handle<FixedArray>::cast( 10364 isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); 10365 } 10366 10367 ArrayConcatVisitor visitor(isolate, storage, fast_case); 10368 10369 for (int i = 0; i < argument_count; i++) { 10370 Handle<Object> obj(elements->get(i), isolate); 10371 if (obj->IsJSArray()) { 10372 Handle<JSArray> array = Handle<JSArray>::cast(obj); 10373 if (!IterateElements(isolate, array, &visitor)) { 10374 return Failure::Exception(); 10375 } 10376 } else { 10377 visitor.visit(0, obj); 10378 visitor.increase_index_offset(1); 10379 } 10380 } 10381 10382 if (visitor.exceeds_array_limit()) { 10383 return isolate->Throw( 10384 *isolate->factory()->NewRangeError("invalid_array_length", 10385 HandleVector<Object>(NULL, 0))); 10386 } 10387 return *visitor.ToArray(); 10388 } 10389 10390 10391 // This will not allocate (flatten the string), but it may run 10392 // very slowly for very deeply nested ConsStrings. For debugging use only. 10393 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { 10394 SealHandleScope shs(isolate); 10395 ASSERT(args.length() == 1); 10396 10397 CONVERT_ARG_CHECKED(String, string, 0); 10398 ConsStringIteratorOp op; 10399 StringCharacterStream stream(string, &op); 10400 while (stream.HasMore()) { 10401 uint16_t character = stream.GetNext(); 10402 PrintF("%c", character); 10403 } 10404 return string; 10405 } 10406 10407 10408 // Moves all own elements of an object, that are below a limit, to positions 10409 // starting at zero. All undefined values are placed after non-undefined values, 10410 // and are followed by non-existing element. Does not change the length 10411 // property. 10412 // Returns the number of non-undefined elements collected. 10413 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { 10414 SealHandleScope shs(isolate); 10415 ASSERT(args.length() == 2); 10416 CONVERT_ARG_CHECKED(JSObject, object, 0); 10417 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 10418 return object->PrepareElementsForSort(limit); 10419 } 10420 10421 10422 // Move contents of argument 0 (an array) to argument 1 (an array) 10423 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { 10424 SealHandleScope shs(isolate); 10425 ASSERT(args.length() == 2); 10426 CONVERT_ARG_CHECKED(JSArray, from, 0); 10427 CONVERT_ARG_CHECKED(JSArray, to, 1); 10428 from->ValidateElements(); 10429 to->ValidateElements(); 10430 FixedArrayBase* new_elements = from->elements(); 10431 ElementsKind from_kind = from->GetElementsKind(); 10432 MaybeObject* maybe_new_map; 10433 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind); 10434 Object* new_map; 10435 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 10436 to->set_map_and_elements(Map::cast(new_map), new_elements); 10437 to->set_length(from->length()); 10438 Object* obj; 10439 { MaybeObject* maybe_obj = from->ResetElements(); 10440 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 10441 } 10442 from->set_length(Smi::FromInt(0)); 10443 to->ValidateElements(); 10444 return to; 10445 } 10446 10447 10448 // How many elements does this object/array have? 10449 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { 10450 SealHandleScope shs(isolate); 10451 ASSERT(args.length() == 1); 10452 CONVERT_ARG_CHECKED(JSObject, object, 0); 10453 HeapObject* elements = object->elements(); 10454 if (elements->IsDictionary()) { 10455 int result = SeededNumberDictionary::cast(elements)->NumberOfElements(); 10456 return Smi::FromInt(result); 10457 } else if (object->IsJSArray()) { 10458 return JSArray::cast(object)->length(); 10459 } else { 10460 return Smi::FromInt(FixedArray::cast(elements)->length()); 10461 } 10462 } 10463 10464 10465 // Returns an array that tells you where in the [0, length) interval an array 10466 // might have elements. Can either return an array of keys (positive integers 10467 // or undefined) or a number representing the positive length of an interval 10468 // starting at index 0. 10469 // Intervals can span over some keys that are not in the object. 10470 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { 10471 HandleScope scope(isolate); 10472 ASSERT(args.length() == 2); 10473 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); 10474 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 10475 if (array->elements()->IsDictionary()) { 10476 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); 10477 for (Handle<Object> p = array; 10478 !p->IsNull(); 10479 p = Handle<Object>(p->GetPrototype(isolate), isolate)) { 10480 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) { 10481 // Bail out if we find a proxy or interceptor, likely not worth 10482 // collecting keys in that case. 10483 return *isolate->factory()->NewNumberFromUint(length); 10484 } 10485 Handle<JSObject> current = Handle<JSObject>::cast(p); 10486 Handle<FixedArray> current_keys = 10487 isolate->factory()->NewFixedArray( 10488 current->NumberOfLocalElements(NONE)); 10489 current->GetLocalElementKeys(*current_keys, NONE); 10490 keys = UnionOfKeys(keys, current_keys); 10491 } 10492 // Erase any keys >= length. 10493 // TODO(adamk): Remove this step when the contract of %GetArrayKeys 10494 // is changed to let this happen on the JS side. 10495 for (int i = 0; i < keys->length(); i++) { 10496 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); 10497 } 10498 return *isolate->factory()->NewJSArrayWithElements(keys); 10499 } else { 10500 ASSERT(array->HasFastSmiOrObjectElements() || 10501 array->HasFastDoubleElements()); 10502 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); 10503 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); 10504 } 10505 } 10506 10507 10508 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { 10509 SealHandleScope shs(isolate); 10510 ASSERT(args.length() == 3); 10511 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0); 10512 CONVERT_ARG_CHECKED(Name, name, 1); 10513 CONVERT_SMI_ARG_CHECKED(flag, 2); 10514 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; 10515 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); 10516 return JSObject::cast(receiver)->LookupAccessor(name, component); 10517 } 10518 10519 10520 #ifdef ENABLE_DEBUGGER_SUPPORT 10521 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) { 10522 SealHandleScope shs(isolate); 10523 ASSERT(args.length() == 0); 10524 return Execution::DebugBreakHelper(); 10525 } 10526 10527 10528 // Helper functions for wrapping and unwrapping stack frame ids. 10529 static Smi* WrapFrameId(StackFrame::Id id) { 10530 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 10531 return Smi::FromInt(id >> 2); 10532 } 10533 10534 10535 static StackFrame::Id UnwrapFrameId(int wrapped) { 10536 return static_cast<StackFrame::Id>(wrapped << 2); 10537 } 10538 10539 10540 // Adds a JavaScript function as a debug event listener. 10541 // args[0]: debug event listener function to set or null or undefined for 10542 // clearing the event listener function 10543 // args[1]: object supplied during callback 10544 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) { 10545 SealHandleScope shs(isolate); 10546 ASSERT(args.length() == 2); 10547 RUNTIME_ASSERT(args[0]->IsJSFunction() || 10548 args[0]->IsUndefined() || 10549 args[0]->IsNull()); 10550 Handle<Object> callback = args.at<Object>(0); 10551 Handle<Object> data = args.at<Object>(1); 10552 isolate->debugger()->SetEventListener(callback, data); 10553 10554 return isolate->heap()->undefined_value(); 10555 } 10556 10557 10558 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) { 10559 SealHandleScope shs(isolate); 10560 ASSERT(args.length() == 0); 10561 isolate->stack_guard()->DebugBreak(); 10562 return isolate->heap()->undefined_value(); 10563 } 10564 10565 10566 static MaybeObject* DebugLookupResultValue(Heap* heap, 10567 Object* receiver, 10568 Name* name, 10569 LookupResult* result, 10570 bool* caught_exception) { 10571 Object* value; 10572 switch (result->type()) { 10573 case NORMAL: 10574 value = result->holder()->GetNormalizedProperty(result); 10575 if (value->IsTheHole()) { 10576 return heap->undefined_value(); 10577 } 10578 return value; 10579 case FIELD: { 10580 Object* value; 10581 MaybeObject* maybe_value = 10582 JSObject::cast(result->holder())->FastPropertyAt( 10583 result->representation(), 10584 result->GetFieldIndex().field_index()); 10585 if (!maybe_value->To(&value)) return maybe_value; 10586 if (value->IsTheHole()) { 10587 return heap->undefined_value(); 10588 } 10589 return value; 10590 } 10591 case CONSTANT: 10592 return result->GetConstant(); 10593 case CALLBACKS: { 10594 Object* structure = result->GetCallbackObject(); 10595 if (structure->IsForeign() || structure->IsAccessorInfo()) { 10596 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback( 10597 receiver, structure, name); 10598 if (!maybe_value->ToObject(&value)) { 10599 if (maybe_value->IsRetryAfterGC()) return maybe_value; 10600 ASSERT(maybe_value->IsException()); 10601 maybe_value = heap->isolate()->pending_exception(); 10602 heap->isolate()->clear_pending_exception(); 10603 if (caught_exception != NULL) { 10604 *caught_exception = true; 10605 } 10606 return maybe_value; 10607 } 10608 return value; 10609 } else { 10610 return heap->undefined_value(); 10611 } 10612 } 10613 case INTERCEPTOR: 10614 case TRANSITION: 10615 return heap->undefined_value(); 10616 case HANDLER: 10617 case NONEXISTENT: 10618 UNREACHABLE(); 10619 return heap->undefined_value(); 10620 } 10621 UNREACHABLE(); // keep the compiler happy 10622 return heap->undefined_value(); 10623 } 10624 10625 10626 // Get debugger related details for an object property. 10627 // args[0]: object holding property 10628 // args[1]: name of the property 10629 // 10630 // The array returned contains the following information: 10631 // 0: Property value 10632 // 1: Property details 10633 // 2: Property value is exception 10634 // 3: Getter function if defined 10635 // 4: Setter function if defined 10636 // Items 2-4 are only filled if the property has either a getter or a setter 10637 // defined through __defineGetter__ and/or __defineSetter__. 10638 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { 10639 HandleScope scope(isolate); 10640 10641 ASSERT(args.length() == 2); 10642 10643 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10644 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10645 10646 // Make sure to set the current context to the context before the debugger was 10647 // entered (if the debugger is entered). The reason for switching context here 10648 // is that for some property lookups (accessors and interceptors) callbacks 10649 // into the embedding application can occour, and the embedding application 10650 // could have the assumption that its own native context is the current 10651 // context and not some internal debugger context. 10652 SaveContext save(isolate); 10653 if (isolate->debug()->InDebugger()) { 10654 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 10655 } 10656 10657 // Skip the global proxy as it has no properties and always delegates to the 10658 // real global object. 10659 if (obj->IsJSGlobalProxy()) { 10660 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 10661 } 10662 10663 10664 // Check if the name is trivially convertible to an index and get the element 10665 // if so. 10666 uint32_t index; 10667 if (name->AsArrayIndex(&index)) { 10668 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 10669 Object* element_or_char; 10670 { MaybeObject* maybe_element_or_char = 10671 Runtime::GetElementOrCharAt(isolate, obj, index); 10672 if (!maybe_element_or_char->ToObject(&element_or_char)) { 10673 return maybe_element_or_char; 10674 } 10675 } 10676 details->set(0, element_or_char); 10677 details->set( 10678 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); 10679 return *isolate->factory()->NewJSArrayWithElements(details); 10680 } 10681 10682 // Find the number of objects making up this. 10683 int length = LocalPrototypeChainLength(*obj); 10684 10685 // Try local lookup on each of the objects. 10686 Handle<JSObject> jsproto = obj; 10687 for (int i = 0; i < length; i++) { 10688 LookupResult result(isolate); 10689 jsproto->LocalLookup(*name, &result); 10690 if (result.IsFound()) { 10691 // LookupResult is not GC safe as it holds raw object pointers. 10692 // GC can happen later in this code so put the required fields into 10693 // local variables using handles when required for later use. 10694 Handle<Object> result_callback_obj; 10695 if (result.IsPropertyCallbacks()) { 10696 result_callback_obj = Handle<Object>(result.GetCallbackObject(), 10697 isolate); 10698 } 10699 Smi* property_details = result.GetPropertyDetails().AsSmi(); 10700 // DebugLookupResultValue can cause GC so details from LookupResult needs 10701 // to be copied to handles before this. 10702 bool caught_exception = false; 10703 Object* raw_value; 10704 { MaybeObject* maybe_raw_value = 10705 DebugLookupResultValue(isolate->heap(), *obj, *name, 10706 &result, &caught_exception); 10707 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value; 10708 } 10709 Handle<Object> value(raw_value, isolate); 10710 10711 // If the callback object is a fixed array then it contains JavaScript 10712 // getter and/or setter. 10713 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() && 10714 result_callback_obj->IsAccessorPair(); 10715 Handle<FixedArray> details = 10716 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2); 10717 details->set(0, *value); 10718 details->set(1, property_details); 10719 if (hasJavaScriptAccessors) { 10720 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj); 10721 details->set(2, isolate->heap()->ToBoolean(caught_exception)); 10722 details->set(3, accessors->GetComponent(ACCESSOR_GETTER)); 10723 details->set(4, accessors->GetComponent(ACCESSOR_SETTER)); 10724 } 10725 10726 return *isolate->factory()->NewJSArrayWithElements(details); 10727 } 10728 if (i < length - 1) { 10729 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 10730 } 10731 } 10732 10733 return isolate->heap()->undefined_value(); 10734 } 10735 10736 10737 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { 10738 HandleScope scope(isolate); 10739 10740 ASSERT(args.length() == 2); 10741 10742 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10743 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10744 10745 LookupResult result(isolate); 10746 obj->Lookup(*name, &result); 10747 if (result.IsFound()) { 10748 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL); 10749 } 10750 return isolate->heap()->undefined_value(); 10751 } 10752 10753 10754 // Return the property type calculated from the property details. 10755 // args[0]: smi with property details. 10756 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { 10757 SealHandleScope shs(isolate); 10758 ASSERT(args.length() == 1); 10759 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10760 return Smi::FromInt(static_cast<int>(details.type())); 10761 } 10762 10763 10764 // Return the property attribute calculated from the property details. 10765 // args[0]: smi with property details. 10766 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { 10767 SealHandleScope shs(isolate); 10768 ASSERT(args.length() == 1); 10769 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10770 return Smi::FromInt(static_cast<int>(details.attributes())); 10771 } 10772 10773 10774 // Return the property insertion index calculated from the property details. 10775 // args[0]: smi with property details. 10776 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { 10777 SealHandleScope shs(isolate); 10778 ASSERT(args.length() == 1); 10779 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10780 // TODO(verwaest): Depends on the type of details. 10781 return Smi::FromInt(details.dictionary_index()); 10782 } 10783 10784 10785 // Return property value from named interceptor. 10786 // args[0]: object 10787 // args[1]: property name 10788 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { 10789 HandleScope scope(isolate); 10790 ASSERT(args.length() == 2); 10791 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10792 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 10793 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10794 10795 PropertyAttributes attributes; 10796 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes); 10797 } 10798 10799 10800 // Return element value from indexed interceptor. 10801 // args[0]: object 10802 // args[1]: index 10803 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) { 10804 HandleScope scope(isolate); 10805 ASSERT(args.length() == 2); 10806 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10807 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 10808 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 10809 10810 return obj->GetElementWithInterceptor(*obj, index); 10811 } 10812 10813 10814 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) { 10815 SealHandleScope shs(isolate); 10816 ASSERT(args.length() >= 1); 10817 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 10818 // Check that the break id is valid. 10819 if (isolate->debug()->break_id() == 0 || 10820 break_id != isolate->debug()->break_id()) { 10821 return isolate->Throw( 10822 isolate->heap()->illegal_execution_state_string()); 10823 } 10824 10825 return isolate->heap()->true_value(); 10826 } 10827 10828 10829 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) { 10830 HandleScope scope(isolate); 10831 ASSERT(args.length() == 1); 10832 10833 // Check arguments. 10834 Object* result; 10835 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 10836 RUNTIME_ARGUMENTS(isolate, args)); 10837 if (!maybe_result->ToObject(&result)) return maybe_result; 10838 } 10839 10840 // Count all frames which are relevant to debugging stack trace. 10841 int n = 0; 10842 StackFrame::Id id = isolate->debug()->break_frame_id(); 10843 if (id == StackFrame::NO_ID) { 10844 // If there is no JavaScript stack frame count is 0. 10845 return Smi::FromInt(0); 10846 } 10847 10848 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { 10849 n += it.frame()->GetInlineCount(); 10850 } 10851 return Smi::FromInt(n); 10852 } 10853 10854 10855 class FrameInspector { 10856 public: 10857 FrameInspector(JavaScriptFrame* frame, 10858 int inlined_jsframe_index, 10859 Isolate* isolate) 10860 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { 10861 // Calculate the deoptimized frame. 10862 if (frame->is_optimized()) { 10863 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( 10864 frame, inlined_jsframe_index, isolate); 10865 } 10866 has_adapted_arguments_ = frame_->has_adapted_arguments(); 10867 is_bottommost_ = inlined_jsframe_index == 0; 10868 is_optimized_ = frame_->is_optimized(); 10869 } 10870 10871 ~FrameInspector() { 10872 // Get rid of the calculated deoptimized frame if any. 10873 if (deoptimized_frame_ != NULL) { 10874 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, 10875 isolate_); 10876 } 10877 } 10878 10879 int GetParametersCount() { 10880 return is_optimized_ 10881 ? deoptimized_frame_->parameters_count() 10882 : frame_->ComputeParametersCount(); 10883 } 10884 int expression_count() { return deoptimized_frame_->expression_count(); } 10885 Object* GetFunction() { 10886 return is_optimized_ 10887 ? deoptimized_frame_->GetFunction() 10888 : frame_->function(); 10889 } 10890 Object* GetParameter(int index) { 10891 return is_optimized_ 10892 ? deoptimized_frame_->GetParameter(index) 10893 : frame_->GetParameter(index); 10894 } 10895 Object* GetExpression(int index) { 10896 return is_optimized_ 10897 ? deoptimized_frame_->GetExpression(index) 10898 : frame_->GetExpression(index); 10899 } 10900 int GetSourcePosition() { 10901 return is_optimized_ 10902 ? deoptimized_frame_->GetSourcePosition() 10903 : frame_->LookupCode()->SourcePosition(frame_->pc()); 10904 } 10905 bool IsConstructor() { 10906 return is_optimized_ && !is_bottommost_ 10907 ? deoptimized_frame_->HasConstructStub() 10908 : frame_->IsConstructor(); 10909 } 10910 10911 // To inspect all the provided arguments the frame might need to be 10912 // replaced with the arguments frame. 10913 void SetArgumentsFrame(JavaScriptFrame* frame) { 10914 ASSERT(has_adapted_arguments_); 10915 frame_ = frame; 10916 is_optimized_ = frame_->is_optimized(); 10917 ASSERT(!is_optimized_); 10918 } 10919 10920 private: 10921 JavaScriptFrame* frame_; 10922 DeoptimizedFrameInfo* deoptimized_frame_; 10923 Isolate* isolate_; 10924 bool is_optimized_; 10925 bool is_bottommost_; 10926 bool has_adapted_arguments_; 10927 10928 DISALLOW_COPY_AND_ASSIGN(FrameInspector); 10929 }; 10930 10931 10932 static const int kFrameDetailsFrameIdIndex = 0; 10933 static const int kFrameDetailsReceiverIndex = 1; 10934 static const int kFrameDetailsFunctionIndex = 2; 10935 static const int kFrameDetailsArgumentCountIndex = 3; 10936 static const int kFrameDetailsLocalCountIndex = 4; 10937 static const int kFrameDetailsSourcePositionIndex = 5; 10938 static const int kFrameDetailsConstructCallIndex = 6; 10939 static const int kFrameDetailsAtReturnIndex = 7; 10940 static const int kFrameDetailsFlagsIndex = 8; 10941 static const int kFrameDetailsFirstDynamicIndex = 9; 10942 10943 10944 static SaveContext* FindSavedContextForFrame(Isolate* isolate, 10945 JavaScriptFrame* frame) { 10946 SaveContext* save = isolate->save_context(); 10947 while (save != NULL && !save->IsBelowFrame(frame)) { 10948 save = save->prev(); 10949 } 10950 ASSERT(save != NULL); 10951 return save; 10952 } 10953 10954 10955 // Return an array with frame details 10956 // args[0]: number: break id 10957 // args[1]: number: frame index 10958 // 10959 // The array returned contains the following information: 10960 // 0: Frame id 10961 // 1: Receiver 10962 // 2: Function 10963 // 3: Argument count 10964 // 4: Local count 10965 // 5: Source position 10966 // 6: Constructor call 10967 // 7: Is at return 10968 // 8: Flags 10969 // Arguments name, value 10970 // Locals name, value 10971 // Return value if any 10972 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { 10973 HandleScope scope(isolate); 10974 ASSERT(args.length() == 2); 10975 10976 // Check arguments. 10977 Object* check; 10978 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 10979 RUNTIME_ARGUMENTS(isolate, args)); 10980 if (!maybe_check->ToObject(&check)) return maybe_check; 10981 } 10982 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 10983 Heap* heap = isolate->heap(); 10984 10985 // Find the relevant frame with the requested index. 10986 StackFrame::Id id = isolate->debug()->break_frame_id(); 10987 if (id == StackFrame::NO_ID) { 10988 // If there are no JavaScript stack frames return undefined. 10989 return heap->undefined_value(); 10990 } 10991 10992 int count = 0; 10993 JavaScriptFrameIterator it(isolate, id); 10994 for (; !it.done(); it.Advance()) { 10995 if (index < count + it.frame()->GetInlineCount()) break; 10996 count += it.frame()->GetInlineCount(); 10997 } 10998 if (it.done()) return heap->undefined_value(); 10999 11000 bool is_optimized = it.frame()->is_optimized(); 11001 11002 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame. 11003 if (is_optimized) { 11004 inlined_jsframe_index = 11005 it.frame()->GetInlineCount() - (index - count) - 1; 11006 } 11007 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); 11008 11009 // Traverse the saved contexts chain to find the active context for the 11010 // selected frame. 11011 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); 11012 11013 // Get the frame id. 11014 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); 11015 11016 // Find source position in unoptimized code. 11017 int position = frame_inspector.GetSourcePosition(); 11018 11019 // Check for constructor frame. 11020 bool constructor = frame_inspector.IsConstructor(); 11021 11022 // Get scope info and read from it for local variable information. 11023 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11024 Handle<SharedFunctionInfo> shared(function->shared()); 11025 Handle<ScopeInfo> scope_info(shared->scope_info()); 11026 ASSERT(*scope_info != ScopeInfo::Empty(isolate)); 11027 11028 // Get the locals names and values into a temporary array. 11029 // 11030 // TODO(1240907): Hide compiler-introduced stack variables 11031 // (e.g. .result)? For users of the debugger, they will probably be 11032 // confusing. 11033 Handle<FixedArray> locals = 11034 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2); 11035 11036 // Fill in the values of the locals. 11037 int i = 0; 11038 for (; i < scope_info->StackLocalCount(); ++i) { 11039 // Use the value from the stack. 11040 locals->set(i * 2, scope_info->LocalName(i)); 11041 locals->set(i * 2 + 1, frame_inspector.GetExpression(i)); 11042 } 11043 if (i < scope_info->LocalCount()) { 11044 // Get the context containing declarations. 11045 Handle<Context> context( 11046 Context::cast(it.frame()->context())->declaration_context()); 11047 for (; i < scope_info->LocalCount(); ++i) { 11048 Handle<String> name(scope_info->LocalName(i)); 11049 VariableMode mode; 11050 InitializationFlag init_flag; 11051 locals->set(i * 2, *name); 11052 locals->set(i * 2 + 1, context->get( 11053 scope_info->ContextSlotIndex(*name, &mode, &init_flag))); 11054 } 11055 } 11056 11057 // Check whether this frame is positioned at return. If not top 11058 // frame or if the frame is optimized it cannot be at a return. 11059 bool at_return = false; 11060 if (!is_optimized && index == 0) { 11061 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); 11062 } 11063 11064 // If positioned just before return find the value to be returned and add it 11065 // to the frame information. 11066 Handle<Object> return_value = isolate->factory()->undefined_value(); 11067 if (at_return) { 11068 StackFrameIterator it2(isolate); 11069 Address internal_frame_sp = NULL; 11070 while (!it2.done()) { 11071 if (it2.frame()->is_internal()) { 11072 internal_frame_sp = it2.frame()->sp(); 11073 } else { 11074 if (it2.frame()->is_java_script()) { 11075 if (it2.frame()->id() == it.frame()->id()) { 11076 // The internal frame just before the JavaScript frame contains the 11077 // value to return on top. A debug break at return will create an 11078 // internal frame to store the return value (eax/rax/r0) before 11079 // entering the debug break exit frame. 11080 if (internal_frame_sp != NULL) { 11081 return_value = 11082 Handle<Object>(Memory::Object_at(internal_frame_sp), 11083 isolate); 11084 break; 11085 } 11086 } 11087 } 11088 11089 // Indicate that the previous frame was not an internal frame. 11090 internal_frame_sp = NULL; 11091 } 11092 it2.Advance(); 11093 } 11094 } 11095 11096 // Now advance to the arguments adapter frame (if any). It contains all 11097 // the provided parameters whereas the function frame always have the number 11098 // of arguments matching the functions parameters. The rest of the 11099 // information (except for what is collected above) is the same. 11100 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { 11101 it.AdvanceToArgumentsFrame(); 11102 frame_inspector.SetArgumentsFrame(it.frame()); 11103 } 11104 11105 // Find the number of arguments to fill. At least fill the number of 11106 // parameters for the function and fill more if more parameters are provided. 11107 int argument_count = scope_info->ParameterCount(); 11108 if (argument_count < frame_inspector.GetParametersCount()) { 11109 argument_count = frame_inspector.GetParametersCount(); 11110 } 11111 11112 // Calculate the size of the result. 11113 int details_size = kFrameDetailsFirstDynamicIndex + 11114 2 * (argument_count + scope_info->LocalCount()) + 11115 (at_return ? 1 : 0); 11116 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 11117 11118 // Add the frame id. 11119 details->set(kFrameDetailsFrameIdIndex, *frame_id); 11120 11121 // Add the function (same as in function frame). 11122 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); 11123 11124 // Add the arguments count. 11125 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 11126 11127 // Add the locals count 11128 details->set(kFrameDetailsLocalCountIndex, 11129 Smi::FromInt(scope_info->LocalCount())); 11130 11131 // Add the source position. 11132 if (position != RelocInfo::kNoPosition) { 11133 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 11134 } else { 11135 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 11136 } 11137 11138 // Add the constructor information. 11139 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 11140 11141 // Add the at return information. 11142 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 11143 11144 // Add flags to indicate information on whether this frame is 11145 // bit 0: invoked in the debugger context. 11146 // bit 1: optimized frame. 11147 // bit 2: inlined in optimized frame 11148 int flags = 0; 11149 if (*save->context() == *isolate->debug()->debug_context()) { 11150 flags |= 1 << 0; 11151 } 11152 if (is_optimized) { 11153 flags |= 1 << 1; 11154 flags |= inlined_jsframe_index << 2; 11155 } 11156 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 11157 11158 // Fill the dynamic part. 11159 int details_index = kFrameDetailsFirstDynamicIndex; 11160 11161 // Add arguments name and value. 11162 for (int i = 0; i < argument_count; i++) { 11163 // Name of the argument. 11164 if (i < scope_info->ParameterCount()) { 11165 details->set(details_index++, scope_info->ParameterName(i)); 11166 } else { 11167 details->set(details_index++, heap->undefined_value()); 11168 } 11169 11170 // Parameter value. 11171 if (i < frame_inspector.GetParametersCount()) { 11172 // Get the value from the stack. 11173 details->set(details_index++, frame_inspector.GetParameter(i)); 11174 } else { 11175 details->set(details_index++, heap->undefined_value()); 11176 } 11177 } 11178 11179 // Add locals name and value from the temporary copy from the function frame. 11180 for (int i = 0; i < scope_info->LocalCount() * 2; i++) { 11181 details->set(details_index++, locals->get(i)); 11182 } 11183 11184 // Add the value being returned. 11185 if (at_return) { 11186 details->set(details_index++, *return_value); 11187 } 11188 11189 // Add the receiver (same as in function frame). 11190 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 11191 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 11192 Handle<Object> receiver(it.frame()->receiver(), isolate); 11193 if (!receiver->IsJSObject() && 11194 shared->is_classic_mode() && 11195 !function->IsBuiltin()) { 11196 // If the receiver is not a JSObject and the function is not a 11197 // builtin or strict-mode we have hit an optimization where a 11198 // value object is not converted into a wrapped JS objects. To 11199 // hide this optimization from the debugger, we wrap the receiver 11200 // by creating correct wrapper object based on the calling frame's 11201 // native context. 11202 it.Advance(); 11203 Handle<Context> calling_frames_native_context( 11204 Context::cast(Context::cast(it.frame()->context())->native_context())); 11205 ASSERT(!receiver->IsUndefined() && !receiver->IsNull()); 11206 receiver = 11207 isolate->factory()->ToObject(receiver, calling_frames_native_context); 11208 } 11209 details->set(kFrameDetailsReceiverIndex, *receiver); 11210 11211 ASSERT_EQ(details_size, details_index); 11212 return *isolate->factory()->NewJSArrayWithElements(details); 11213 } 11214 11215 11216 // Create a plain JSObject which materializes the local scope for the specified 11217 // frame. 11218 static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( 11219 Isolate* isolate, 11220 Handle<JSObject> target, 11221 Handle<JSFunction> function, 11222 FrameInspector* frame_inspector) { 11223 Handle<SharedFunctionInfo> shared(function->shared()); 11224 Handle<ScopeInfo> scope_info(shared->scope_info()); 11225 11226 // First fill all parameters. 11227 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11228 Handle<Object> value(i < frame_inspector->GetParametersCount() 11229 ? frame_inspector->GetParameter(i) 11230 : isolate->heap()->undefined_value(), 11231 isolate); 11232 ASSERT(!value->IsTheHole()); 11233 11234 RETURN_IF_EMPTY_HANDLE_VALUE( 11235 isolate, 11236 SetProperty(isolate, 11237 target, 11238 Handle<String>(scope_info->ParameterName(i)), 11239 value, 11240 NONE, 11241 kNonStrictMode), 11242 Handle<JSObject>()); 11243 } 11244 11245 // Second fill all stack locals. 11246 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11247 Handle<Object> value(frame_inspector->GetExpression(i), isolate); 11248 if (value->IsTheHole()) continue; 11249 11250 RETURN_IF_EMPTY_HANDLE_VALUE( 11251 isolate, 11252 SetProperty(isolate, 11253 target, 11254 Handle<String>(scope_info->StackLocalName(i)), 11255 value, 11256 NONE, 11257 kNonStrictMode), 11258 Handle<JSObject>()); 11259 } 11260 11261 return target; 11262 } 11263 11264 11265 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, 11266 Handle<JSObject> target, 11267 Handle<JSFunction> function, 11268 JavaScriptFrame* frame, 11269 int inlined_jsframe_index) { 11270 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11271 // Optimized frames are not supported. 11272 // TODO(yangguo): make sure all code deoptimized when debugger is active 11273 // and assert that this cannot happen. 11274 return; 11275 } 11276 11277 Handle<SharedFunctionInfo> shared(function->shared()); 11278 Handle<ScopeInfo> scope_info(shared->scope_info()); 11279 11280 // Parameters. 11281 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11282 ASSERT(!frame->GetParameter(i)->IsTheHole()); 11283 HandleScope scope(isolate); 11284 Handle<Object> value = GetProperty( 11285 isolate, target, Handle<String>(scope_info->ParameterName(i))); 11286 frame->SetParameterValue(i, *value); 11287 } 11288 11289 // Stack locals. 11290 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11291 if (frame->GetExpression(i)->IsTheHole()) continue; 11292 HandleScope scope(isolate); 11293 Handle<Object> value = GetProperty( 11294 isolate, target, Handle<String>(scope_info->StackLocalName(i))); 11295 frame->SetExpression(i, *value); 11296 } 11297 } 11298 11299 11300 static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, 11301 Handle<JSObject> target, 11302 Handle<JSFunction> function, 11303 JavaScriptFrame* frame) { 11304 HandleScope scope(isolate); 11305 Handle<SharedFunctionInfo> shared(function->shared()); 11306 Handle<ScopeInfo> scope_info(shared->scope_info()); 11307 11308 if (!scope_info->HasContext()) return target; 11309 11310 // Third fill all context locals. 11311 Handle<Context> frame_context(Context::cast(frame->context())); 11312 Handle<Context> function_context(frame_context->declaration_context()); 11313 if (!scope_info->CopyContextLocalsToScopeObject( 11314 isolate, function_context, target)) { 11315 return Handle<JSObject>(); 11316 } 11317 11318 // Finally copy any properties from the function context extension. 11319 // These will be variables introduced by eval. 11320 if (function_context->closure() == *function) { 11321 if (function_context->has_extension() && 11322 !function_context->IsNativeContext()) { 11323 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11324 bool threw = false; 11325 Handle<FixedArray> keys = 11326 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 11327 if (threw) return Handle<JSObject>(); 11328 11329 for (int i = 0; i < keys->length(); i++) { 11330 // Names of variables introduced by eval are strings. 11331 ASSERT(keys->get(i)->IsString()); 11332 Handle<String> key(String::cast(keys->get(i))); 11333 RETURN_IF_EMPTY_HANDLE_VALUE( 11334 isolate, 11335 SetProperty(isolate, 11336 target, 11337 key, 11338 GetProperty(isolate, ext, key), 11339 NONE, 11340 kNonStrictMode), 11341 Handle<JSObject>()); 11342 } 11343 } 11344 } 11345 11346 return target; 11347 } 11348 11349 11350 static Handle<JSObject> MaterializeLocalScope( 11351 Isolate* isolate, 11352 JavaScriptFrame* frame, 11353 int inlined_jsframe_index) { 11354 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 11355 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11356 11357 Handle<JSObject> local_scope = 11358 isolate->factory()->NewJSObject(isolate->object_function()); 11359 local_scope = MaterializeStackLocalsWithFrameInspector( 11360 isolate, local_scope, function, &frame_inspector); 11361 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>()); 11362 11363 return MaterializeLocalContext(isolate, local_scope, function, frame); 11364 } 11365 11366 11367 // Set the context local variable value. 11368 static bool SetContextLocalValue(Isolate* isolate, 11369 Handle<ScopeInfo> scope_info, 11370 Handle<Context> context, 11371 Handle<String> variable_name, 11372 Handle<Object> new_value) { 11373 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { 11374 Handle<String> next_name(scope_info->ContextLocalName(i)); 11375 if (variable_name->Equals(*next_name)) { 11376 VariableMode mode; 11377 InitializationFlag init_flag; 11378 int context_index = 11379 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag); 11380 context->set(context_index, *new_value); 11381 return true; 11382 } 11383 } 11384 11385 return false; 11386 } 11387 11388 11389 static bool SetLocalVariableValue(Isolate* isolate, 11390 JavaScriptFrame* frame, 11391 int inlined_jsframe_index, 11392 Handle<String> variable_name, 11393 Handle<Object> new_value) { 11394 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11395 // Optimized frames are not supported. 11396 return false; 11397 } 11398 11399 Handle<JSFunction> function(frame->function()); 11400 Handle<SharedFunctionInfo> shared(function->shared()); 11401 Handle<ScopeInfo> scope_info(shared->scope_info()); 11402 11403 bool default_result = false; 11404 11405 // Parameters. 11406 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11407 if (scope_info->ParameterName(i)->Equals(*variable_name)) { 11408 frame->SetParameterValue(i, *new_value); 11409 // Argument might be shadowed in heap context, don't stop here. 11410 default_result = true; 11411 } 11412 } 11413 11414 // Stack locals. 11415 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11416 if (scope_info->StackLocalName(i)->Equals(*variable_name)) { 11417 frame->SetExpression(i, *new_value); 11418 return true; 11419 } 11420 } 11421 11422 if (scope_info->HasContext()) { 11423 // Context locals. 11424 Handle<Context> frame_context(Context::cast(frame->context())); 11425 Handle<Context> function_context(frame_context->declaration_context()); 11426 if (SetContextLocalValue( 11427 isolate, scope_info, function_context, variable_name, new_value)) { 11428 return true; 11429 } 11430 11431 // Function context extension. These are variables introduced by eval. 11432 if (function_context->closure() == *function) { 11433 if (function_context->has_extension() && 11434 !function_context->IsNativeContext()) { 11435 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11436 11437 if (ext->HasProperty(*variable_name)) { 11438 // We don't expect this to do anything except replacing 11439 // property value. 11440 SetProperty(isolate, 11441 ext, 11442 variable_name, 11443 new_value, 11444 NONE, 11445 kNonStrictMode); 11446 return true; 11447 } 11448 } 11449 } 11450 } 11451 11452 return default_result; 11453 } 11454 11455 11456 // Create a plain JSObject which materializes the closure content for the 11457 // context. 11458 static Handle<JSObject> MaterializeClosure(Isolate* isolate, 11459 Handle<Context> context) { 11460 ASSERT(context->IsFunctionContext()); 11461 11462 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11463 Handle<ScopeInfo> scope_info(shared->scope_info()); 11464 11465 // Allocate and initialize a JSObject with all the content of this function 11466 // closure. 11467 Handle<JSObject> closure_scope = 11468 isolate->factory()->NewJSObject(isolate->object_function()); 11469 11470 // Fill all context locals to the context extension. 11471 if (!scope_info->CopyContextLocalsToScopeObject( 11472 isolate, context, closure_scope)) { 11473 return Handle<JSObject>(); 11474 } 11475 11476 // Finally copy any properties from the function context extension. This will 11477 // be variables introduced by eval. 11478 if (context->has_extension()) { 11479 Handle<JSObject> ext(JSObject::cast(context->extension())); 11480 bool threw = false; 11481 Handle<FixedArray> keys = 11482 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 11483 if (threw) return Handle<JSObject>(); 11484 11485 for (int i = 0; i < keys->length(); i++) { 11486 // Names of variables introduced by eval are strings. 11487 ASSERT(keys->get(i)->IsString()); 11488 Handle<String> key(String::cast(keys->get(i))); 11489 RETURN_IF_EMPTY_HANDLE_VALUE( 11490 isolate, 11491 SetProperty(isolate, 11492 closure_scope, 11493 key, 11494 GetProperty(isolate, ext, key), 11495 NONE, 11496 kNonStrictMode), 11497 Handle<JSObject>()); 11498 } 11499 } 11500 11501 return closure_scope; 11502 } 11503 11504 11505 // This method copies structure of MaterializeClosure method above. 11506 static bool SetClosureVariableValue(Isolate* isolate, 11507 Handle<Context> context, 11508 Handle<String> variable_name, 11509 Handle<Object> new_value) { 11510 ASSERT(context->IsFunctionContext()); 11511 11512 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11513 Handle<ScopeInfo> scope_info(shared->scope_info()); 11514 11515 // Context locals to the context extension. 11516 if (SetContextLocalValue( 11517 isolate, scope_info, context, variable_name, new_value)) { 11518 return true; 11519 } 11520 11521 // Properties from the function context extension. This will 11522 // be variables introduced by eval. 11523 if (context->has_extension()) { 11524 Handle<JSObject> ext(JSObject::cast(context->extension())); 11525 if (ext->HasProperty(*variable_name)) { 11526 // We don't expect this to do anything except replacing property value. 11527 SetProperty(isolate, 11528 ext, 11529 variable_name, 11530 new_value, 11531 NONE, 11532 kNonStrictMode); 11533 return true; 11534 } 11535 } 11536 11537 return false; 11538 } 11539 11540 11541 // Create a plain JSObject which materializes the scope for the specified 11542 // catch context. 11543 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, 11544 Handle<Context> context) { 11545 ASSERT(context->IsCatchContext()); 11546 Handle<String> name(String::cast(context->extension())); 11547 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), 11548 isolate); 11549 Handle<JSObject> catch_scope = 11550 isolate->factory()->NewJSObject(isolate->object_function()); 11551 RETURN_IF_EMPTY_HANDLE_VALUE( 11552 isolate, 11553 SetProperty(isolate, 11554 catch_scope, 11555 name, 11556 thrown_object, 11557 NONE, 11558 kNonStrictMode), 11559 Handle<JSObject>()); 11560 return catch_scope; 11561 } 11562 11563 11564 static bool SetCatchVariableValue(Isolate* isolate, 11565 Handle<Context> context, 11566 Handle<String> variable_name, 11567 Handle<Object> new_value) { 11568 ASSERT(context->IsCatchContext()); 11569 Handle<String> name(String::cast(context->extension())); 11570 if (!name->Equals(*variable_name)) { 11571 return false; 11572 } 11573 context->set(Context::THROWN_OBJECT_INDEX, *new_value); 11574 return true; 11575 } 11576 11577 11578 // Create a plain JSObject which materializes the block scope for the specified 11579 // block context. 11580 static Handle<JSObject> MaterializeBlockScope( 11581 Isolate* isolate, 11582 Handle<Context> context) { 11583 ASSERT(context->IsBlockContext()); 11584 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11585 11586 // Allocate and initialize a JSObject with all the arguments, stack locals 11587 // heap locals and extension properties of the debugged function. 11588 Handle<JSObject> block_scope = 11589 isolate->factory()->NewJSObject(isolate->object_function()); 11590 11591 // Fill all context locals. 11592 if (!scope_info->CopyContextLocalsToScopeObject( 11593 isolate, context, block_scope)) { 11594 return Handle<JSObject>(); 11595 } 11596 11597 return block_scope; 11598 } 11599 11600 11601 // Create a plain JSObject which materializes the module scope for the specified 11602 // module context. 11603 static Handle<JSObject> MaterializeModuleScope( 11604 Isolate* isolate, 11605 Handle<Context> context) { 11606 ASSERT(context->IsModuleContext()); 11607 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11608 11609 // Allocate and initialize a JSObject with all the members of the debugged 11610 // module. 11611 Handle<JSObject> module_scope = 11612 isolate->factory()->NewJSObject(isolate->object_function()); 11613 11614 // Fill all context locals. 11615 if (!scope_info->CopyContextLocalsToScopeObject( 11616 isolate, context, module_scope)) { 11617 return Handle<JSObject>(); 11618 } 11619 11620 return module_scope; 11621 } 11622 11623 11624 // Iterate over the actual scopes visible from a stack frame or from a closure. 11625 // The iteration proceeds from the innermost visible nested scope outwards. 11626 // All scopes are backed by an actual context except the local scope, 11627 // which is inserted "artificially" in the context chain. 11628 class ScopeIterator { 11629 public: 11630 enum ScopeType { 11631 ScopeTypeGlobal = 0, 11632 ScopeTypeLocal, 11633 ScopeTypeWith, 11634 ScopeTypeClosure, 11635 ScopeTypeCatch, 11636 ScopeTypeBlock, 11637 ScopeTypeModule 11638 }; 11639 11640 ScopeIterator(Isolate* isolate, 11641 JavaScriptFrame* frame, 11642 int inlined_jsframe_index) 11643 : isolate_(isolate), 11644 frame_(frame), 11645 inlined_jsframe_index_(inlined_jsframe_index), 11646 function_(frame->function()), 11647 context_(Context::cast(frame->context())), 11648 nested_scope_chain_(4), 11649 failed_(false) { 11650 11651 // Catch the case when the debugger stops in an internal function. 11652 Handle<SharedFunctionInfo> shared_info(function_->shared()); 11653 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11654 if (shared_info->script() == isolate->heap()->undefined_value()) { 11655 while (context_->closure() == *function_) { 11656 context_ = Handle<Context>(context_->previous(), isolate_); 11657 } 11658 return; 11659 } 11660 11661 // Get the debug info (create it if it does not exist). 11662 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) { 11663 // Return if ensuring debug info failed. 11664 return; 11665 } 11666 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); 11667 11668 // Find the break point where execution has stopped. 11669 BreakLocationIterator break_location_iterator(debug_info, 11670 ALL_BREAK_LOCATIONS); 11671 // pc points to the instruction after the current one, possibly a break 11672 // location as well. So the "- 1" to exclude it from the search. 11673 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); 11674 if (break_location_iterator.IsExit()) { 11675 // We are within the return sequence. At the momemt it is not possible to 11676 // get a source position which is consistent with the current scope chain. 11677 // Thus all nested with, catch and block contexts are skipped and we only 11678 // provide the function scope. 11679 if (scope_info->HasContext()) { 11680 context_ = Handle<Context>(context_->declaration_context(), isolate_); 11681 } else { 11682 while (context_->closure() == *function_) { 11683 context_ = Handle<Context>(context_->previous(), isolate_); 11684 } 11685 } 11686 if (scope_info->scope_type() != EVAL_SCOPE) { 11687 nested_scope_chain_.Add(scope_info); 11688 } 11689 } else { 11690 // Reparse the code and analyze the scopes. 11691 Handle<Script> script(Script::cast(shared_info->script())); 11692 Scope* scope = NULL; 11693 11694 // Check whether we are in global, eval or function code. 11695 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11696 if (scope_info->scope_type() != FUNCTION_SCOPE) { 11697 // Global or eval code. 11698 CompilationInfoWithZone info(script); 11699 if (scope_info->scope_type() == GLOBAL_SCOPE) { 11700 info.MarkAsGlobal(); 11701 } else { 11702 ASSERT(scope_info->scope_type() == EVAL_SCOPE); 11703 info.MarkAsEval(); 11704 info.SetContext(Handle<Context>(function_->context())); 11705 } 11706 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 11707 scope = info.function()->scope(); 11708 } 11709 RetrieveScopeChain(scope, shared_info); 11710 } else { 11711 // Function code 11712 CompilationInfoWithZone info(shared_info); 11713 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 11714 scope = info.function()->scope(); 11715 } 11716 RetrieveScopeChain(scope, shared_info); 11717 } 11718 } 11719 } 11720 11721 ScopeIterator(Isolate* isolate, 11722 Handle<JSFunction> function) 11723 : isolate_(isolate), 11724 frame_(NULL), 11725 inlined_jsframe_index_(0), 11726 function_(function), 11727 context_(function->context()), 11728 failed_(false) { 11729 if (function->IsBuiltin()) { 11730 context_ = Handle<Context>(); 11731 } 11732 } 11733 11734 // More scopes? 11735 bool Done() { 11736 ASSERT(!failed_); 11737 return context_.is_null(); 11738 } 11739 11740 bool Failed() { return failed_; } 11741 11742 // Move to the next scope. 11743 void Next() { 11744 ASSERT(!failed_); 11745 ScopeType scope_type = Type(); 11746 if (scope_type == ScopeTypeGlobal) { 11747 // The global scope is always the last in the chain. 11748 ASSERT(context_->IsNativeContext()); 11749 context_ = Handle<Context>(); 11750 return; 11751 } 11752 if (nested_scope_chain_.is_empty()) { 11753 context_ = Handle<Context>(context_->previous(), isolate_); 11754 } else { 11755 if (nested_scope_chain_.last()->HasContext()) { 11756 ASSERT(context_->previous() != NULL); 11757 context_ = Handle<Context>(context_->previous(), isolate_); 11758 } 11759 nested_scope_chain_.RemoveLast(); 11760 } 11761 } 11762 11763 // Return the type of the current scope. 11764 ScopeType Type() { 11765 ASSERT(!failed_); 11766 if (!nested_scope_chain_.is_empty()) { 11767 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); 11768 switch (scope_info->scope_type()) { 11769 case FUNCTION_SCOPE: 11770 ASSERT(context_->IsFunctionContext() || 11771 !scope_info->HasContext()); 11772 return ScopeTypeLocal; 11773 case MODULE_SCOPE: 11774 ASSERT(context_->IsModuleContext()); 11775 return ScopeTypeModule; 11776 case GLOBAL_SCOPE: 11777 ASSERT(context_->IsNativeContext()); 11778 return ScopeTypeGlobal; 11779 case WITH_SCOPE: 11780 ASSERT(context_->IsWithContext()); 11781 return ScopeTypeWith; 11782 case CATCH_SCOPE: 11783 ASSERT(context_->IsCatchContext()); 11784 return ScopeTypeCatch; 11785 case BLOCK_SCOPE: 11786 ASSERT(!scope_info->HasContext() || 11787 context_->IsBlockContext()); 11788 return ScopeTypeBlock; 11789 case EVAL_SCOPE: 11790 UNREACHABLE(); 11791 } 11792 } 11793 if (context_->IsNativeContext()) { 11794 ASSERT(context_->global_object()->IsGlobalObject()); 11795 return ScopeTypeGlobal; 11796 } 11797 if (context_->IsFunctionContext()) { 11798 return ScopeTypeClosure; 11799 } 11800 if (context_->IsCatchContext()) { 11801 return ScopeTypeCatch; 11802 } 11803 if (context_->IsBlockContext()) { 11804 return ScopeTypeBlock; 11805 } 11806 if (context_->IsModuleContext()) { 11807 return ScopeTypeModule; 11808 } 11809 ASSERT(context_->IsWithContext()); 11810 return ScopeTypeWith; 11811 } 11812 11813 // Return the JavaScript object with the content of the current scope. 11814 Handle<JSObject> ScopeObject() { 11815 ASSERT(!failed_); 11816 switch (Type()) { 11817 case ScopeIterator::ScopeTypeGlobal: 11818 return Handle<JSObject>(CurrentContext()->global_object()); 11819 case ScopeIterator::ScopeTypeLocal: 11820 // Materialize the content of the local scope into a JSObject. 11821 ASSERT(nested_scope_chain_.length() == 1); 11822 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); 11823 case ScopeIterator::ScopeTypeWith: 11824 // Return the with object. 11825 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); 11826 case ScopeIterator::ScopeTypeCatch: 11827 return MaterializeCatchScope(isolate_, CurrentContext()); 11828 case ScopeIterator::ScopeTypeClosure: 11829 // Materialize the content of the closure scope into a JSObject. 11830 return MaterializeClosure(isolate_, CurrentContext()); 11831 case ScopeIterator::ScopeTypeBlock: 11832 return MaterializeBlockScope(isolate_, CurrentContext()); 11833 case ScopeIterator::ScopeTypeModule: 11834 return MaterializeModuleScope(isolate_, CurrentContext()); 11835 } 11836 UNREACHABLE(); 11837 return Handle<JSObject>(); 11838 } 11839 11840 bool SetVariableValue(Handle<String> variable_name, 11841 Handle<Object> new_value) { 11842 ASSERT(!failed_); 11843 switch (Type()) { 11844 case ScopeIterator::ScopeTypeGlobal: 11845 break; 11846 case ScopeIterator::ScopeTypeLocal: 11847 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, 11848 variable_name, new_value); 11849 case ScopeIterator::ScopeTypeWith: 11850 break; 11851 case ScopeIterator::ScopeTypeCatch: 11852 return SetCatchVariableValue(isolate_, CurrentContext(), 11853 variable_name, new_value); 11854 case ScopeIterator::ScopeTypeClosure: 11855 return SetClosureVariableValue(isolate_, CurrentContext(), 11856 variable_name, new_value); 11857 case ScopeIterator::ScopeTypeBlock: 11858 // TODO(2399): should we implement it? 11859 break; 11860 case ScopeIterator::ScopeTypeModule: 11861 // TODO(2399): should we implement it? 11862 break; 11863 } 11864 return false; 11865 } 11866 11867 Handle<ScopeInfo> CurrentScopeInfo() { 11868 ASSERT(!failed_); 11869 if (!nested_scope_chain_.is_empty()) { 11870 return nested_scope_chain_.last(); 11871 } else if (context_->IsBlockContext()) { 11872 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); 11873 } else if (context_->IsFunctionContext()) { 11874 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); 11875 } 11876 return Handle<ScopeInfo>::null(); 11877 } 11878 11879 // Return the context for this scope. For the local context there might not 11880 // be an actual context. 11881 Handle<Context> CurrentContext() { 11882 ASSERT(!failed_); 11883 if (Type() == ScopeTypeGlobal || 11884 nested_scope_chain_.is_empty()) { 11885 return context_; 11886 } else if (nested_scope_chain_.last()->HasContext()) { 11887 return context_; 11888 } else { 11889 return Handle<Context>(); 11890 } 11891 } 11892 11893 #ifdef DEBUG 11894 // Debug print of the content of the current scope. 11895 void DebugPrint() { 11896 ASSERT(!failed_); 11897 switch (Type()) { 11898 case ScopeIterator::ScopeTypeGlobal: 11899 PrintF("Global:\n"); 11900 CurrentContext()->Print(); 11901 break; 11902 11903 case ScopeIterator::ScopeTypeLocal: { 11904 PrintF("Local:\n"); 11905 function_->shared()->scope_info()->Print(); 11906 if (!CurrentContext().is_null()) { 11907 CurrentContext()->Print(); 11908 if (CurrentContext()->has_extension()) { 11909 Handle<Object> extension(CurrentContext()->extension(), isolate_); 11910 if (extension->IsJSContextExtensionObject()) { 11911 extension->Print(); 11912 } 11913 } 11914 } 11915 break; 11916 } 11917 11918 case ScopeIterator::ScopeTypeWith: 11919 PrintF("With:\n"); 11920 CurrentContext()->extension()->Print(); 11921 break; 11922 11923 case ScopeIterator::ScopeTypeCatch: 11924 PrintF("Catch:\n"); 11925 CurrentContext()->extension()->Print(); 11926 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(); 11927 break; 11928 11929 case ScopeIterator::ScopeTypeClosure: 11930 PrintF("Closure:\n"); 11931 CurrentContext()->Print(); 11932 if (CurrentContext()->has_extension()) { 11933 Handle<Object> extension(CurrentContext()->extension(), isolate_); 11934 if (extension->IsJSContextExtensionObject()) { 11935 extension->Print(); 11936 } 11937 } 11938 break; 11939 11940 default: 11941 UNREACHABLE(); 11942 } 11943 PrintF("\n"); 11944 } 11945 #endif 11946 11947 private: 11948 Isolate* isolate_; 11949 JavaScriptFrame* frame_; 11950 int inlined_jsframe_index_; 11951 Handle<JSFunction> function_; 11952 Handle<Context> context_; 11953 List<Handle<ScopeInfo> > nested_scope_chain_; 11954 bool failed_; 11955 11956 void RetrieveScopeChain(Scope* scope, 11957 Handle<SharedFunctionInfo> shared_info) { 11958 if (scope != NULL) { 11959 int source_position = shared_info->code()->SourcePosition(frame_->pc()); 11960 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); 11961 } else { 11962 // A failed reparse indicates that the preparser has diverged from the 11963 // parser or that the preparse data given to the initial parse has been 11964 // faulty. We fail in debug mode but in release mode we only provide the 11965 // information we get from the context chain but nothing about 11966 // completely stack allocated scopes or stack allocated locals. 11967 // Or it could be due to stack overflow. 11968 ASSERT(isolate_->has_pending_exception()); 11969 failed_ = true; 11970 } 11971 } 11972 11973 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 11974 }; 11975 11976 11977 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { 11978 HandleScope scope(isolate); 11979 ASSERT(args.length() == 2); 11980 11981 // Check arguments. 11982 Object* check; 11983 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11984 RUNTIME_ARGUMENTS(isolate, args)); 11985 if (!maybe_check->ToObject(&check)) return maybe_check; 11986 } 11987 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 11988 11989 // Get the frame where the debugging is performed. 11990 StackFrame::Id id = UnwrapFrameId(wrapped_id); 11991 JavaScriptFrameIterator it(isolate, id); 11992 JavaScriptFrame* frame = it.frame(); 11993 11994 // Count the visible scopes. 11995 int n = 0; 11996 for (ScopeIterator it(isolate, frame, 0); 11997 !it.Done(); 11998 it.Next()) { 11999 n++; 12000 } 12001 12002 return Smi::FromInt(n); 12003 } 12004 12005 12006 // Returns the list of step-in positions (text offset) in a function of the 12007 // stack frame in a range from the current debug break position to the end 12008 // of the corresponding statement. 12009 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { 12010 HandleScope scope(isolate); 12011 ASSERT(args.length() == 2); 12012 12013 // Check arguments. 12014 Object* check; 12015 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12016 RUNTIME_ARGUMENTS(isolate, args)); 12017 if (!maybe_check->ToObject(&check)) return maybe_check; 12018 } 12019 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12020 12021 // Get the frame where the debugging is performed. 12022 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12023 JavaScriptFrameIterator frame_it(isolate, id); 12024 JavaScriptFrame* frame = frame_it.frame(); 12025 12026 Handle<JSFunction> fun = 12027 Handle<JSFunction>(frame->function()); 12028 Handle<SharedFunctionInfo> shared = 12029 Handle<SharedFunctionInfo>(fun->shared()); 12030 12031 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { 12032 return isolate->heap()->undefined_value(); 12033 } 12034 12035 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); 12036 12037 int len = 0; 12038 Handle<JSArray> array(isolate->factory()->NewJSArray(10)); 12039 // Find the break point where execution has stopped. 12040 BreakLocationIterator break_location_iterator(debug_info, 12041 ALL_BREAK_LOCATIONS); 12042 12043 break_location_iterator.FindBreakLocationFromAddress(frame->pc()); 12044 int current_statement_pos = break_location_iterator.statement_position(); 12045 12046 while (!break_location_iterator.Done()) { 12047 if (break_location_iterator.pc() > frame->pc()) { 12048 if (break_location_iterator.IsStepInLocation(isolate)) { 12049 Smi* position_value = Smi::FromInt(break_location_iterator.position()); 12050 JSObject::SetElement(array, len, 12051 Handle<Object>(position_value, isolate), 12052 NONE, kNonStrictMode); 12053 len++; 12054 } 12055 } 12056 // Advance iterator. 12057 break_location_iterator.Next(); 12058 if (current_statement_pos != 12059 break_location_iterator.statement_position()) { 12060 break; 12061 } 12062 } 12063 return *array; 12064 } 12065 12066 12067 static const int kScopeDetailsTypeIndex = 0; 12068 static const int kScopeDetailsObjectIndex = 1; 12069 static const int kScopeDetailsSize = 2; 12070 12071 12072 static MaybeObject* MaterializeScopeDetails(Isolate* isolate, 12073 ScopeIterator* it) { 12074 // Calculate the size of the result. 12075 int details_size = kScopeDetailsSize; 12076 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 12077 12078 // Fill in scope details. 12079 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); 12080 Handle<JSObject> scope_object = it->ScopeObject(); 12081 RETURN_IF_EMPTY_HANDLE(isolate, scope_object); 12082 details->set(kScopeDetailsObjectIndex, *scope_object); 12083 12084 return *isolate->factory()->NewJSArrayWithElements(details); 12085 } 12086 12087 12088 // Return an array with scope details 12089 // args[0]: number: break id 12090 // args[1]: number: frame index 12091 // args[2]: number: inlined frame index 12092 // args[3]: number: scope index 12093 // 12094 // The array returned contains the following information: 12095 // 0: Scope type 12096 // 1: Scope object 12097 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { 12098 HandleScope scope(isolate); 12099 ASSERT(args.length() == 4); 12100 12101 // Check arguments. 12102 Object* check; 12103 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12104 RUNTIME_ARGUMENTS(isolate, args)); 12105 if (!maybe_check->ToObject(&check)) return maybe_check; 12106 } 12107 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12108 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12109 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12110 12111 // Get the frame where the debugging is performed. 12112 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12113 JavaScriptFrameIterator frame_it(isolate, id); 12114 JavaScriptFrame* frame = frame_it.frame(); 12115 12116 // Find the requested scope. 12117 int n = 0; 12118 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12119 for (; !it.Done() && n < index; it.Next()) { 12120 n++; 12121 } 12122 if (it.Done()) { 12123 return isolate->heap()->undefined_value(); 12124 } 12125 return MaterializeScopeDetails(isolate, &it); 12126 } 12127 12128 12129 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) { 12130 HandleScope scope(isolate); 12131 ASSERT(args.length() == 1); 12132 12133 // Check arguments. 12134 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12135 12136 // Count the visible scopes. 12137 int n = 0; 12138 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { 12139 n++; 12140 } 12141 12142 return Smi::FromInt(n); 12143 } 12144 12145 12146 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { 12147 HandleScope scope(isolate); 12148 ASSERT(args.length() == 2); 12149 12150 // Check arguments. 12151 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12152 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12153 12154 // Find the requested scope. 12155 int n = 0; 12156 ScopeIterator it(isolate, fun); 12157 for (; !it.Done() && n < index; it.Next()) { 12158 n++; 12159 } 12160 if (it.Done()) { 12161 return isolate->heap()->undefined_value(); 12162 } 12163 12164 return MaterializeScopeDetails(isolate, &it); 12165 } 12166 12167 12168 static bool SetScopeVariableValue(ScopeIterator* it, int index, 12169 Handle<String> variable_name, 12170 Handle<Object> new_value) { 12171 for (int n = 0; !it->Done() && n < index; it->Next()) { 12172 n++; 12173 } 12174 if (it->Done()) { 12175 return false; 12176 } 12177 return it->SetVariableValue(variable_name, new_value); 12178 } 12179 12180 12181 // Change variable value in closure or local scope 12182 // args[0]: number or JsFunction: break id or function 12183 // args[1]: number: frame index (when arg[0] is break id) 12184 // args[2]: number: inlined frame index (when arg[0] is break id) 12185 // args[3]: number: scope index 12186 // args[4]: string: variable name 12187 // args[5]: object: new value 12188 // 12189 // Return true if success and false otherwise 12190 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) { 12191 HandleScope scope(isolate); 12192 ASSERT(args.length() == 6); 12193 12194 // Check arguments. 12195 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12196 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); 12197 Handle<Object> new_value = args.at<Object>(5); 12198 12199 bool res; 12200 if (args[0]->IsNumber()) { 12201 Object* check; 12202 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12203 RUNTIME_ARGUMENTS(isolate, args)); 12204 if (!maybe_check->ToObject(&check)) return maybe_check; 12205 } 12206 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12207 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12208 12209 // Get the frame where the debugging is performed. 12210 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12211 JavaScriptFrameIterator frame_it(isolate, id); 12212 JavaScriptFrame* frame = frame_it.frame(); 12213 12214 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12215 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12216 } else { 12217 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12218 ScopeIterator it(isolate, fun); 12219 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12220 } 12221 12222 return isolate->heap()->ToBoolean(res); 12223 } 12224 12225 12226 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { 12227 HandleScope scope(isolate); 12228 ASSERT(args.length() == 0); 12229 12230 #ifdef DEBUG 12231 // Print the scopes for the top frame. 12232 StackFrameLocator locator(isolate); 12233 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 12234 for (ScopeIterator it(isolate, frame, 0); 12235 !it.Done(); 12236 it.Next()) { 12237 it.DebugPrint(); 12238 } 12239 #endif 12240 return isolate->heap()->undefined_value(); 12241 } 12242 12243 12244 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) { 12245 HandleScope scope(isolate); 12246 ASSERT(args.length() == 1); 12247 12248 // Check arguments. 12249 Object* result; 12250 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12251 RUNTIME_ARGUMENTS(isolate, args)); 12252 if (!maybe_result->ToObject(&result)) return maybe_result; 12253 } 12254 12255 // Count all archived V8 threads. 12256 int n = 0; 12257 for (ThreadState* thread = 12258 isolate->thread_manager()->FirstThreadStateInUse(); 12259 thread != NULL; 12260 thread = thread->Next()) { 12261 n++; 12262 } 12263 12264 // Total number of threads is current thread and archived threads. 12265 return Smi::FromInt(n + 1); 12266 } 12267 12268 12269 static const int kThreadDetailsCurrentThreadIndex = 0; 12270 static const int kThreadDetailsThreadIdIndex = 1; 12271 static const int kThreadDetailsSize = 2; 12272 12273 // Return an array with thread details 12274 // args[0]: number: break id 12275 // args[1]: number: thread index 12276 // 12277 // The array returned contains the following information: 12278 // 0: Is current thread? 12279 // 1: Thread id 12280 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { 12281 HandleScope scope(isolate); 12282 ASSERT(args.length() == 2); 12283 12284 // Check arguments. 12285 Object* check; 12286 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12287 RUNTIME_ARGUMENTS(isolate, args)); 12288 if (!maybe_check->ToObject(&check)) return maybe_check; 12289 } 12290 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12291 12292 // Allocate array for result. 12293 Handle<FixedArray> details = 12294 isolate->factory()->NewFixedArray(kThreadDetailsSize); 12295 12296 // Thread index 0 is current thread. 12297 if (index == 0) { 12298 // Fill the details. 12299 details->set(kThreadDetailsCurrentThreadIndex, 12300 isolate->heap()->true_value()); 12301 details->set(kThreadDetailsThreadIdIndex, 12302 Smi::FromInt(ThreadId::Current().ToInteger())); 12303 } else { 12304 // Find the thread with the requested index. 12305 int n = 1; 12306 ThreadState* thread = 12307 isolate->thread_manager()->FirstThreadStateInUse(); 12308 while (index != n && thread != NULL) { 12309 thread = thread->Next(); 12310 n++; 12311 } 12312 if (thread == NULL) { 12313 return isolate->heap()->undefined_value(); 12314 } 12315 12316 // Fill the details. 12317 details->set(kThreadDetailsCurrentThreadIndex, 12318 isolate->heap()->false_value()); 12319 details->set(kThreadDetailsThreadIdIndex, 12320 Smi::FromInt(thread->id().ToInteger())); 12321 } 12322 12323 // Convert to JS array and return. 12324 return *isolate->factory()->NewJSArrayWithElements(details); 12325 } 12326 12327 12328 // Sets the disable break state 12329 // args[0]: disable break state 12330 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) { 12331 HandleScope scope(isolate); 12332 ASSERT(args.length() == 1); 12333 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); 12334 isolate->debug()->set_disable_break(disable_break); 12335 return isolate->heap()->undefined_value(); 12336 } 12337 12338 12339 static bool IsPositionAlignmentCodeCorrect(int alignment) { 12340 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; 12341 } 12342 12343 12344 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { 12345 HandleScope scope(isolate); 12346 ASSERT(args.length() == 2); 12347 12348 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12349 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); 12350 12351 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12352 return isolate->ThrowIllegalOperation(); 12353 } 12354 BreakPositionAlignment alignment = 12355 static_cast<BreakPositionAlignment>(statement_aligned_code); 12356 12357 Handle<SharedFunctionInfo> shared(fun->shared()); 12358 // Find the number of break points 12359 Handle<Object> break_locations = 12360 Debug::GetSourceBreakLocations(shared, alignment); 12361 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); 12362 // Return array as JS array 12363 return *isolate->factory()->NewJSArrayWithElements( 12364 Handle<FixedArray>::cast(break_locations)); 12365 } 12366 12367 12368 // Set a break point in a function. 12369 // args[0]: function 12370 // args[1]: number: break source position (within the function source) 12371 // args[2]: number: break point object 12372 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { 12373 HandleScope scope(isolate); 12374 ASSERT(args.length() == 3); 12375 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 12376 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12377 RUNTIME_ASSERT(source_position >= 0); 12378 Handle<Object> break_point_object_arg = args.at<Object>(2); 12379 12380 // Set break point. 12381 isolate->debug()->SetBreakPoint(function, break_point_object_arg, 12382 &source_position); 12383 12384 return Smi::FromInt(source_position); 12385 } 12386 12387 12388 // Changes the state of a break point in a script and returns source position 12389 // where break point was set. NOTE: Regarding performance see the NOTE for 12390 // GetScriptFromScriptData. 12391 // args[0]: script to set break point in 12392 // args[1]: number: break source position (within the script source) 12393 // args[2]: number, breakpoint position alignment 12394 // args[3]: number: break point object 12395 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { 12396 HandleScope scope(isolate); 12397 ASSERT(args.length() == 4); 12398 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 12399 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12400 RUNTIME_ASSERT(source_position >= 0); 12401 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); 12402 Handle<Object> break_point_object_arg = args.at<Object>(3); 12403 12404 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12405 return isolate->ThrowIllegalOperation(); 12406 } 12407 BreakPositionAlignment alignment = 12408 static_cast<BreakPositionAlignment>(statement_aligned_code); 12409 12410 // Get the script from the script wrapper. 12411 RUNTIME_ASSERT(wrapper->value()->IsScript()); 12412 Handle<Script> script(Script::cast(wrapper->value())); 12413 12414 // Set break point. 12415 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, 12416 &source_position, 12417 alignment)) { 12418 return isolate->heap()->undefined_value(); 12419 } 12420 12421 return Smi::FromInt(source_position); 12422 } 12423 12424 12425 // Clear a break point 12426 // args[0]: number: break point object 12427 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { 12428 HandleScope scope(isolate); 12429 ASSERT(args.length() == 1); 12430 Handle<Object> break_point_object_arg = args.at<Object>(0); 12431 12432 // Clear break point. 12433 isolate->debug()->ClearBreakPoint(break_point_object_arg); 12434 12435 return isolate->heap()->undefined_value(); 12436 } 12437 12438 12439 // Change the state of break on exceptions. 12440 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 12441 // args[1]: Boolean indicating on/off. 12442 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { 12443 HandleScope scope(isolate); 12444 ASSERT(args.length() == 2); 12445 RUNTIME_ASSERT(args[0]->IsNumber()); 12446 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 12447 12448 // If the number doesn't match an enum value, the ChangeBreakOnException 12449 // function will default to affecting caught exceptions. 12450 ExceptionBreakType type = 12451 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 12452 // Update break point state. 12453 isolate->debug()->ChangeBreakOnException(type, enable); 12454 return isolate->heap()->undefined_value(); 12455 } 12456 12457 12458 // Returns the state of break on exceptions 12459 // args[0]: boolean indicating uncaught exceptions 12460 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { 12461 HandleScope scope(isolate); 12462 ASSERT(args.length() == 1); 12463 RUNTIME_ASSERT(args[0]->IsNumber()); 12464 12465 ExceptionBreakType type = 12466 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 12467 bool result = isolate->debug()->IsBreakOnException(type); 12468 return Smi::FromInt(result); 12469 } 12470 12471 12472 // Prepare for stepping 12473 // args[0]: break id for checking execution state 12474 // args[1]: step action from the enumeration StepAction 12475 // args[2]: number of times to perform the step, for step out it is the number 12476 // of frames to step down. 12477 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { 12478 HandleScope scope(isolate); 12479 ASSERT(args.length() == 3); 12480 // Check arguments. 12481 Object* check; 12482 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12483 RUNTIME_ARGUMENTS(isolate, args)); 12484 if (!maybe_check->ToObject(&check)) return maybe_check; 12485 } 12486 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 12487 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12488 } 12489 12490 // Get the step action and check validity. 12491 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 12492 if (step_action != StepIn && 12493 step_action != StepNext && 12494 step_action != StepOut && 12495 step_action != StepInMin && 12496 step_action != StepMin) { 12497 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12498 } 12499 12500 // Get the number of steps. 12501 int step_count = NumberToInt32(args[2]); 12502 if (step_count < 1) { 12503 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12504 } 12505 12506 // Clear all current stepping setup. 12507 isolate->debug()->ClearStepping(); 12508 12509 // Prepare step. 12510 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), 12511 step_count); 12512 return isolate->heap()->undefined_value(); 12513 } 12514 12515 12516 // Clear all stepping set by PrepareStep. 12517 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { 12518 HandleScope scope(isolate); 12519 ASSERT(args.length() == 0); 12520 isolate->debug()->ClearStepping(); 12521 return isolate->heap()->undefined_value(); 12522 } 12523 12524 12525 // Helper function to find or create the arguments object for 12526 // Runtime_DebugEvaluate. 12527 static Handle<JSObject> MaterializeArgumentsObject( 12528 Isolate* isolate, 12529 Handle<JSObject> target, 12530 Handle<JSFunction> function) { 12531 // Do not materialize the arguments object for eval or top-level code. 12532 // Skip if "arguments" is already taken. 12533 if (!function->shared()->is_function() || 12534 target->HasLocalProperty(isolate->heap()->arguments_string())) { 12535 return target; 12536 } 12537 12538 // FunctionGetArguments can't throw an exception. 12539 Handle<JSObject> arguments = Handle<JSObject>::cast( 12540 Accessors::FunctionGetArguments(function)); 12541 SetProperty(isolate, 12542 target, 12543 isolate->factory()->arguments_string(), 12544 arguments, 12545 ::NONE, 12546 kNonStrictMode); 12547 return target; 12548 } 12549 12550 12551 // Compile and evaluate source for the given context. 12552 static MaybeObject* DebugEvaluate(Isolate* isolate, 12553 Handle<Context> context, 12554 Handle<Object> context_extension, 12555 Handle<Object> receiver, 12556 Handle<String> source) { 12557 if (context_extension->IsJSObject()) { 12558 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); 12559 Handle<JSFunction> closure(context->closure(), isolate); 12560 context = isolate->factory()->NewWithContext(closure, context, extension); 12561 } 12562 12563 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 12564 source, 12565 context, 12566 context->IsNativeContext(), 12567 CLASSIC_MODE, 12568 NO_PARSE_RESTRICTION, 12569 RelocInfo::kNoPosition); 12570 RETURN_IF_EMPTY_HANDLE(isolate, shared); 12571 12572 Handle<JSFunction> eval_fun = 12573 isolate->factory()->NewFunctionFromSharedFunctionInfo( 12574 shared, context, NOT_TENURED); 12575 bool pending_exception; 12576 Handle<Object> result = Execution::Call( 12577 eval_fun, receiver, 0, NULL, &pending_exception); 12578 12579 if (pending_exception) return Failure::Exception(); 12580 12581 // Skip the global proxy as it has no properties and always delegates to the 12582 // real global object. 12583 if (result->IsJSGlobalProxy()) { 12584 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate))); 12585 } 12586 12587 // Clear the oneshot breakpoints so that the debugger does not step further. 12588 isolate->debug()->ClearStepping(); 12589 return *result; 12590 } 12591 12592 12593 // Evaluate a piece of JavaScript in the context of a stack frame for 12594 // debugging. Things that need special attention are: 12595 // - Parameters and stack-allocated locals need to be materialized. Altered 12596 // values need to be written back to the stack afterwards. 12597 // - The arguments object needs to materialized. 12598 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { 12599 HandleScope scope(isolate); 12600 12601 // Check the execution state and decode arguments frame and source to be 12602 // evaluated. 12603 ASSERT(args.length() == 6); 12604 Object* check_result; 12605 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12606 RUNTIME_ARGUMENTS(isolate, args)); 12607 if (!maybe_result->ToObject(&check_result)) return maybe_result; 12608 } 12609 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12610 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12611 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 12612 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); 12613 Handle<Object> context_extension(args[5], isolate); 12614 12615 // Handle the processing of break. 12616 DisableBreak disable_break_save(disable_break); 12617 12618 // Get the frame where the debugging is performed. 12619 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12620 JavaScriptFrameIterator it(isolate, id); 12621 JavaScriptFrame* frame = it.frame(); 12622 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 12623 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 12624 12625 // Traverse the saved contexts chain to find the active context for the 12626 // selected frame. 12627 SaveContext* save = FindSavedContextForFrame(isolate, frame); 12628 12629 SaveContext savex(isolate); 12630 isolate->set_context(*(save->context())); 12631 12632 // Evaluate on the context of the frame. 12633 Handle<Context> context(Context::cast(frame->context())); 12634 ASSERT(!context.is_null()); 12635 12636 // Materialize stack locals and the arguments object. 12637 Handle<JSObject> materialized = 12638 isolate->factory()->NewJSObject(isolate->object_function()); 12639 12640 materialized = MaterializeStackLocalsWithFrameInspector( 12641 isolate, materialized, function, &frame_inspector); 12642 RETURN_IF_EMPTY_HANDLE(isolate, materialized); 12643 12644 materialized = MaterializeArgumentsObject(isolate, materialized, function); 12645 RETURN_IF_EMPTY_HANDLE(isolate, materialized); 12646 12647 // Add the materialized object in a with-scope to shadow the stack locals. 12648 context = isolate->factory()->NewWithContext(function, context, materialized); 12649 12650 Handle<Object> receiver(frame->receiver(), isolate); 12651 Object* evaluate_result_object; 12652 { MaybeObject* maybe_result = 12653 DebugEvaluate(isolate, context, context_extension, receiver, source); 12654 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result; 12655 } 12656 12657 Handle<Object> result(evaluate_result_object, isolate); 12658 12659 // Write back potential changes to materialized stack locals to the stack. 12660 UpdateStackLocalsFromMaterializedObject( 12661 isolate, materialized, function, frame, inlined_jsframe_index); 12662 12663 return *result; 12664 } 12665 12666 12667 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { 12668 HandleScope scope(isolate); 12669 12670 // Check the execution state and decode arguments frame and source to be 12671 // evaluated. 12672 ASSERT(args.length() == 4); 12673 Object* check_result; 12674 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12675 RUNTIME_ARGUMENTS(isolate, args)); 12676 if (!maybe_result->ToObject(&check_result)) return maybe_result; 12677 } 12678 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 12679 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); 12680 Handle<Object> context_extension(args[3], isolate); 12681 12682 // Handle the processing of break. 12683 DisableBreak disable_break_save(disable_break); 12684 12685 // Enter the top context from before the debugger was invoked. 12686 SaveContext save(isolate); 12687 SaveContext* top = &save; 12688 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { 12689 top = top->prev(); 12690 } 12691 if (top != NULL) { 12692 isolate->set_context(*top->context()); 12693 } 12694 12695 // Get the native context now set to the top context from before the 12696 // debugger was invoked. 12697 Handle<Context> context = isolate->native_context(); 12698 Handle<Object> receiver = isolate->global_object(); 12699 return DebugEvaluate(isolate, context, context_extension, receiver, source); 12700 } 12701 12702 12703 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { 12704 HandleScope scope(isolate); 12705 ASSERT(args.length() == 0); 12706 12707 // Fill the script objects. 12708 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); 12709 12710 // Convert the script objects to proper JS objects. 12711 for (int i = 0; i < instances->length(); i++) { 12712 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 12713 // Get the script wrapper in a local handle before calling GetScriptWrapper, 12714 // because using 12715 // instances->set(i, *GetScriptWrapper(script)) 12716 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 12717 // already have dereferenced the instances handle. 12718 Handle<JSValue> wrapper = GetScriptWrapper(script); 12719 instances->set(i, *wrapper); 12720 } 12721 12722 // Return result as a JS array. 12723 Handle<JSObject> result = 12724 isolate->factory()->NewJSObject(isolate->array_function()); 12725 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances); 12726 return *result; 12727 } 12728 12729 12730 // Helper function used by Runtime_DebugReferencedBy below. 12731 static int DebugReferencedBy(HeapIterator* iterator, 12732 JSObject* target, 12733 Object* instance_filter, int max_references, 12734 FixedArray* instances, int instances_size, 12735 JSFunction* arguments_function) { 12736 Isolate* isolate = target->GetIsolate(); 12737 SealHandleScope shs(isolate); 12738 DisallowHeapAllocation no_allocation; 12739 12740 // Iterate the heap. 12741 int count = 0; 12742 JSObject* last = NULL; 12743 HeapObject* heap_obj = NULL; 12744 while (((heap_obj = iterator->next()) != NULL) && 12745 (max_references == 0 || count < max_references)) { 12746 // Only look at all JSObjects. 12747 if (heap_obj->IsJSObject()) { 12748 // Skip context extension objects and argument arrays as these are 12749 // checked in the context of functions using them. 12750 JSObject* obj = JSObject::cast(heap_obj); 12751 if (obj->IsJSContextExtensionObject() || 12752 obj->map()->constructor() == arguments_function) { 12753 continue; 12754 } 12755 12756 // Check if the JS object has a reference to the object looked for. 12757 if (obj->ReferencesObject(target)) { 12758 // Check instance filter if supplied. This is normally used to avoid 12759 // references from mirror objects (see Runtime_IsInPrototypeChain). 12760 if (!instance_filter->IsUndefined()) { 12761 Object* V = obj; 12762 while (true) { 12763 Object* prototype = V->GetPrototype(isolate); 12764 if (prototype->IsNull()) { 12765 break; 12766 } 12767 if (instance_filter == prototype) { 12768 obj = NULL; // Don't add this object. 12769 break; 12770 } 12771 V = prototype; 12772 } 12773 } 12774 12775 if (obj != NULL) { 12776 // Valid reference found add to instance array if supplied an update 12777 // count. 12778 if (instances != NULL && count < instances_size) { 12779 instances->set(count, obj); 12780 } 12781 last = obj; 12782 count++; 12783 } 12784 } 12785 } 12786 } 12787 12788 // Check for circular reference only. This can happen when the object is only 12789 // referenced from mirrors and has a circular reference in which case the 12790 // object is not really alive and would have been garbage collected if not 12791 // referenced from the mirror. 12792 if (count == 1 && last == target) { 12793 count = 0; 12794 } 12795 12796 // Return the number of referencing objects found. 12797 return count; 12798 } 12799 12800 12801 // Scan the heap for objects with direct references to an object 12802 // args[0]: the object to find references to 12803 // args[1]: constructor function for instances to exclude (Mirror) 12804 // args[2]: the the maximum number of objects to return 12805 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { 12806 SealHandleScope shs(isolate); 12807 ASSERT(args.length() == 3); 12808 12809 // First perform a full GC in order to avoid references from dead objects. 12810 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 12811 "%DebugReferencedBy"); 12812 // The heap iterator reserves the right to do a GC to make the heap iterable. 12813 // Due to the GC above we know it won't need to do that, but it seems cleaner 12814 // to get the heap iterator constructed before we start having unprotected 12815 // Object* locals that are not protected by handles. 12816 12817 // Check parameters. 12818 CONVERT_ARG_CHECKED(JSObject, target, 0); 12819 Object* instance_filter = args[1]; 12820 RUNTIME_ASSERT(instance_filter->IsUndefined() || 12821 instance_filter->IsJSObject()); 12822 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 12823 RUNTIME_ASSERT(max_references >= 0); 12824 12825 12826 // Get the constructor function for context extension and arguments array. 12827 JSObject* arguments_boilerplate = 12828 isolate->context()->native_context()->arguments_boilerplate(); 12829 JSFunction* arguments_function = 12830 JSFunction::cast(arguments_boilerplate->map()->constructor()); 12831 12832 // Get the number of referencing objects. 12833 int count; 12834 Heap* heap = isolate->heap(); 12835 HeapIterator heap_iterator(heap); 12836 count = DebugReferencedBy(&heap_iterator, 12837 target, instance_filter, max_references, 12838 NULL, 0, arguments_function); 12839 12840 // Allocate an array to hold the result. 12841 Object* object; 12842 { MaybeObject* maybe_object = heap->AllocateFixedArray(count); 12843 if (!maybe_object->ToObject(&object)) return maybe_object; 12844 } 12845 FixedArray* instances = FixedArray::cast(object); 12846 12847 // Fill the referencing objects. 12848 // AllocateFixedArray above does not make the heap non-iterable. 12849 ASSERT(heap->IsHeapIterable()); 12850 HeapIterator heap_iterator2(heap); 12851 count = DebugReferencedBy(&heap_iterator2, 12852 target, instance_filter, max_references, 12853 instances, count, arguments_function); 12854 12855 // Return result as JS array. 12856 Object* result; 12857 MaybeObject* maybe_result = heap->AllocateJSObject( 12858 isolate->context()->native_context()->array_function()); 12859 if (!maybe_result->ToObject(&result)) return maybe_result; 12860 return JSArray::cast(result)->SetContent(instances); 12861 } 12862 12863 12864 // Helper function used by Runtime_DebugConstructedBy below. 12865 static int DebugConstructedBy(HeapIterator* iterator, 12866 JSFunction* constructor, 12867 int max_references, 12868 FixedArray* instances, 12869 int instances_size) { 12870 DisallowHeapAllocation no_allocation; 12871 12872 // Iterate the heap. 12873 int count = 0; 12874 HeapObject* heap_obj = NULL; 12875 while (((heap_obj = iterator->next()) != NULL) && 12876 (max_references == 0 || count < max_references)) { 12877 // Only look at all JSObjects. 12878 if (heap_obj->IsJSObject()) { 12879 JSObject* obj = JSObject::cast(heap_obj); 12880 if (obj->map()->constructor() == constructor) { 12881 // Valid reference found add to instance array if supplied an update 12882 // count. 12883 if (instances != NULL && count < instances_size) { 12884 instances->set(count, obj); 12885 } 12886 count++; 12887 } 12888 } 12889 } 12890 12891 // Return the number of referencing objects found. 12892 return count; 12893 } 12894 12895 12896 // Scan the heap for objects constructed by a specific function. 12897 // args[0]: the constructor to find instances of 12898 // args[1]: the the maximum number of objects to return 12899 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) { 12900 SealHandleScope shs(isolate); 12901 ASSERT(args.length() == 2); 12902 12903 // First perform a full GC in order to avoid dead objects. 12904 Heap* heap = isolate->heap(); 12905 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); 12906 12907 // Check parameters. 12908 CONVERT_ARG_CHECKED(JSFunction, constructor, 0); 12909 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 12910 RUNTIME_ASSERT(max_references >= 0); 12911 12912 // Get the number of referencing objects. 12913 int count; 12914 HeapIterator heap_iterator(heap); 12915 count = DebugConstructedBy(&heap_iterator, 12916 constructor, 12917 max_references, 12918 NULL, 12919 0); 12920 12921 // Allocate an array to hold the result. 12922 Object* object; 12923 { MaybeObject* maybe_object = heap->AllocateFixedArray(count); 12924 if (!maybe_object->ToObject(&object)) return maybe_object; 12925 } 12926 FixedArray* instances = FixedArray::cast(object); 12927 12928 ASSERT(HEAP->IsHeapIterable()); 12929 // Fill the referencing objects. 12930 HeapIterator heap_iterator2(heap); 12931 count = DebugConstructedBy(&heap_iterator2, 12932 constructor, 12933 max_references, 12934 instances, 12935 count); 12936 12937 // Return result as JS array. 12938 Object* result; 12939 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( 12940 isolate->context()->native_context()->array_function()); 12941 if (!maybe_result->ToObject(&result)) return maybe_result; 12942 } 12943 return JSArray::cast(result)->SetContent(instances); 12944 } 12945 12946 12947 // Find the effective prototype object as returned by __proto__. 12948 // args[0]: the object to find the prototype for. 12949 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) { 12950 SealHandleScope shs(isolate); 12951 ASSERT(args.length() == 1); 12952 CONVERT_ARG_CHECKED(JSObject, obj, 0); 12953 return GetPrototypeSkipHiddenPrototypes(isolate, obj); 12954 } 12955 12956 12957 // Patches script source (should be called upon BeforeCompile event). 12958 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { 12959 HandleScope scope(isolate); 12960 ASSERT(args.length() == 2); 12961 12962 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 12963 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 12964 12965 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); 12966 Handle<Script> script(Script::cast(script_wrapper->value())); 12967 12968 int compilation_state = script->compilation_state(); 12969 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); 12970 script->set_source(*source); 12971 12972 return isolate->heap()->undefined_value(); 12973 } 12974 12975 12976 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { 12977 SealHandleScope shs(isolate); 12978 ASSERT(args.length() == 0); 12979 CPU::DebugBreak(); 12980 return isolate->heap()->undefined_value(); 12981 } 12982 12983 12984 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { 12985 HandleScope scope(isolate); 12986 #ifdef DEBUG 12987 ASSERT(args.length() == 1); 12988 // Get the function and make sure it is compiled. 12989 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 12990 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { 12991 return Failure::Exception(); 12992 } 12993 func->code()->PrintLn(); 12994 #endif // DEBUG 12995 return isolate->heap()->undefined_value(); 12996 } 12997 12998 12999 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { 13000 HandleScope scope(isolate); 13001 #ifdef DEBUG 13002 ASSERT(args.length() == 1); 13003 // Get the function and make sure it is compiled. 13004 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 13005 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { 13006 return Failure::Exception(); 13007 } 13008 func->shared()->construct_stub()->PrintLn(); 13009 #endif // DEBUG 13010 return isolate->heap()->undefined_value(); 13011 } 13012 13013 13014 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) { 13015 SealHandleScope shs(isolate); 13016 ASSERT(args.length() == 1); 13017 13018 CONVERT_ARG_CHECKED(JSFunction, f, 0); 13019 return f->shared()->inferred_name(); 13020 } 13021 13022 13023 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, 13024 Script* script, 13025 FixedArray* buffer) { 13026 DisallowHeapAllocation no_allocation; 13027 int counter = 0; 13028 int buffer_size = buffer->length(); 13029 for (HeapObject* obj = iterator->next(); 13030 obj != NULL; 13031 obj = iterator->next()) { 13032 ASSERT(obj != NULL); 13033 if (!obj->IsSharedFunctionInfo()) { 13034 continue; 13035 } 13036 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 13037 if (shared->script() != script) { 13038 continue; 13039 } 13040 if (counter < buffer_size) { 13041 buffer->set(counter, shared); 13042 } 13043 counter++; 13044 } 13045 return counter; 13046 } 13047 13048 13049 // For a script finds all SharedFunctionInfo's in the heap that points 13050 // to this script. Returns JSArray of SharedFunctionInfo wrapped 13051 // in OpaqueReferences. 13052 RUNTIME_FUNCTION(MaybeObject*, 13053 Runtime_LiveEditFindSharedFunctionInfosForScript) { 13054 HandleScope scope(isolate); 13055 CHECK(isolate->debugger()->live_edit_enabled()); 13056 ASSERT(args.length() == 1); 13057 CONVERT_ARG_CHECKED(JSValue, script_value, 0); 13058 13059 RUNTIME_ASSERT(script_value->value()->IsScript()); 13060 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); 13061 13062 const int kBufferSize = 32; 13063 13064 Handle<FixedArray> array; 13065 array = isolate->factory()->NewFixedArray(kBufferSize); 13066 int number; 13067 Heap* heap = isolate->heap(); 13068 { 13069 heap->EnsureHeapIsIterable(); 13070 DisallowHeapAllocation no_allocation; 13071 HeapIterator heap_iterator(heap); 13072 Script* scr = *script; 13073 FixedArray* arr = *array; 13074 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13075 } 13076 if (number > kBufferSize) { 13077 array = isolate->factory()->NewFixedArray(number); 13078 heap->EnsureHeapIsIterable(); 13079 DisallowHeapAllocation no_allocation; 13080 HeapIterator heap_iterator(heap); 13081 Script* scr = *script; 13082 FixedArray* arr = *array; 13083 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13084 } 13085 13086 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); 13087 result->set_length(Smi::FromInt(number)); 13088 13089 LiveEdit::WrapSharedFunctionInfos(result); 13090 13091 return *result; 13092 } 13093 13094 13095 // For a script calculates compilation information about all its functions. 13096 // The script source is explicitly specified by the second argument. 13097 // The source of the actual script is not used, however it is important that 13098 // all generated code keeps references to this particular instance of script. 13099 // Returns a JSArray of compilation infos. The array is ordered so that 13100 // each function with all its descendant is always stored in a continues range 13101 // with the function itself going first. The root function is a script function. 13102 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { 13103 HandleScope scope(isolate); 13104 CHECK(isolate->debugger()->live_edit_enabled()); 13105 ASSERT(args.length() == 2); 13106 CONVERT_ARG_CHECKED(JSValue, script, 0); 13107 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13108 13109 RUNTIME_ASSERT(script->value()->IsScript()); 13110 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 13111 13112 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); 13113 13114 if (isolate->has_pending_exception()) { 13115 return Failure::Exception(); 13116 } 13117 13118 return result; 13119 } 13120 13121 13122 // Changes the source of the script to a new_source. 13123 // If old_script_name is provided (i.e. is a String), also creates a copy of 13124 // the script with its original source and sends notification to debugger. 13125 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) { 13126 HandleScope scope(isolate); 13127 CHECK(isolate->debugger()->live_edit_enabled()); 13128 ASSERT(args.length() == 3); 13129 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); 13130 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); 13131 Handle<Object> old_script_name(args[2], isolate); 13132 13133 RUNTIME_ASSERT(original_script_value->value()->IsScript()); 13134 Handle<Script> original_script(Script::cast(original_script_value->value())); 13135 13136 Object* old_script = LiveEdit::ChangeScriptSource(original_script, 13137 new_source, 13138 old_script_name); 13139 13140 if (old_script->IsScript()) { 13141 Handle<Script> script_handle(Script::cast(old_script)); 13142 return *(GetScriptWrapper(script_handle)); 13143 } else { 13144 return isolate->heap()->null_value(); 13145 } 13146 } 13147 13148 13149 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) { 13150 HandleScope scope(isolate); 13151 CHECK(isolate->debugger()->live_edit_enabled()); 13152 ASSERT(args.length() == 1); 13153 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); 13154 return LiveEdit::FunctionSourceUpdated(shared_info); 13155 } 13156 13157 13158 // Replaces code of SharedFunctionInfo with a new one. 13159 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) { 13160 HandleScope scope(isolate); 13161 CHECK(isolate->debugger()->live_edit_enabled()); 13162 ASSERT(args.length() == 2); 13163 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); 13164 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); 13165 13166 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); 13167 } 13168 13169 13170 // Connects SharedFunctionInfo to another script. 13171 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { 13172 HandleScope scope(isolate); 13173 CHECK(isolate->debugger()->live_edit_enabled()); 13174 ASSERT(args.length() == 2); 13175 Handle<Object> function_object(args[0], isolate); 13176 Handle<Object> script_object(args[1], isolate); 13177 13178 if (function_object->IsJSValue()) { 13179 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); 13180 if (script_object->IsJSValue()) { 13181 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); 13182 Script* script = Script::cast(JSValue::cast(*script_object)->value()); 13183 script_object = Handle<Object>(script, isolate); 13184 } 13185 13186 LiveEdit::SetFunctionScript(function_wrapper, script_object); 13187 } else { 13188 // Just ignore this. We may not have a SharedFunctionInfo for some functions 13189 // and we check it in this function. 13190 } 13191 13192 return isolate->heap()->undefined_value(); 13193 } 13194 13195 13196 // In a code of a parent function replaces original function as embedded object 13197 // with a substitution one. 13198 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { 13199 HandleScope scope(isolate); 13200 CHECK(isolate->debugger()->live_edit_enabled()); 13201 ASSERT(args.length() == 3); 13202 13203 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); 13204 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); 13205 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); 13206 13207 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, 13208 subst_wrapper); 13209 13210 return isolate->heap()->undefined_value(); 13211 } 13212 13213 13214 // Updates positions of a shared function info (first parameter) according 13215 // to script source change. Text change is described in second parameter as 13216 // array of groups of 3 numbers: 13217 // (change_begin, change_end, change_end_new_position). 13218 // Each group describes a change in text; groups are sorted by change_begin. 13219 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { 13220 HandleScope scope(isolate); 13221 CHECK(isolate->debugger()->live_edit_enabled()); 13222 ASSERT(args.length() == 2); 13223 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13224 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); 13225 13226 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); 13227 } 13228 13229 13230 // For array of SharedFunctionInfo's (each wrapped in JSValue) 13231 // checks that none of them have activations on stacks (of any thread). 13232 // Returns array of the same length with corresponding results of 13233 // LiveEdit::FunctionPatchabilityStatus type. 13234 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { 13235 HandleScope scope(isolate); 13236 CHECK(isolate->debugger()->live_edit_enabled()); 13237 ASSERT(args.length() == 2); 13238 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13239 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); 13240 13241 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); 13242 } 13243 13244 13245 // Compares 2 strings line-by-line, then token-wise and returns diff in form 13246 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list 13247 // of diff chunks. 13248 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { 13249 HandleScope scope(isolate); 13250 CHECK(isolate->debugger()->live_edit_enabled()); 13251 ASSERT(args.length() == 2); 13252 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); 13253 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); 13254 13255 return *LiveEdit::CompareStrings(s1, s2); 13256 } 13257 13258 13259 // Restarts a call frame and completely drops all frames above. 13260 // Returns true if successful. Otherwise returns undefined or an error message. 13261 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) { 13262 HandleScope scope(isolate); 13263 CHECK(isolate->debugger()->live_edit_enabled()); 13264 ASSERT(args.length() == 2); 13265 13266 // Check arguments. 13267 Object* check; 13268 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 13269 RUNTIME_ARGUMENTS(isolate, args)); 13270 if (!maybe_check->ToObject(&check)) return maybe_check; 13271 } 13272 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 13273 Heap* heap = isolate->heap(); 13274 13275 // Find the relevant frame with the requested index. 13276 StackFrame::Id id = isolate->debug()->break_frame_id(); 13277 if (id == StackFrame::NO_ID) { 13278 // If there are no JavaScript stack frames return undefined. 13279 return heap->undefined_value(); 13280 } 13281 13282 int count = 0; 13283 JavaScriptFrameIterator it(isolate, id); 13284 for (; !it.done(); it.Advance()) { 13285 if (index < count + it.frame()->GetInlineCount()) break; 13286 count += it.frame()->GetInlineCount(); 13287 } 13288 if (it.done()) return heap->undefined_value(); 13289 13290 const char* error_message = LiveEdit::RestartFrame(it.frame()); 13291 if (error_message) { 13292 return *(isolate->factory()->InternalizeUtf8String(error_message)); 13293 } 13294 return heap->true_value(); 13295 } 13296 13297 13298 // A testing entry. Returns statement position which is the closest to 13299 // source_position. 13300 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { 13301 HandleScope scope(isolate); 13302 CHECK(isolate->debugger()->live_edit_enabled()); 13303 ASSERT(args.length() == 2); 13304 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13305 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 13306 13307 Handle<Code> code(function->code(), isolate); 13308 13309 if (code->kind() != Code::FUNCTION && 13310 code->kind() != Code::OPTIMIZED_FUNCTION) { 13311 return isolate->heap()->undefined_value(); 13312 } 13313 13314 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); 13315 int closest_pc = 0; 13316 int distance = kMaxInt; 13317 while (!it.done()) { 13318 int statement_position = static_cast<int>(it.rinfo()->data()); 13319 // Check if this break point is closer that what was previously found. 13320 if (source_position <= statement_position && 13321 statement_position - source_position < distance) { 13322 closest_pc = 13323 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 13324 distance = statement_position - source_position; 13325 // Check whether we can't get any closer. 13326 if (distance == 0) break; 13327 } 13328 it.next(); 13329 } 13330 13331 return Smi::FromInt(closest_pc); 13332 } 13333 13334 13335 // Calls specified function with or without entering the debugger. 13336 // This is used in unit tests to run code as if debugger is entered or simply 13337 // to have a stack with C++ frame in the middle. 13338 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) { 13339 HandleScope scope(isolate); 13340 ASSERT(args.length() == 2); 13341 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13342 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); 13343 13344 Handle<Object> result; 13345 bool pending_exception; 13346 { 13347 if (without_debugger) { 13348 result = Execution::Call(function, isolate->global_object(), 0, NULL, 13349 &pending_exception); 13350 } else { 13351 EnterDebugger enter_debugger; 13352 result = Execution::Call(function, isolate->global_object(), 0, NULL, 13353 &pending_exception); 13354 } 13355 } 13356 if (!pending_exception) { 13357 return *result; 13358 } else { 13359 return Failure::Exception(); 13360 } 13361 } 13362 13363 13364 // Sets a v8 flag. 13365 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) { 13366 SealHandleScope shs(isolate); 13367 CONVERT_ARG_CHECKED(String, arg, 0); 13368 SmartArrayPointer<char> flags = 13369 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 13370 FlagList::SetFlagsFromString(*flags, StrLength(*flags)); 13371 return isolate->heap()->undefined_value(); 13372 } 13373 13374 13375 // Performs a GC. 13376 // Presently, it only does a full GC. 13377 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) { 13378 SealHandleScope shs(isolate); 13379 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); 13380 return isolate->heap()->undefined_value(); 13381 } 13382 13383 13384 // Gets the current heap usage. 13385 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { 13386 SealHandleScope shs(isolate); 13387 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 13388 if (!Smi::IsValid(usage)) { 13389 return *isolate->factory()->NewNumberFromInt(usage); 13390 } 13391 return Smi::FromInt(usage); 13392 } 13393 13394 #endif // ENABLE_DEBUGGER_SUPPORT 13395 13396 13397 #ifdef V8_I18N_SUPPORT 13398 RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { 13399 HandleScope scope(isolate); 13400 13401 ASSERT(args.length() == 1); 13402 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); 13403 13404 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); 13405 13406 // Return value which denotes invalid language tag. 13407 const char* const kInvalidTag = "invalid-tag"; 13408 13409 UErrorCode error = U_ZERO_ERROR; 13410 char icu_result[ULOC_FULLNAME_CAPACITY]; 13411 int icu_length = 0; 13412 13413 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, 13414 &icu_length, &error); 13415 if (U_FAILURE(error) || icu_length == 0) { 13416 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); 13417 } 13418 13419 char result[ULOC_FULLNAME_CAPACITY]; 13420 13421 // Force strict BCP47 rules. 13422 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); 13423 13424 if (U_FAILURE(error)) { 13425 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); 13426 } 13427 13428 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); 13429 } 13430 13431 13432 RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { 13433 HandleScope scope(isolate); 13434 13435 ASSERT(args.length() == 1); 13436 CONVERT_ARG_HANDLE_CHECKED(String, service, 0); 13437 13438 const icu::Locale* available_locales = NULL; 13439 int32_t count = 0; 13440 13441 if (service->IsUtf8EqualTo(CStrVector("collator"))) { 13442 available_locales = icu::Collator::getAvailableLocales(count); 13443 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { 13444 available_locales = icu::NumberFormat::getAvailableLocales(count); 13445 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { 13446 available_locales = icu::DateFormat::getAvailableLocales(count); 13447 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { 13448 available_locales = icu::BreakIterator::getAvailableLocales(count); 13449 } 13450 13451 UErrorCode error = U_ZERO_ERROR; 13452 char result[ULOC_FULLNAME_CAPACITY]; 13453 Handle<JSObject> locales = 13454 isolate->factory()->NewJSObject(isolate->object_function()); 13455 13456 for (int32_t i = 0; i < count; ++i) { 13457 const char* icu_name = available_locales[i].getName(); 13458 13459 error = U_ZERO_ERROR; 13460 // No need to force strict BCP47 rules. 13461 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13462 if (U_FAILURE(error)) { 13463 // This shouldn't happen, but lets not break the user. 13464 continue; 13465 } 13466 13467 RETURN_IF_EMPTY_HANDLE(isolate, 13468 JSObject::SetLocalPropertyIgnoreAttributes( 13469 locales, 13470 isolate->factory()->NewStringFromAscii(CStrVector(result)), 13471 isolate->factory()->NewNumber(i), 13472 NONE)); 13473 } 13474 13475 return *locales; 13476 } 13477 13478 13479 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { 13480 SealHandleScope shs(isolate); 13481 13482 ASSERT(args.length() == 0); 13483 13484 icu::Locale default_locale; 13485 13486 // Set the locale 13487 char result[ULOC_FULLNAME_CAPACITY]; 13488 UErrorCode status = U_ZERO_ERROR; 13489 uloc_toLanguageTag( 13490 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); 13491 if (U_SUCCESS(status)) { 13492 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); 13493 } 13494 13495 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und")); 13496 } 13497 13498 13499 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { 13500 HandleScope scope(isolate); 13501 13502 ASSERT(args.length() == 1); 13503 13504 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); 13505 13506 uint32_t length = static_cast<uint32_t>(input->length()->Number()); 13507 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length); 13508 Handle<Name> maximized = 13509 isolate->factory()->NewStringFromAscii(CStrVector("maximized")); 13510 Handle<Name> base = 13511 isolate->factory()->NewStringFromAscii(CStrVector("base")); 13512 for (unsigned int i = 0; i < length; ++i) { 13513 MaybeObject* maybe_string = input->GetElement(i); 13514 Object* locale_id; 13515 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) { 13516 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13517 } 13518 13519 v8::String::Utf8Value utf8_locale_id( 13520 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id)))); 13521 13522 UErrorCode error = U_ZERO_ERROR; 13523 13524 // Convert from BCP47 to ICU format. 13525 // de-DE-u-co-phonebk -> de_DE@collation=phonebook 13526 char icu_locale[ULOC_FULLNAME_CAPACITY]; 13527 int icu_locale_length = 0; 13528 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, 13529 &icu_locale_length, &error); 13530 if (U_FAILURE(error) || icu_locale_length == 0) { 13531 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13532 } 13533 13534 // Maximize the locale. 13535 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook 13536 char icu_max_locale[ULOC_FULLNAME_CAPACITY]; 13537 uloc_addLikelySubtags( 13538 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13539 13540 // Remove extensions from maximized locale. 13541 // de_Latn_DE@collation=phonebook -> de_Latn_DE 13542 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; 13543 uloc_getBaseName( 13544 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13545 13546 // Get original name without extensions. 13547 // de_DE@collation=phonebook -> de_DE 13548 char icu_base_locale[ULOC_FULLNAME_CAPACITY]; 13549 uloc_getBaseName( 13550 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); 13551 13552 // Convert from ICU locale format to BCP47 format. 13553 // de_Latn_DE -> de-Latn-DE 13554 char base_max_locale[ULOC_FULLNAME_CAPACITY]; 13555 uloc_toLanguageTag(icu_base_max_locale, base_max_locale, 13556 ULOC_FULLNAME_CAPACITY, FALSE, &error); 13557 13558 // de_DE -> de-DE 13559 char base_locale[ULOC_FULLNAME_CAPACITY]; 13560 uloc_toLanguageTag( 13561 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13562 13563 if (U_FAILURE(error)) { 13564 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13565 } 13566 13567 Handle<JSObject> result = 13568 isolate->factory()->NewJSObject(isolate->object_function()); 13569 RETURN_IF_EMPTY_HANDLE(isolate, 13570 JSObject::SetLocalPropertyIgnoreAttributes( 13571 result, 13572 maximized, 13573 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)), 13574 NONE)); 13575 RETURN_IF_EMPTY_HANDLE(isolate, 13576 JSObject::SetLocalPropertyIgnoreAttributes( 13577 result, 13578 base, 13579 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)), 13580 NONE)); 13581 output->set(i, *result); 13582 } 13583 13584 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output); 13585 result->set_length(Smi::FromInt(length)); 13586 return *result; 13587 } 13588 13589 13590 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { 13591 HandleScope scope(isolate); 13592 13593 ASSERT(args.length() == 3); 13594 13595 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 13596 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 13597 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 13598 13599 Handle<ObjectTemplateInfo> date_format_template = 13600 I18N::GetTemplate(isolate); 13601 13602 // Create an empty object wrapper. 13603 bool has_pending_exception = false; 13604 Handle<JSObject> local_object = Execution::InstantiateObject( 13605 date_format_template, &has_pending_exception); 13606 if (has_pending_exception) { 13607 ASSERT(isolate->has_pending_exception()); 13608 return Failure::Exception(); 13609 } 13610 13611 // Set date time formatter as internal field of the resulting JS object. 13612 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( 13613 isolate, locale, options, resolved); 13614 13615 if (!date_format) return isolate->ThrowIllegalOperation(); 13616 13617 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); 13618 13619 RETURN_IF_EMPTY_HANDLE(isolate, 13620 JSObject::SetLocalPropertyIgnoreAttributes( 13621 local_object, 13622 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")), 13623 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 13624 NONE)); 13625 13626 Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), 13627 v8::Utils::ToLocal(local_object)); 13628 // Make object handle weak so we can delete the data format once GC kicks in. 13629 wrapper.MakeWeak<void>(NULL, &DateFormat::DeleteDateFormat); 13630 wrapper.ClearAndLeak(); 13631 return *local_object; 13632 } 13633 13634 13635 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { 13636 HandleScope scope(isolate); 13637 13638 ASSERT(args.length() == 2); 13639 13640 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 13641 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); 13642 13643 bool has_pending_exception = false; 13644 Handle<Object> value = Execution::ToNumber(date, &has_pending_exception); 13645 if (has_pending_exception) { 13646 ASSERT(isolate->has_pending_exception()); 13647 return Failure::Exception(); 13648 } 13649 13650 icu::SimpleDateFormat* date_format = 13651 DateFormat::UnpackDateFormat(isolate, date_format_holder); 13652 if (!date_format) return isolate->ThrowIllegalOperation(); 13653 13654 icu::UnicodeString result; 13655 date_format->format(value->Number(), result); 13656 13657 return *isolate->factory()->NewStringFromTwoByte( 13658 Vector<const uint16_t>( 13659 reinterpret_cast<const uint16_t*>(result.getBuffer()), 13660 result.length())); 13661 } 13662 13663 13664 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) { 13665 HandleScope scope(isolate); 13666 13667 ASSERT(args.length() == 2); 13668 13669 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 13670 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1); 13671 13672 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string)); 13673 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date)); 13674 icu::SimpleDateFormat* date_format = 13675 DateFormat::UnpackDateFormat(isolate, date_format_holder); 13676 if (!date_format) return isolate->ThrowIllegalOperation(); 13677 13678 UErrorCode status = U_ZERO_ERROR; 13679 UDate date = date_format->parse(u_date, status); 13680 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 13681 13682 bool has_pending_exception = false; 13683 Handle<JSDate> result = Handle<JSDate>::cast( 13684 Execution::NewDate(static_cast<double>(date), &has_pending_exception)); 13685 if (has_pending_exception) { 13686 ASSERT(isolate->has_pending_exception()); 13687 return Failure::Exception(); 13688 } 13689 return *result; 13690 } 13691 13692 13693 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { 13694 HandleScope scope(isolate); 13695 13696 ASSERT(args.length() == 3); 13697 13698 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 13699 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 13700 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 13701 13702 Handle<ObjectTemplateInfo> number_format_template = 13703 I18N::GetTemplate(isolate); 13704 13705 // Create an empty object wrapper. 13706 bool has_pending_exception = false; 13707 Handle<JSObject> local_object = Execution::InstantiateObject( 13708 number_format_template, &has_pending_exception); 13709 if (has_pending_exception) { 13710 ASSERT(isolate->has_pending_exception()); 13711 return Failure::Exception(); 13712 } 13713 13714 // Set number formatter as internal field of the resulting JS object. 13715 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( 13716 isolate, locale, options, resolved); 13717 13718 if (!number_format) return isolate->ThrowIllegalOperation(); 13719 13720 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); 13721 13722 RETURN_IF_EMPTY_HANDLE(isolate, 13723 JSObject::SetLocalPropertyIgnoreAttributes( 13724 local_object, 13725 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")), 13726 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 13727 NONE)); 13728 13729 Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), 13730 v8::Utils::ToLocal(local_object)); 13731 // Make object handle weak so we can delete the number format once GC kicks 13732 // in. 13733 wrapper.MakeWeak<void>(NULL, &NumberFormat::DeleteNumberFormat); 13734 wrapper.ClearAndLeak(); 13735 return *local_object; 13736 } 13737 13738 13739 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { 13740 HandleScope scope(isolate); 13741 13742 ASSERT(args.length() == 2); 13743 13744 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 13745 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); 13746 13747 bool has_pending_exception = false; 13748 Handle<Object> value = Execution::ToNumber(number, &has_pending_exception); 13749 if (has_pending_exception) { 13750 ASSERT(isolate->has_pending_exception()); 13751 return Failure::Exception(); 13752 } 13753 13754 icu::DecimalFormat* number_format = 13755 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 13756 if (!number_format) return isolate->ThrowIllegalOperation(); 13757 13758 icu::UnicodeString result; 13759 number_format->format(value->Number(), result); 13760 13761 return *isolate->factory()->NewStringFromTwoByte( 13762 Vector<const uint16_t>( 13763 reinterpret_cast<const uint16_t*>(result.getBuffer()), 13764 result.length())); 13765 } 13766 13767 13768 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) { 13769 HandleScope scope(isolate); 13770 13771 ASSERT(args.length() == 2); 13772 13773 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 13774 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1); 13775 13776 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string)); 13777 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number)); 13778 icu::DecimalFormat* number_format = 13779 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 13780 if (!number_format) return isolate->ThrowIllegalOperation(); 13781 13782 UErrorCode status = U_ZERO_ERROR; 13783 icu::Formattable result; 13784 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 13785 // to be part of Chrome. 13786 // TODO(cira): Include currency parsing code using parseCurrency call. 13787 // We need to check if the formatter parses all currencies or only the 13788 // one it was constructed with (it will impact the API - how to return ISO 13789 // code and the value). 13790 number_format->parse(u_number, result, status); 13791 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 13792 13793 switch (result.getType()) { 13794 case icu::Formattable::kDouble: 13795 return *isolate->factory()->NewNumber(result.getDouble()); 13796 case icu::Formattable::kLong: 13797 return *isolate->factory()->NewNumberFromInt(result.getLong()); 13798 case icu::Formattable::kInt64: 13799 return *isolate->factory()->NewNumber( 13800 static_cast<double>(result.getInt64())); 13801 default: 13802 return isolate->heap()->undefined_value(); 13803 } 13804 } 13805 13806 13807 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { 13808 HandleScope scope(isolate); 13809 13810 ASSERT(args.length() == 3); 13811 13812 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 13813 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 13814 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 13815 13816 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); 13817 13818 // Create an empty object wrapper. 13819 bool has_pending_exception = false; 13820 Handle<JSObject> local_object = Execution::InstantiateObject( 13821 collator_template, &has_pending_exception); 13822 if (has_pending_exception) { 13823 ASSERT(isolate->has_pending_exception()); 13824 return Failure::Exception(); 13825 } 13826 13827 // Set collator as internal field of the resulting JS object. 13828 icu::Collator* collator = Collator::InitializeCollator( 13829 isolate, locale, options, resolved); 13830 13831 if (!collator) return isolate->ThrowIllegalOperation(); 13832 13833 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); 13834 13835 RETURN_IF_EMPTY_HANDLE(isolate, 13836 JSObject::SetLocalPropertyIgnoreAttributes( 13837 local_object, 13838 isolate->factory()->NewStringFromAscii(CStrVector("collator")), 13839 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 13840 NONE)); 13841 13842 Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate), 13843 v8::Utils::ToLocal(local_object)); 13844 // Make object handle weak so we can delete the collator once GC kicks in. 13845 wrapper.MakeWeak<void>(NULL, &Collator::DeleteCollator); 13846 wrapper.ClearAndLeak(); 13847 return *local_object; 13848 } 13849 13850 13851 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) { 13852 HandleScope scope(isolate); 13853 13854 ASSERT(args.length() == 3); 13855 13856 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0); 13857 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1); 13858 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2); 13859 13860 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder); 13861 if (!collator) return isolate->ThrowIllegalOperation(); 13862 13863 v8::String::Value string_value1(v8::Utils::ToLocal(string1)); 13864 v8::String::Value string_value2(v8::Utils::ToLocal(string2)); 13865 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1); 13866 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2); 13867 UErrorCode status = U_ZERO_ERROR; 13868 UCollationResult result = collator->compare(u_string1, 13869 string_value1.length(), 13870 u_string2, 13871 string_value2.length(), 13872 status); 13873 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation(); 13874 13875 return *isolate->factory()->NewNumberFromInt(result); 13876 } 13877 #endif // V8_I18N_SUPPORT 13878 13879 13880 // Finds the script object from the script data. NOTE: This operation uses 13881 // heap traversal to find the function generated for the source position 13882 // for the requested break point. For lazily compiled functions several heap 13883 // traversals might be required rendering this operation as a rather slow 13884 // operation. However for setting break points which is normally done through 13885 // some kind of user interaction the performance is not crucial. 13886 static Handle<Object> Runtime_GetScriptFromScriptName( 13887 Handle<String> script_name) { 13888 // Scan the heap for Script objects to find the script with the requested 13889 // script data. 13890 Handle<Script> script; 13891 Factory* factory = script_name->GetIsolate()->factory(); 13892 Heap* heap = script_name->GetHeap(); 13893 heap->EnsureHeapIsIterable(); 13894 DisallowHeapAllocation no_allocation_during_heap_iteration; 13895 HeapIterator iterator(heap); 13896 HeapObject* obj = NULL; 13897 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 13898 // If a script is found check if it has the script data requested. 13899 if (obj->IsScript()) { 13900 if (Script::cast(obj)->name()->IsString()) { 13901 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 13902 script = Handle<Script>(Script::cast(obj)); 13903 } 13904 } 13905 } 13906 } 13907 13908 // If no script with the requested script data is found return undefined. 13909 if (script.is_null()) return factory->undefined_value(); 13910 13911 // Return the script found. 13912 return GetScriptWrapper(script); 13913 } 13914 13915 13916 // Get the script object from script data. NOTE: Regarding performance 13917 // see the NOTE for GetScriptFromScriptData. 13918 // args[0]: script data for the script to find the source for 13919 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { 13920 HandleScope scope(isolate); 13921 13922 ASSERT(args.length() == 1); 13923 13924 CONVERT_ARG_CHECKED(String, script_name, 0); 13925 13926 // Find the requested script. 13927 Handle<Object> result = 13928 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 13929 return *result; 13930 } 13931 13932 13933 // Collect the raw data for a stack trace. Returns an array of 4 13934 // element segments each containing a receiver, function, code and 13935 // native code offset. 13936 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { 13937 HandleScope scope(isolate); 13938 ASSERT_EQ(args.length(), 3); 13939 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 13940 Handle<Object> caller = args.at<Object>(1); 13941 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); 13942 13943 // Optionally capture a more detailed stack trace for the message. 13944 isolate->CaptureAndSetDetailedStackTrace(error_object); 13945 // Capture a simple stack trace for the stack property. 13946 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit); 13947 } 13948 13949 13950 // Retrieve the stack trace. This is the raw stack trace that yet has to 13951 // be formatted. Since we only need this once, clear it afterwards. 13952 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) { 13953 HandleScope scope(isolate); 13954 ASSERT_EQ(args.length(), 1); 13955 CONVERT_ARG_CHECKED(JSObject, error_object, 0); 13956 String* key = isolate->heap()->hidden_stack_trace_string(); 13957 Object* result = error_object->GetHiddenProperty(key); 13958 if (result->IsTheHole()) return isolate->heap()->undefined_value(); 13959 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined()); 13960 error_object->DeleteHiddenProperty(key); 13961 return result; 13962 } 13963 13964 13965 // Returns V8 version as a string. 13966 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { 13967 SealHandleScope shs(isolate); 13968 ASSERT_EQ(args.length(), 0); 13969 13970 const char* version_string = v8::V8::GetVersion(); 13971 13972 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string), 13973 NOT_TENURED); 13974 } 13975 13976 13977 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { 13978 SealHandleScope shs(isolate); 13979 ASSERT(args.length() == 2); 13980 OS::PrintError("abort: %s\n", 13981 reinterpret_cast<char*>(args[0]) + args.smi_at(1)); 13982 isolate->PrintStack(stderr); 13983 OS::Abort(); 13984 UNREACHABLE(); 13985 return NULL; 13986 } 13987 13988 13989 RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) { 13990 HandleScope scope(isolate); 13991 ASSERT(args.length() == 1); 13992 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 13993 FlattenString(str); 13994 return isolate->heap()->undefined_value(); 13995 } 13996 13997 13998 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) { 13999 HandleScope scope(isolate); 14000 ASSERT(args.length() == 0); 14001 isolate->heap()->NotifyContextDisposed(); 14002 return isolate->heap()->undefined_value(); 14003 } 14004 14005 14006 RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) { 14007 HandleScope scope(isolate); 14008 ASSERT(args.length() == 1); 14009 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 14010 if (!object->IsJSObject()) return Smi::FromInt(0); 14011 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 14012 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); 14013 JSObject::MigrateInstance(js_object); 14014 return *object; 14015 } 14016 14017 14018 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { 14019 SealHandleScope shs(isolate); 14020 // This is only called from codegen, so checks might be more lax. 14021 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); 14022 Object* key = args[1]; 14023 14024 int finger_index = cache->finger_index(); 14025 Object* o = cache->get(finger_index); 14026 if (o == key) { 14027 // The fastest case: hit the same place again. 14028 return cache->get(finger_index + 1); 14029 } 14030 14031 for (int i = finger_index - 2; 14032 i >= JSFunctionResultCache::kEntriesIndex; 14033 i -= 2) { 14034 o = cache->get(i); 14035 if (o == key) { 14036 cache->set_finger_index(i); 14037 return cache->get(i + 1); 14038 } 14039 } 14040 14041 int size = cache->size(); 14042 ASSERT(size <= cache->length()); 14043 14044 for (int i = size - 2; i > finger_index; i -= 2) { 14045 o = cache->get(i); 14046 if (o == key) { 14047 cache->set_finger_index(i); 14048 return cache->get(i + 1); 14049 } 14050 } 14051 14052 // There is no value in the cache. Invoke the function and cache result. 14053 HandleScope scope(isolate); 14054 14055 Handle<JSFunctionResultCache> cache_handle(cache); 14056 Handle<Object> key_handle(key, isolate); 14057 Handle<Object> value; 14058 { 14059 Handle<JSFunction> factory(JSFunction::cast( 14060 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); 14061 // TODO(antonm): consider passing a receiver when constructing a cache. 14062 Handle<Object> receiver(isolate->native_context()->global_object(), 14063 isolate); 14064 // This handle is nor shared, nor used later, so it's safe. 14065 Handle<Object> argv[] = { key_handle }; 14066 bool pending_exception; 14067 value = Execution::Call(factory, 14068 receiver, 14069 ARRAY_SIZE(argv), 14070 argv, 14071 &pending_exception); 14072 if (pending_exception) return Failure::Exception(); 14073 } 14074 14075 #ifdef VERIFY_HEAP 14076 if (FLAG_verify_heap) { 14077 cache_handle->JSFunctionResultCacheVerify(); 14078 } 14079 #endif 14080 14081 // Function invocation may have cleared the cache. Reread all the data. 14082 finger_index = cache_handle->finger_index(); 14083 size = cache_handle->size(); 14084 14085 // If we have spare room, put new data into it, otherwise evict post finger 14086 // entry which is likely to be the least recently used. 14087 int index = -1; 14088 if (size < cache_handle->length()) { 14089 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); 14090 index = size; 14091 } else { 14092 index = finger_index + JSFunctionResultCache::kEntrySize; 14093 if (index == cache_handle->length()) { 14094 index = JSFunctionResultCache::kEntriesIndex; 14095 } 14096 } 14097 14098 ASSERT(index % 2 == 0); 14099 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); 14100 ASSERT(index < cache_handle->length()); 14101 14102 cache_handle->set(index, *key_handle); 14103 cache_handle->set(index + 1, *value); 14104 cache_handle->set_finger_index(index); 14105 14106 #ifdef VERIFY_HEAP 14107 if (FLAG_verify_heap) { 14108 cache_handle->JSFunctionResultCacheVerify(); 14109 } 14110 #endif 14111 14112 return *value; 14113 } 14114 14115 14116 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { 14117 SealHandleScope shs(isolate); 14118 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14119 return Smi::FromInt(message->start_position()); 14120 } 14121 14122 14123 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { 14124 SealHandleScope shs(isolate); 14125 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14126 return message->script(); 14127 } 14128 14129 14130 #ifdef DEBUG 14131 // ListNatives is ONLY used by the fuzz-natives.js in debug mode 14132 // Exclude the code in release mode. 14133 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { 14134 HandleScope scope(isolate); 14135 ASSERT(args.length() == 0); 14136 #define COUNT_ENTRY(Name, argc, ressize) + 1 14137 int entry_count = 0 14138 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) 14139 INLINE_FUNCTION_LIST(COUNT_ENTRY) 14140 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY); 14141 #undef COUNT_ENTRY 14142 Factory* factory = isolate->factory(); 14143 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); 14144 int index = 0; 14145 bool inline_runtime_functions = false; 14146 #define ADD_ENTRY(Name, argc, ressize) \ 14147 { \ 14148 HandleScope inner(isolate); \ 14149 Handle<String> name; \ 14150 /* Inline runtime functions have an underscore in front of the name. */ \ 14151 if (inline_runtime_functions) { \ 14152 name = factory->NewStringFromAscii( \ 14153 Vector<const char>("_" #Name, StrLength("_" #Name))); \ 14154 } else { \ 14155 name = factory->NewStringFromAscii( \ 14156 Vector<const char>(#Name, StrLength(#Name))); \ 14157 } \ 14158 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ 14159 pair_elements->set(0, *name); \ 14160 pair_elements->set(1, Smi::FromInt(argc)); \ 14161 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ 14162 elements->set(index++, *pair); \ 14163 } 14164 inline_runtime_functions = false; 14165 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 14166 inline_runtime_functions = true; 14167 INLINE_FUNCTION_LIST(ADD_ENTRY) 14168 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) 14169 #undef ADD_ENTRY 14170 ASSERT_EQ(index, entry_count); 14171 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); 14172 return *result; 14173 } 14174 #endif 14175 14176 14177 RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) { 14178 SealHandleScope shs(isolate); 14179 ASSERT(args.length() == 2); 14180 CONVERT_ARG_CHECKED(String, format, 0); 14181 CONVERT_ARG_CHECKED(JSArray, elms, 1); 14182 DisallowHeapAllocation no_gc; 14183 String::FlatContent format_content = format->GetFlatContent(); 14184 RUNTIME_ASSERT(format_content.IsAscii()); 14185 Vector<const uint8_t> chars = format_content.ToOneByteVector(); 14186 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms); 14187 return isolate->heap()->undefined_value(); 14188 } 14189 14190 14191 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) { 14192 UNREACHABLE(); // implemented as macro in the parser 14193 return NULL; 14194 } 14195 14196 14197 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 14198 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \ 14199 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 14200 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 14201 } 14202 14203 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) 14204 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) 14205 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) 14206 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 14207 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) 14208 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 14209 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements) 14210 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements) 14211 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) 14212 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements) 14213 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements) 14214 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements) 14215 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements) 14216 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements) 14217 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements) 14218 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements) 14219 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements) 14220 // Properties test sitting with elements tests - not fooling anyone. 14221 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) 14222 14223 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 14224 14225 14226 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { 14227 SealHandleScope shs(isolate); 14228 ASSERT(args.length() == 2); 14229 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 14230 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 14231 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 14232 } 14233 14234 14235 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) { 14236 SealHandleScope shs(isolate); 14237 ASSERT(args.length() == 1); 14238 14239 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value(); 14240 JSReceiver* obj = JSReceiver::cast(args[0]); 14241 if (obj->IsJSGlobalProxy()) { 14242 Object* proto = obj->GetPrototype(); 14243 if (proto->IsNull()) return isolate->heap()->false_value(); 14244 ASSERT(proto->IsJSGlobalObject()); 14245 obj = JSReceiver::cast(proto); 14246 } 14247 return isolate->heap()->ToBoolean(obj->map()->is_observed()); 14248 } 14249 14250 14251 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { 14252 SealHandleScope shs(isolate); 14253 ASSERT(args.length() == 1); 14254 CONVERT_ARG_CHECKED(JSReceiver, obj, 0); 14255 if (obj->IsJSGlobalProxy()) { 14256 Object* proto = obj->GetPrototype(); 14257 if (proto->IsNull()) return isolate->heap()->undefined_value(); 14258 ASSERT(proto->IsJSGlobalObject()); 14259 obj = JSReceiver::cast(proto); 14260 } 14261 if (obj->IsJSProxy()) 14262 return isolate->heap()->undefined_value(); 14263 14264 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() && 14265 JSObject::cast(obj)->HasFastElements())); 14266 ASSERT(obj->IsJSObject()); 14267 return JSObject::cast(obj)->SetObserved(isolate); 14268 } 14269 14270 14271 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetObserverDeliveryPending) { 14272 SealHandleScope shs(isolate); 14273 ASSERT(args.length() == 0); 14274 isolate->set_observer_delivery_pending(true); 14275 return isolate->heap()->undefined_value(); 14276 } 14277 14278 14279 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) { 14280 SealHandleScope shs(isolate); 14281 ASSERT(args.length() == 0); 14282 return isolate->heap()->observation_state(); 14283 } 14284 14285 14286 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) { 14287 HandleScope scope(isolate); 14288 ASSERT(args.length() == 0); 14289 // TODO(adamk): Currently this runtime function is only called three times per 14290 // isolate. If it's called more often, the map should be moved into the 14291 // strong root list. 14292 Handle<Map> map = 14293 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); 14294 Handle<JSWeakMap> weakmap = 14295 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map)); 14296 return WeakCollectionInitialize(isolate, weakmap); 14297 } 14298 14299 14300 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) { 14301 SealHandleScope shs(isolate); 14302 ASSERT(args.length() == 1); 14303 Object* object = args[0]; 14304 if (object->IsJSGlobalProxy()) { 14305 object = object->GetPrototype(isolate); 14306 if (object->IsNull()) return isolate->heap()->undefined_value(); 14307 } 14308 return object; 14309 } 14310 14311 14312 static MaybeObject* ArrayConstructorCommon(Isolate* isolate, 14313 Handle<JSFunction> constructor, 14314 Handle<Object> type_info, 14315 Arguments* caller_args) { 14316 bool holey = false; 14317 bool can_use_type_feedback = true; 14318 if (caller_args->length() == 1) { 14319 Object* argument_one = (*caller_args)[0]; 14320 if (argument_one->IsSmi()) { 14321 int value = Smi::cast(argument_one)->value(); 14322 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) { 14323 // the array is a dictionary in this case. 14324 can_use_type_feedback = false; 14325 } else if (value != 0) { 14326 holey = true; 14327 } 14328 } else { 14329 // Non-smi length argument produces a dictionary 14330 can_use_type_feedback = false; 14331 } 14332 } 14333 14334 JSArray* array; 14335 MaybeObject* maybe_array; 14336 if (!type_info.is_null() && 14337 *type_info != isolate->heap()->undefined_value() && 14338 Cell::cast(*type_info)->value()->IsAllocationSite() && 14339 can_use_type_feedback) { 14340 Handle<Cell> cell = Handle<Cell>::cast(type_info); 14341 Handle<AllocationSite> site = Handle<AllocationSite>( 14342 AllocationSite::cast(cell->value()), isolate); 14343 ASSERT(!site->IsLiteralSite()); 14344 ElementsKind to_kind = site->GetElementsKind(); 14345 if (holey && !IsFastHoleyElementsKind(to_kind)) { 14346 to_kind = GetHoleyElementsKind(to_kind); 14347 // Update the allocation site info to reflect the advice alteration. 14348 site->SetElementsKind(to_kind); 14349 } 14350 14351 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite( 14352 *constructor, site); 14353 if (!maybe_array->To(&array)) return maybe_array; 14354 } else { 14355 maybe_array = isolate->heap()->AllocateJSObject(*constructor); 14356 if (!maybe_array->To(&array)) return maybe_array; 14357 // We might need to transition to holey 14358 ElementsKind kind = constructor->initial_map()->elements_kind(); 14359 if (holey && !IsFastHoleyElementsKind(kind)) { 14360 kind = GetHoleyElementsKind(kind); 14361 maybe_array = array->TransitionElementsKind(kind); 14362 if (maybe_array->IsFailure()) return maybe_array; 14363 } 14364 } 14365 14366 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0, 14367 DONT_INITIALIZE_ARRAY_ELEMENTS); 14368 if (maybe_array->IsFailure()) return maybe_array; 14369 maybe_array = ArrayConstructInitializeElements(array, caller_args); 14370 if (maybe_array->IsFailure()) return maybe_array; 14371 return array; 14372 } 14373 14374 14375 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { 14376 HandleScope scope(isolate); 14377 // If we get 2 arguments then they are the stub parameters (constructor, type 14378 // info). If we get 3, then the first one is a pointer to the arguments 14379 // passed by the caller. 14380 Arguments empty_args(0, NULL); 14381 bool no_caller_args = args.length() == 2; 14382 ASSERT(no_caller_args || args.length() == 3); 14383 int parameters_start = no_caller_args ? 0 : 1; 14384 Arguments* caller_args = no_caller_args 14385 ? &empty_args 14386 : reinterpret_cast<Arguments*>(args[0]); 14387 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 14388 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1); 14389 14390 return ArrayConstructorCommon(isolate, 14391 constructor, 14392 type_info, 14393 caller_args); 14394 } 14395 14396 14397 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) { 14398 HandleScope scope(isolate); 14399 Arguments empty_args(0, NULL); 14400 bool no_caller_args = args.length() == 1; 14401 ASSERT(no_caller_args || args.length() == 2); 14402 int parameters_start = no_caller_args ? 0 : 1; 14403 Arguments* caller_args = no_caller_args 14404 ? &empty_args 14405 : reinterpret_cast<Arguments*>(args[0]); 14406 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 14407 14408 return ArrayConstructorCommon(isolate, 14409 constructor, 14410 Handle<Object>::null(), 14411 caller_args); 14412 } 14413 14414 14415 // ---------------------------------------------------------------------------- 14416 // Implementation of Runtime 14417 14418 #define F(name, number_of_args, result_size) \ 14419 { Runtime::k##name, Runtime::RUNTIME, #name, \ 14420 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, 14421 14422 14423 #define I(name, number_of_args, result_size) \ 14424 { Runtime::kInline##name, Runtime::INLINE, \ 14425 "_" #name, NULL, number_of_args, result_size }, 14426 14427 static const Runtime::Function kIntrinsicFunctions[] = { 14428 RUNTIME_FUNCTION_LIST(F) 14429 INLINE_FUNCTION_LIST(I) 14430 INLINE_RUNTIME_FUNCTION_LIST(I) 14431 }; 14432 14433 14434 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap, 14435 Object* dictionary) { 14436 ASSERT(Isolate::Current()->heap() == heap); 14437 ASSERT(dictionary != NULL); 14438 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0); 14439 for (int i = 0; i < kNumFunctions; ++i) { 14440 Object* name_string; 14441 { MaybeObject* maybe_name_string = 14442 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name); 14443 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string; 14444 } 14445 NameDictionary* name_dictionary = NameDictionary::cast(dictionary); 14446 { MaybeObject* maybe_dictionary = name_dictionary->Add( 14447 String::cast(name_string), 14448 Smi::FromInt(i), 14449 PropertyDetails(NONE, NORMAL, Representation::None())); 14450 if (!maybe_dictionary->ToObject(&dictionary)) { 14451 // Non-recoverable failure. Calling code must restart heap 14452 // initialization. 14453 return maybe_dictionary; 14454 } 14455 } 14456 } 14457 return dictionary; 14458 } 14459 14460 14461 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) { 14462 Heap* heap = name->GetHeap(); 14463 int entry = heap->intrinsic_function_names()->FindEntry(*name); 14464 if (entry != kNotFound) { 14465 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); 14466 int function_index = Smi::cast(smi_index)->value(); 14467 return &(kIntrinsicFunctions[function_index]); 14468 } 14469 return NULL; 14470 } 14471 14472 14473 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { 14474 return &(kIntrinsicFunctions[static_cast<int>(id)]); 14475 } 14476 14477 14478 void Runtime::PerformGC(Object* result) { 14479 Isolate* isolate = Isolate::Current(); 14480 Failure* failure = Failure::cast(result); 14481 if (failure->IsRetryAfterGC()) { 14482 if (isolate->heap()->new_space()->AddFreshPage()) { 14483 return; 14484 } 14485 14486 // Try to do a garbage collection; ignore it if it fails. The C 14487 // entry stub will throw an out-of-memory exception in that case. 14488 isolate->heap()->CollectGarbage(failure->allocation_space(), 14489 "Runtime::PerformGC"); 14490 } else { 14491 // Handle last resort GC and make sure to allow future allocations 14492 // to grow the heap without causing GCs (if possible). 14493 isolate->counters()->gc_last_resort_from_js()->Increment(); 14494 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 14495 "Runtime::PerformGC"); 14496 } 14497 } 14498 14499 14500 } } // namespace v8::internal 14501