1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdlib.h> 6 #include <limits> 7 8 #include "src/v8.h" 9 10 #include "src/accessors.h" 11 #include "src/allocation-site-scopes.h" 12 #include "src/api.h" 13 #include "src/arguments.h" 14 #include "src/bootstrapper.h" 15 #include "src/codegen.h" 16 #include "src/compilation-cache.h" 17 #include "src/compiler.h" 18 #include "src/conversions.h" 19 #include "src/cpu.h" 20 #include "src/cpu-profiler.h" 21 #include "src/dateparser-inl.h" 22 #include "src/debug.h" 23 #include "src/deoptimizer.h" 24 #include "src/date.h" 25 #include "src/execution.h" 26 #include "src/full-codegen.h" 27 #include "src/global-handles.h" 28 #include "src/isolate-inl.h" 29 #include "src/jsregexp.h" 30 #include "src/jsregexp-inl.h" 31 #include "src/json-parser.h" 32 #include "src/json-stringifier.h" 33 #include "src/liveedit.h" 34 #include "src/misc-intrinsics.h" 35 #include "src/parser.h" 36 #include "src/platform.h" 37 #include "src/runtime-profiler.h" 38 #include "src/runtime.h" 39 #include "src/scopeinfo.h" 40 #include "src/smart-pointers.h" 41 #include "src/string-search.h" 42 #include "src/stub-cache.h" 43 #include "src/uri.h" 44 #include "src/v8threads.h" 45 #include "src/vm-state-inl.h" 46 47 #ifdef V8_I18N_SUPPORT 48 #include "src/i18n.h" 49 #include "unicode/brkiter.h" 50 #include "unicode/calendar.h" 51 #include "unicode/coll.h" 52 #include "unicode/curramt.h" 53 #include "unicode/datefmt.h" 54 #include "unicode/dcfmtsym.h" 55 #include "unicode/decimfmt.h" 56 #include "unicode/dtfmtsym.h" 57 #include "unicode/dtptngen.h" 58 #include "unicode/locid.h" 59 #include "unicode/numfmt.h" 60 #include "unicode/numsys.h" 61 #include "unicode/rbbi.h" 62 #include "unicode/smpdtfmt.h" 63 #include "unicode/timezone.h" 64 #include "unicode/uchar.h" 65 #include "unicode/ucol.h" 66 #include "unicode/ucurr.h" 67 #include "unicode/uloc.h" 68 #include "unicode/unum.h" 69 #include "unicode/uversion.h" 70 #endif 71 72 #ifndef _STLP_VENDOR_CSTD 73 // STLPort doesn't import fpclassify and isless into the std namespace. 74 using std::fpclassify; 75 using std::isless; 76 #endif 77 78 namespace v8 { 79 namespace internal { 80 81 82 #define RUNTIME_ASSERT(value) \ 83 if (!(value)) return isolate->ThrowIllegalOperation(); 84 85 #define RUNTIME_ASSERT_HANDLIFIED(value, T) \ 86 if (!(value)) { \ 87 isolate->ThrowIllegalOperation(); \ 88 return MaybeHandle<T>(); \ 89 } 90 91 // Cast the given object to a value of the specified type and store 92 // it in a variable with the given name. If the object is not of the 93 // expected type call IllegalOperation and return. 94 #define CONVERT_ARG_CHECKED(Type, name, index) \ 95 RUNTIME_ASSERT(args[index]->Is##Type()); \ 96 Type* name = Type::cast(args[index]); 97 98 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ 99 RUNTIME_ASSERT(args[index]->Is##Type()); \ 100 Handle<Type> name = args.at<Type>(index); 101 102 #define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \ 103 RUNTIME_ASSERT(args[index]->IsNumber()); \ 104 Handle<Object> name = args.at<Object>(index); 105 106 // Cast the given object to a boolean and store it in a variable with 107 // the given name. If the object is not a boolean call IllegalOperation 108 // and return. 109 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ 110 RUNTIME_ASSERT(args[index]->IsBoolean()); \ 111 bool name = args[index]->IsTrue(); 112 113 // Cast the given argument to a Smi and store its value in an int variable 114 // with the given name. If the argument is not a Smi call IllegalOperation 115 // and return. 116 #define CONVERT_SMI_ARG_CHECKED(name, index) \ 117 RUNTIME_ASSERT(args[index]->IsSmi()); \ 118 int name = args.smi_at(index); 119 120 // Cast the given argument to a double and store it in a variable with 121 // the given name. If the argument is not a number (as opposed to 122 // the number not-a-number) call IllegalOperation and return. 123 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ 124 RUNTIME_ASSERT(args[index]->IsNumber()); \ 125 double name = args.number_at(index); 126 127 // Call the specified converter on the object *comand store the result in 128 // a variable of the specified type with the given name. If the 129 // object is not a Number call IllegalOperation and return. 130 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 131 RUNTIME_ASSERT(obj->IsNumber()); \ 132 type name = NumberTo##Type(obj); 133 134 135 // Cast the given argument to PropertyDetails and store its value in a 136 // variable with the given name. If the argument is not a Smi call 137 // IllegalOperation and return. 138 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ 139 RUNTIME_ASSERT(args[index]->IsSmi()); \ 140 PropertyDetails name = PropertyDetails(Smi::cast(args[index])); 141 142 143 // Assert that the given argument has a valid value for a StrictMode 144 // and store it in a StrictMode variable with the given name. 145 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ 146 RUNTIME_ASSERT(args[index]->IsSmi()); \ 147 RUNTIME_ASSERT(args.smi_at(index) == STRICT || \ 148 args.smi_at(index) == SLOPPY); \ 149 StrictMode name = static_cast<StrictMode>(args.smi_at(index)); 150 151 152 static Handle<Map> ComputeObjectLiteralMap( 153 Handle<Context> context, 154 Handle<FixedArray> constant_properties, 155 bool* is_result_from_cache) { 156 Isolate* isolate = context->GetIsolate(); 157 int properties_length = constant_properties->length(); 158 int number_of_properties = properties_length / 2; 159 // Check that there are only internal strings and array indices among keys. 160 int number_of_string_keys = 0; 161 for (int p = 0; p != properties_length; p += 2) { 162 Object* key = constant_properties->get(p); 163 uint32_t element_index = 0; 164 if (key->IsInternalizedString()) { 165 number_of_string_keys++; 166 } else if (key->ToArrayIndex(&element_index)) { 167 // An index key does not require space in the property backing store. 168 number_of_properties--; 169 } else { 170 // Bail out as a non-internalized-string non-index key makes caching 171 // impossible. 172 // ASSERT to make sure that the if condition after the loop is false. 173 ASSERT(number_of_string_keys != number_of_properties); 174 break; 175 } 176 } 177 // If we only have internalized strings and array indices among keys then we 178 // can use the map cache in the native context. 179 const int kMaxKeys = 10; 180 if ((number_of_string_keys == number_of_properties) && 181 (number_of_string_keys < kMaxKeys)) { 182 // Create the fixed array with the key. 183 Handle<FixedArray> keys = 184 isolate->factory()->NewFixedArray(number_of_string_keys); 185 if (number_of_string_keys > 0) { 186 int index = 0; 187 for (int p = 0; p < properties_length; p += 2) { 188 Object* key = constant_properties->get(p); 189 if (key->IsInternalizedString()) { 190 keys->set(index++, key); 191 } 192 } 193 ASSERT(index == number_of_string_keys); 194 } 195 *is_result_from_cache = true; 196 return isolate->factory()->ObjectLiteralMapFromCache(context, keys); 197 } 198 *is_result_from_cache = false; 199 return Map::Create(handle(context->object_function()), number_of_properties); 200 } 201 202 203 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( 204 Isolate* isolate, 205 Handle<FixedArray> literals, 206 Handle<FixedArray> constant_properties); 207 208 209 MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate( 210 Isolate* isolate, 211 Handle<FixedArray> literals, 212 Handle<FixedArray> constant_properties, 213 bool should_have_fast_elements, 214 bool has_function_literal) { 215 // Get the native context from the literals array. This is the 216 // context in which the function was created and we use the object 217 // function from this context to create the object literal. We do 218 // not use the object function from the current native context 219 // because this might be the object function from another context 220 // which we should not have access to. 221 Handle<Context> context = 222 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals)); 223 224 // In case we have function literals, we want the object to be in 225 // slow properties mode for now. We don't go in the map cache because 226 // maps with constant functions can't be shared if the functions are 227 // not the same (which is the common case). 228 bool is_result_from_cache = false; 229 Handle<Map> map = has_function_literal 230 ? Handle<Map>(context->object_function()->initial_map()) 231 : ComputeObjectLiteralMap(context, 232 constant_properties, 233 &is_result_from_cache); 234 235 PretenureFlag pretenure_flag = 236 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; 237 238 Handle<JSObject> boilerplate = 239 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag); 240 241 // Normalize the elements of the boilerplate to save space if needed. 242 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); 243 244 // Add the constant properties to the boilerplate. 245 int length = constant_properties->length(); 246 bool should_transform = 247 !is_result_from_cache && boilerplate->HasFastProperties(); 248 bool should_normalize = should_transform || has_function_literal; 249 if (should_normalize) { 250 // TODO(verwaest): We might not want to ever normalize here. 251 JSObject::NormalizeProperties( 252 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); 253 } 254 Object::ValueType value_type = should_normalize 255 ? Object::FORCE_TAGGED : Object::OPTIMAL_REPRESENTATION; 256 257 // TODO(verwaest): Support tracking representations in the boilerplate. 258 for (int index = 0; index < length; index +=2) { 259 Handle<Object> key(constant_properties->get(index+0), isolate); 260 Handle<Object> value(constant_properties->get(index+1), isolate); 261 if (value->IsFixedArray()) { 262 // The value contains the constant_properties of a 263 // simple object or array literal. 264 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 265 ASSIGN_RETURN_ON_EXCEPTION( 266 isolate, value, 267 CreateLiteralBoilerplate(isolate, literals, array), 268 Object); 269 } 270 MaybeHandle<Object> maybe_result; 271 uint32_t element_index = 0; 272 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT; 273 if (key->IsInternalizedString()) { 274 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { 275 // Array index as string (uint32). 276 maybe_result = JSObject::SetOwnElement( 277 boilerplate, element_index, value, SLOPPY); 278 } else { 279 Handle<String> name(String::cast(*key)); 280 ASSERT(!name->AsArrayIndex(&element_index)); 281 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes( 282 boilerplate, name, value, NONE, 283 value_type, mode); 284 } 285 } else if (key->ToArrayIndex(&element_index)) { 286 // Array index (uint32). 287 maybe_result = JSObject::SetOwnElement( 288 boilerplate, element_index, value, SLOPPY); 289 } else { 290 // Non-uint32 number. 291 ASSERT(key->IsNumber()); 292 double num = key->Number(); 293 char arr[100]; 294 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 295 const char* str = DoubleToCString(num, buffer); 296 Handle<String> name = isolate->factory()->NewStringFromAsciiChecked(str); 297 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes( 298 boilerplate, name, value, NONE, 299 value_type, mode); 300 } 301 // If setting the property on the boilerplate throws an 302 // exception, the exception is converted to an empty handle in 303 // the handle based operations. In that case, we need to 304 // convert back to an exception. 305 RETURN_ON_EXCEPTION(isolate, maybe_result, Object); 306 } 307 308 // Transform to fast properties if necessary. For object literals with 309 // containing function literals we defer this operation until after all 310 // computed properties have been assigned so that we can generate 311 // constant function properties. 312 if (should_transform && !has_function_literal) { 313 JSObject::TransformToFastProperties( 314 boilerplate, boilerplate->map()->unused_property_fields()); 315 } 316 317 return boilerplate; 318 } 319 320 321 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements( 322 Handle<Object> object, 323 ElementsKind to_kind, 324 Isolate* isolate) { 325 HandleScope scope(isolate); 326 if (!object->IsJSObject()) { 327 isolate->ThrowIllegalOperation(); 328 return MaybeHandle<Object>(); 329 } 330 ElementsKind from_kind = 331 Handle<JSObject>::cast(object)->map()->elements_kind(); 332 if (Map::IsValidElementsTransition(from_kind, to_kind)) { 333 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); 334 return object; 335 } 336 isolate->ThrowIllegalOperation(); 337 return MaybeHandle<Object>(); 338 } 339 340 341 static const int kSmiLiteralMinimumLength = 1024; 342 343 344 MaybeHandle<Object> Runtime::CreateArrayLiteralBoilerplate( 345 Isolate* isolate, 346 Handle<FixedArray> literals, 347 Handle<FixedArray> elements) { 348 // Create the JSArray. 349 Handle<JSFunction> constructor( 350 JSFunction::NativeContextFromLiterals(*literals)->array_function()); 351 352 PretenureFlag pretenure_flag = 353 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED; 354 355 Handle<JSArray> object = Handle<JSArray>::cast( 356 isolate->factory()->NewJSObject(constructor, pretenure_flag)); 357 358 ElementsKind constant_elements_kind = 359 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value()); 360 Handle<FixedArrayBase> constant_elements_values( 361 FixedArrayBase::cast(elements->get(1))); 362 363 { DisallowHeapAllocation no_gc; 364 ASSERT(IsFastElementsKind(constant_elements_kind)); 365 Context* native_context = isolate->context()->native_context(); 366 Object* maps_array = native_context->js_array_maps(); 367 ASSERT(!maps_array->IsUndefined()); 368 Object* map = FixedArray::cast(maps_array)->get(constant_elements_kind); 369 object->set_map(Map::cast(map)); 370 } 371 372 Handle<FixedArrayBase> copied_elements_values; 373 if (IsFastDoubleElementsKind(constant_elements_kind)) { 374 ASSERT(FLAG_smi_only_arrays); 375 copied_elements_values = isolate->factory()->CopyFixedDoubleArray( 376 Handle<FixedDoubleArray>::cast(constant_elements_values)); 377 } else { 378 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind)); 379 const bool is_cow = 380 (constant_elements_values->map() == 381 isolate->heap()->fixed_cow_array_map()); 382 if (is_cow) { 383 copied_elements_values = constant_elements_values; 384 #if DEBUG 385 Handle<FixedArray> fixed_array_values = 386 Handle<FixedArray>::cast(copied_elements_values); 387 for (int i = 0; i < fixed_array_values->length(); i++) { 388 ASSERT(!fixed_array_values->get(i)->IsFixedArray()); 389 } 390 #endif 391 } else { 392 Handle<FixedArray> fixed_array_values = 393 Handle<FixedArray>::cast(constant_elements_values); 394 Handle<FixedArray> fixed_array_values_copy = 395 isolate->factory()->CopyFixedArray(fixed_array_values); 396 copied_elements_values = fixed_array_values_copy; 397 for (int i = 0; i < fixed_array_values->length(); i++) { 398 if (fixed_array_values->get(i)->IsFixedArray()) { 399 // The value contains the constant_properties of a 400 // simple object or array literal. 401 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); 402 Handle<Object> result; 403 ASSIGN_RETURN_ON_EXCEPTION( 404 isolate, result, 405 CreateLiteralBoilerplate(isolate, literals, fa), 406 Object); 407 fixed_array_values_copy->set(i, *result); 408 } 409 } 410 } 411 } 412 object->set_elements(*copied_elements_values); 413 object->set_length(Smi::FromInt(copied_elements_values->length())); 414 415 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is 416 // on or the object is larger than the threshold. 417 if (!FLAG_smi_only_arrays && 418 constant_elements_values->length() < kSmiLiteralMinimumLength) { 419 ElementsKind elements_kind = object->GetElementsKind(); 420 if (!IsFastObjectElementsKind(elements_kind)) { 421 if (IsFastHoleyElementsKind(elements_kind)) { 422 TransitionElements(object, FAST_HOLEY_ELEMENTS, isolate).Check(); 423 } else { 424 TransitionElements(object, FAST_ELEMENTS, isolate).Check(); 425 } 426 } 427 } 428 429 JSObject::ValidateElements(object); 430 return object; 431 } 432 433 434 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( 435 Isolate* isolate, 436 Handle<FixedArray> literals, 437 Handle<FixedArray> array) { 438 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 439 const bool kHasNoFunctionLiteral = false; 440 switch (CompileTimeValue::GetLiteralType(array)) { 441 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: 442 return CreateObjectLiteralBoilerplate(isolate, 443 literals, 444 elements, 445 true, 446 kHasNoFunctionLiteral); 447 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 448 return CreateObjectLiteralBoilerplate(isolate, 449 literals, 450 elements, 451 false, 452 kHasNoFunctionLiteral); 453 case CompileTimeValue::ARRAY_LITERAL: 454 return Runtime::CreateArrayLiteralBoilerplate( 455 isolate, literals, elements); 456 default: 457 UNREACHABLE(); 458 return MaybeHandle<Object>(); 459 } 460 } 461 462 463 RUNTIME_FUNCTION(RuntimeHidden_CreateObjectLiteral) { 464 HandleScope scope(isolate); 465 ASSERT(args.length() == 4); 466 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 467 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 468 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2); 469 CONVERT_SMI_ARG_CHECKED(flags, 3); 470 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; 471 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; 472 473 RUNTIME_ASSERT(literals_index >= 0 && literals_index < literals->length()); 474 475 // Check if boilerplate exists. If not, create it first. 476 Handle<Object> literal_site(literals->get(literals_index), isolate); 477 Handle<AllocationSite> site; 478 Handle<JSObject> boilerplate; 479 if (*literal_site == isolate->heap()->undefined_value()) { 480 Handle<Object> raw_boilerplate; 481 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 482 isolate, raw_boilerplate, 483 CreateObjectLiteralBoilerplate( 484 isolate, 485 literals, 486 constant_properties, 487 should_have_fast_elements, 488 has_function_literal)); 489 boilerplate = Handle<JSObject>::cast(raw_boilerplate); 490 491 AllocationSiteCreationContext creation_context(isolate); 492 site = creation_context.EnterNewScope(); 493 RETURN_FAILURE_ON_EXCEPTION( 494 isolate, 495 JSObject::DeepWalk(boilerplate, &creation_context)); 496 creation_context.ExitScope(site, boilerplate); 497 498 // Update the functions literal and return the boilerplate. 499 literals->set(literals_index, *site); 500 } else { 501 site = Handle<AllocationSite>::cast(literal_site); 502 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()), 503 isolate); 504 } 505 506 AllocationSiteUsageContext usage_context(isolate, site, true); 507 usage_context.EnterNewScope(); 508 MaybeHandle<Object> maybe_copy = JSObject::DeepCopy( 509 boilerplate, &usage_context); 510 usage_context.ExitScope(site, boilerplate); 511 Handle<Object> copy; 512 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, copy, maybe_copy); 513 return *copy; 514 } 515 516 517 MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite( 518 Isolate* isolate, 519 Handle<FixedArray> literals, 520 int literals_index, 521 Handle<FixedArray> elements) { 522 // Check if boilerplate exists. If not, create it first. 523 Handle<Object> literal_site(literals->get(literals_index), isolate); 524 Handle<AllocationSite> site; 525 if (*literal_site == isolate->heap()->undefined_value()) { 526 ASSERT(*elements != isolate->heap()->empty_fixed_array()); 527 Handle<Object> boilerplate; 528 ASSIGN_RETURN_ON_EXCEPTION( 529 isolate, boilerplate, 530 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements), 531 AllocationSite); 532 533 AllocationSiteCreationContext creation_context(isolate); 534 site = creation_context.EnterNewScope(); 535 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), 536 &creation_context).is_null()) { 537 return Handle<AllocationSite>::null(); 538 } 539 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate)); 540 541 literals->set(literals_index, *site); 542 } else { 543 site = Handle<AllocationSite>::cast(literal_site); 544 } 545 546 return site; 547 } 548 549 550 static MaybeHandle<JSObject> CreateArrayLiteralImpl(Isolate* isolate, 551 Handle<FixedArray> literals, 552 int literals_index, 553 Handle<FixedArray> elements, 554 int flags) { 555 RUNTIME_ASSERT_HANDLIFIED(literals_index >= 0 && 556 literals_index < literals->length(), JSObject); 557 Handle<AllocationSite> site; 558 ASSIGN_RETURN_ON_EXCEPTION( 559 isolate, site, 560 GetLiteralAllocationSite(isolate, literals, literals_index, elements), 561 JSObject); 562 563 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0; 564 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info())); 565 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos); 566 usage_context.EnterNewScope(); 567 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0 568 ? JSObject::kNoHints 569 : JSObject::kObjectIsShallowArray; 570 MaybeHandle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context, 571 hints); 572 usage_context.ExitScope(site, boilerplate); 573 return copy; 574 } 575 576 577 RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteral) { 578 HandleScope scope(isolate); 579 ASSERT(args.length() == 4); 580 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 581 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 582 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 583 CONVERT_SMI_ARG_CHECKED(flags, 3); 584 585 Handle<JSObject> result; 586 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 587 CreateArrayLiteralImpl(isolate, literals, literals_index, elements, 588 flags)); 589 return *result; 590 } 591 592 593 RUNTIME_FUNCTION(RuntimeHidden_CreateArrayLiteralStubBailout) { 594 HandleScope scope(isolate); 595 ASSERT(args.length() == 3); 596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 597 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 599 600 Handle<JSObject> result; 601 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 602 CreateArrayLiteralImpl(isolate, literals, literals_index, elements, 603 ArrayLiteral::kShallowElements)); 604 return *result; 605 } 606 607 608 RUNTIME_FUNCTION(Runtime_CreateSymbol) { 609 HandleScope scope(isolate); 610 ASSERT(args.length() == 1); 611 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); 612 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); 613 Handle<Symbol> symbol = isolate->factory()->NewSymbol(); 614 if (name->IsString()) symbol->set_name(*name); 615 return *symbol; 616 } 617 618 619 RUNTIME_FUNCTION(Runtime_CreatePrivateSymbol) { 620 HandleScope scope(isolate); 621 ASSERT(args.length() == 1); 622 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); 623 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); 624 Handle<Symbol> symbol = isolate->factory()->NewPrivateSymbol(); 625 if (name->IsString()) symbol->set_name(*name); 626 return *symbol; 627 } 628 629 630 RUNTIME_FUNCTION(Runtime_CreateGlobalPrivateSymbol) { 631 HandleScope scope(isolate); 632 ASSERT(args.length() == 1); 633 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 634 Handle<JSObject> registry = isolate->GetSymbolRegistry(); 635 Handle<String> part = isolate->factory()->private_intern_string(); 636 Handle<Object> privates; 637 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 638 isolate, privates, Object::GetPropertyOrElement(registry, part)); 639 Handle<Object> symbol; 640 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 641 isolate, symbol, Object::GetPropertyOrElement(privates, name)); 642 if (!symbol->IsSymbol()) { 643 ASSERT(symbol->IsUndefined()); 644 symbol = isolate->factory()->NewPrivateSymbol(); 645 Handle<Symbol>::cast(symbol)->set_name(*name); 646 JSObject::SetProperty(Handle<JSObject>::cast(privates), 647 name, symbol, NONE, STRICT).Assert(); 648 } 649 return *symbol; 650 } 651 652 653 RUNTIME_FUNCTION(Runtime_NewSymbolWrapper) { 654 HandleScope scope(isolate); 655 ASSERT(args.length() == 1); 656 CONVERT_ARG_HANDLE_CHECKED(Symbol, symbol, 0); 657 return *Object::ToObject(isolate, symbol).ToHandleChecked(); 658 } 659 660 661 RUNTIME_FUNCTION(Runtime_SymbolDescription) { 662 SealHandleScope shs(isolate); 663 ASSERT(args.length() == 1); 664 CONVERT_ARG_CHECKED(Symbol, symbol, 0); 665 return symbol->name(); 666 } 667 668 669 RUNTIME_FUNCTION(Runtime_SymbolRegistry) { 670 HandleScope scope(isolate); 671 ASSERT(args.length() == 0); 672 return *isolate->GetSymbolRegistry(); 673 } 674 675 676 RUNTIME_FUNCTION(Runtime_SymbolIsPrivate) { 677 SealHandleScope shs(isolate); 678 ASSERT(args.length() == 1); 679 CONVERT_ARG_CHECKED(Symbol, symbol, 0); 680 return isolate->heap()->ToBoolean(symbol->is_private()); 681 } 682 683 684 RUNTIME_FUNCTION(Runtime_CreateJSProxy) { 685 HandleScope scope(isolate); 686 ASSERT(args.length() == 2); 687 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); 688 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 689 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); 690 return *isolate->factory()->NewJSProxy(handler, prototype); 691 } 692 693 694 RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) { 695 HandleScope scope(isolate); 696 ASSERT(args.length() == 4); 697 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, handler, 0); 698 CONVERT_ARG_HANDLE_CHECKED(Object, call_trap, 1); 699 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); 700 CONVERT_ARG_HANDLE_CHECKED(JSFunction, construct_trap, 2); 701 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 3); 702 if (!prototype->IsJSReceiver()) prototype = isolate->factory()->null_value(); 703 return *isolate->factory()->NewJSFunctionProxy( 704 handler, call_trap, construct_trap, prototype); 705 } 706 707 708 RUNTIME_FUNCTION(Runtime_IsJSProxy) { 709 SealHandleScope shs(isolate); 710 ASSERT(args.length() == 1); 711 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 712 return isolate->heap()->ToBoolean(obj->IsJSProxy()); 713 } 714 715 716 RUNTIME_FUNCTION(Runtime_IsJSFunctionProxy) { 717 SealHandleScope shs(isolate); 718 ASSERT(args.length() == 1); 719 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 720 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); 721 } 722 723 724 RUNTIME_FUNCTION(Runtime_GetHandler) { 725 SealHandleScope shs(isolate); 726 ASSERT(args.length() == 1); 727 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 728 return proxy->handler(); 729 } 730 731 732 RUNTIME_FUNCTION(Runtime_GetCallTrap) { 733 SealHandleScope shs(isolate); 734 ASSERT(args.length() == 1); 735 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 736 return proxy->call_trap(); 737 } 738 739 740 RUNTIME_FUNCTION(Runtime_GetConstructTrap) { 741 SealHandleScope shs(isolate); 742 ASSERT(args.length() == 1); 743 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 744 return proxy->construct_trap(); 745 } 746 747 748 RUNTIME_FUNCTION(Runtime_Fix) { 749 HandleScope scope(isolate); 750 ASSERT(args.length() == 1); 751 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0); 752 JSProxy::Fix(proxy); 753 return isolate->heap()->undefined_value(); 754 } 755 756 757 void Runtime::FreeArrayBuffer(Isolate* isolate, 758 JSArrayBuffer* phantom_array_buffer) { 759 if (phantom_array_buffer->should_be_freed()) { 760 ASSERT(phantom_array_buffer->is_external()); 761 free(phantom_array_buffer->backing_store()); 762 } 763 if (phantom_array_buffer->is_external()) return; 764 765 size_t allocated_length = NumberToSize( 766 isolate, phantom_array_buffer->byte_length()); 767 768 reinterpret_cast<v8::Isolate*>(isolate) 769 ->AdjustAmountOfExternalAllocatedMemory( 770 -static_cast<int64_t>(allocated_length)); 771 CHECK(V8::ArrayBufferAllocator() != NULL); 772 V8::ArrayBufferAllocator()->Free( 773 phantom_array_buffer->backing_store(), 774 allocated_length); 775 } 776 777 778 void Runtime::SetupArrayBuffer(Isolate* isolate, 779 Handle<JSArrayBuffer> array_buffer, 780 bool is_external, 781 void* data, 782 size_t allocated_length) { 783 ASSERT(array_buffer->GetInternalFieldCount() == 784 v8::ArrayBuffer::kInternalFieldCount); 785 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 786 array_buffer->SetInternalField(i, Smi::FromInt(0)); 787 } 788 array_buffer->set_backing_store(data); 789 array_buffer->set_flag(Smi::FromInt(0)); 790 array_buffer->set_is_external(is_external); 791 792 Handle<Object> byte_length = 793 isolate->factory()->NewNumberFromSize(allocated_length); 794 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 795 array_buffer->set_byte_length(*byte_length); 796 797 array_buffer->set_weak_next(isolate->heap()->array_buffers_list()); 798 isolate->heap()->set_array_buffers_list(*array_buffer); 799 array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); 800 } 801 802 803 bool Runtime::SetupArrayBufferAllocatingData( 804 Isolate* isolate, 805 Handle<JSArrayBuffer> array_buffer, 806 size_t allocated_length, 807 bool initialize) { 808 void* data; 809 CHECK(V8::ArrayBufferAllocator() != NULL); 810 if (allocated_length != 0) { 811 if (initialize) { 812 data = V8::ArrayBufferAllocator()->Allocate(allocated_length); 813 } else { 814 data = 815 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); 816 } 817 if (data == NULL) return false; 818 } else { 819 data = NULL; 820 } 821 822 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); 823 824 reinterpret_cast<v8::Isolate*>(isolate) 825 ->AdjustAmountOfExternalAllocatedMemory(allocated_length); 826 827 return true; 828 } 829 830 831 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) { 832 Isolate* isolate = array_buffer->GetIsolate(); 833 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate); 834 !view_obj->IsUndefined();) { 835 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj)); 836 if (view->IsJSTypedArray()) { 837 JSTypedArray::cast(*view)->Neuter(); 838 } else if (view->IsJSDataView()) { 839 JSDataView::cast(*view)->Neuter(); 840 } else { 841 UNREACHABLE(); 842 } 843 view_obj = handle(view->weak_next(), isolate); 844 } 845 array_buffer->Neuter(); 846 } 847 848 849 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) { 850 HandleScope scope(isolate); 851 ASSERT(args.length() == 2); 852 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); 853 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1); 854 if (!holder->byte_length()->IsUndefined()) { 855 // ArrayBuffer is already initialized; probably a fuzz test. 856 return *holder; 857 } 858 size_t allocated_length = 0; 859 if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) { 860 return isolate->Throw( 861 *isolate->factory()->NewRangeError("invalid_array_buffer_length", 862 HandleVector<Object>(NULL, 0))); 863 } 864 if (!Runtime::SetupArrayBufferAllocatingData(isolate, 865 holder, allocated_length)) { 866 return isolate->Throw( 867 *isolate->factory()->NewRangeError("invalid_array_buffer_length", 868 HandleVector<Object>(NULL, 0))); 869 } 870 return *holder; 871 } 872 873 874 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) { 875 SealHandleScope shs(isolate); 876 ASSERT(args.length() == 1); 877 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); 878 return holder->byte_length(); 879 } 880 881 882 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) { 883 HandleScope scope(isolate); 884 ASSERT(args.length() == 3); 885 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); 886 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); 887 CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2); 888 RUNTIME_ASSERT(!source.is_identical_to(target)); 889 size_t start = 0; 890 RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start)); 891 size_t target_length = NumberToSize(isolate, target->byte_length()); 892 893 if (target_length == 0) return isolate->heap()->undefined_value(); 894 895 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); 896 RUNTIME_ASSERT(start <= source_byte_length); 897 RUNTIME_ASSERT(source_byte_length - start >= target_length); 898 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); 899 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); 900 CopyBytes(target_data, source_data + start, target_length); 901 return isolate->heap()->undefined_value(); 902 } 903 904 905 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) { 906 HandleScope scope(isolate); 907 ASSERT(args.length() == 1); 908 CONVERT_ARG_CHECKED(Object, object, 0); 909 return isolate->heap()->ToBoolean(object->IsJSArrayBufferView()); 910 } 911 912 913 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { 914 HandleScope scope(isolate); 915 ASSERT(args.length() == 1); 916 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0); 917 if (array_buffer->backing_store() == NULL) { 918 CHECK(Smi::FromInt(0) == array_buffer->byte_length()); 919 return isolate->heap()->undefined_value(); 920 } 921 ASSERT(!array_buffer->is_external()); 922 void* backing_store = array_buffer->backing_store(); 923 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length()); 924 array_buffer->set_is_external(true); 925 Runtime::NeuterArrayBuffer(array_buffer); 926 V8::ArrayBufferAllocator()->Free(backing_store, byte_length); 927 return isolate->heap()->undefined_value(); 928 } 929 930 931 void Runtime::ArrayIdToTypeAndSize( 932 int arrayId, 933 ExternalArrayType* array_type, 934 ElementsKind* external_elements_kind, 935 ElementsKind* fixed_elements_kind, 936 size_t* element_size) { 937 switch (arrayId) { 938 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ 939 case ARRAY_ID_##TYPE: \ 940 *array_type = kExternal##Type##Array; \ 941 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \ 942 *fixed_elements_kind = TYPE##_ELEMENTS; \ 943 *element_size = size; \ 944 break; 945 946 TYPED_ARRAYS(ARRAY_ID_CASE) 947 #undef ARRAY_ID_CASE 948 949 default: 950 UNREACHABLE(); 951 } 952 } 953 954 955 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { 956 HandleScope scope(isolate); 957 ASSERT(args.length() == 5); 958 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 959 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 960 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2); 961 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3); 962 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4); 963 964 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && 965 arrayId <= Runtime::ARRAY_ID_LAST); 966 967 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. 968 size_t element_size = 1; // Bogus initialization. 969 ElementsKind external_elements_kind = 970 EXTERNAL_INT8_ELEMENTS; // Bogus initialization. 971 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. 972 Runtime::ArrayIdToTypeAndSize(arrayId, 973 &array_type, 974 &external_elements_kind, 975 &fixed_elements_kind, 976 &element_size); 977 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); 978 979 size_t byte_offset = 0; 980 size_t byte_length = 0; 981 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset)); 982 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length)); 983 984 if (maybe_buffer->IsJSArrayBuffer()) { 985 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); 986 size_t array_buffer_byte_length = 987 NumberToSize(isolate, buffer->byte_length()); 988 RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length); 989 RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length); 990 } else { 991 RUNTIME_ASSERT(maybe_buffer->IsNull()); 992 } 993 994 RUNTIME_ASSERT(byte_length % element_size == 0); 995 size_t length = byte_length / element_size; 996 997 if (length > static_cast<unsigned>(Smi::kMaxValue)) { 998 return isolate->Throw( 999 *isolate->factory()->NewRangeError("invalid_typed_array_length", 1000 HandleVector<Object>(NULL, 0))); 1001 } 1002 1003 // All checks are done, now we can modify objects. 1004 1005 ASSERT(holder->GetInternalFieldCount() == 1006 v8::ArrayBufferView::kInternalFieldCount); 1007 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 1008 holder->SetInternalField(i, Smi::FromInt(0)); 1009 } 1010 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); 1011 holder->set_length(*length_obj); 1012 holder->set_byte_offset(*byte_offset_object); 1013 holder->set_byte_length(*byte_length_object); 1014 1015 if (!maybe_buffer->IsNull()) { 1016 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer); 1017 holder->set_buffer(*buffer); 1018 holder->set_weak_next(buffer->weak_first_view()); 1019 buffer->set_weak_first_view(*holder); 1020 1021 Handle<ExternalArray> elements = 1022 isolate->factory()->NewExternalArray( 1023 static_cast<int>(length), array_type, 1024 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); 1025 Handle<Map> map = 1026 JSObject::GetElementsTransitionMap(holder, external_elements_kind); 1027 JSObject::SetMapAndElements(holder, map, elements); 1028 ASSERT(IsExternalArrayElementsKind(holder->map()->elements_kind())); 1029 } else { 1030 holder->set_buffer(Smi::FromInt(0)); 1031 holder->set_weak_next(isolate->heap()->undefined_value()); 1032 Handle<FixedTypedArrayBase> elements = 1033 isolate->factory()->NewFixedTypedArray( 1034 static_cast<int>(length), array_type); 1035 holder->set_elements(*elements); 1036 } 1037 return isolate->heap()->undefined_value(); 1038 } 1039 1040 1041 // Initializes a typed array from an array-like object. 1042 // If an array-like object happens to be a typed array of the same type, 1043 // initializes backing store using memove. 1044 // 1045 // Returns true if backing store was initialized or false otherwise. 1046 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { 1047 HandleScope scope(isolate); 1048 ASSERT(args.length() == 4); 1049 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 1050 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 1051 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); 1052 CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3); 1053 1054 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST && 1055 arrayId <= Runtime::ARRAY_ID_LAST); 1056 1057 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. 1058 size_t element_size = 1; // Bogus initialization. 1059 ElementsKind external_elements_kind = 1060 EXTERNAL_INT8_ELEMENTS; // Bogus intialization. 1061 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. 1062 Runtime::ArrayIdToTypeAndSize(arrayId, 1063 &array_type, 1064 &external_elements_kind, 1065 &fixed_elements_kind, 1066 &element_size); 1067 1068 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); 1069 1070 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 1071 if (source->IsJSTypedArray() && 1072 JSTypedArray::cast(*source)->type() == array_type) { 1073 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate); 1074 } 1075 size_t length = 0; 1076 RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length)); 1077 1078 if ((length > static_cast<unsigned>(Smi::kMaxValue)) || 1079 (length > (kMaxInt / element_size))) { 1080 return isolate->Throw(*isolate->factory()-> 1081 NewRangeError("invalid_typed_array_length", 1082 HandleVector<Object>(NULL, 0))); 1083 } 1084 size_t byte_length = length * element_size; 1085 1086 ASSERT(holder->GetInternalFieldCount() == 1087 v8::ArrayBufferView::kInternalFieldCount); 1088 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 1089 holder->SetInternalField(i, Smi::FromInt(0)); 1090 } 1091 1092 // NOTE: not initializing backing store. 1093 // We assume that the caller of this function will initialize holder 1094 // with the loop 1095 // for(i = 0; i < length; i++) { holder[i] = source[i]; } 1096 // We assume that the caller of this function is always a typed array 1097 // constructor. 1098 // If source is a typed array, this loop will always run to completion, 1099 // so we are sure that the backing store will be initialized. 1100 // Otherwise, the indexing operation might throw, so the loop will not 1101 // run to completion and the typed array might remain partly initialized. 1102 // However we further assume that the caller of this function is a typed array 1103 // constructor, and the exception will propagate out of the constructor, 1104 // therefore uninitialized memory will not be accessible by a user program. 1105 // 1106 // TODO(dslomov): revise this once we support subclassing. 1107 1108 if (!Runtime::SetupArrayBufferAllocatingData( 1109 isolate, buffer, byte_length, false)) { 1110 return isolate->Throw(*isolate->factory()-> 1111 NewRangeError("invalid_array_buffer_length", 1112 HandleVector<Object>(NULL, 0))); 1113 } 1114 1115 holder->set_buffer(*buffer); 1116 holder->set_byte_offset(Smi::FromInt(0)); 1117 Handle<Object> byte_length_obj( 1118 isolate->factory()->NewNumberFromSize(byte_length)); 1119 holder->set_byte_length(*byte_length_obj); 1120 holder->set_length(*length_obj); 1121 holder->set_weak_next(buffer->weak_first_view()); 1122 buffer->set_weak_first_view(*holder); 1123 1124 Handle<ExternalArray> elements = 1125 isolate->factory()->NewExternalArray( 1126 static_cast<int>(length), array_type, 1127 static_cast<uint8_t*>(buffer->backing_store())); 1128 Handle<Map> map = JSObject::GetElementsTransitionMap( 1129 holder, external_elements_kind); 1130 JSObject::SetMapAndElements(holder, map, elements); 1131 1132 if (source->IsJSTypedArray()) { 1133 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); 1134 1135 if (typed_array->type() == holder->type()) { 1136 uint8_t* backing_store = 1137 static_cast<uint8_t*>( 1138 typed_array->GetBuffer()->backing_store()); 1139 size_t source_byte_offset = 1140 NumberToSize(isolate, typed_array->byte_offset()); 1141 memcpy( 1142 buffer->backing_store(), 1143 backing_store + source_byte_offset, 1144 byte_length); 1145 return isolate->heap()->true_value(); 1146 } 1147 } 1148 1149 return isolate->heap()->false_value(); 1150 } 1151 1152 1153 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \ 1154 RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \ 1155 HandleScope scope(isolate); \ 1156 ASSERT(args.length() == 1); \ 1157 CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \ 1158 return holder->accessor(); \ 1159 } 1160 1161 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length) 1162 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset) 1163 BUFFER_VIEW_GETTER(TypedArray, Length, length) 1164 BUFFER_VIEW_GETTER(DataView, Buffer, buffer) 1165 1166 #undef BUFFER_VIEW_GETTER 1167 1168 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) { 1169 HandleScope scope(isolate); 1170 ASSERT(args.length() == 1); 1171 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 1172 return *holder->GetBuffer(); 1173 } 1174 1175 1176 // Return codes for Runtime_TypedArraySetFastCases. 1177 // Should be synchronized with typedarray.js natives. 1178 enum TypedArraySetResultCodes { 1179 // Set from typed array of the same type. 1180 // This is processed by TypedArraySetFastCases 1181 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, 1182 // Set from typed array of the different type, overlapping in memory. 1183 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, 1184 // Set from typed array of the different type, non-overlapping. 1185 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, 1186 // Set from non-typed array. 1187 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 1188 }; 1189 1190 1191 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) { 1192 HandleScope scope(isolate); 1193 ASSERT(args.length() == 3); 1194 if (!args[0]->IsJSTypedArray()) 1195 return isolate->Throw(*isolate->factory()->NewTypeError( 1196 "not_typed_array", HandleVector<Object>(NULL, 0))); 1197 1198 if (!args[1]->IsJSTypedArray()) 1199 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); 1200 1201 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0); 1202 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1); 1203 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2); 1204 1205 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); 1206 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); 1207 size_t offset = 0; 1208 RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset)); 1209 size_t target_length = NumberToSize(isolate, target->length()); 1210 size_t source_length = NumberToSize(isolate, source->length()); 1211 size_t target_byte_length = NumberToSize(isolate, target->byte_length()); 1212 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); 1213 if (offset > target_length || 1214 offset + source_length > target_length || 1215 offset + source_length < offset) // overflow 1216 return isolate->Throw(*isolate->factory()->NewRangeError( 1217 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0))); 1218 1219 size_t target_offset = NumberToSize(isolate, target->byte_offset()); 1220 size_t source_offset = NumberToSize(isolate, source->byte_offset()); 1221 uint8_t* target_base = 1222 static_cast<uint8_t*>( 1223 target->GetBuffer()->backing_store()) + target_offset; 1224 uint8_t* source_base = 1225 static_cast<uint8_t*>( 1226 source->GetBuffer()->backing_store()) + source_offset; 1227 1228 // Typed arrays of the same type: use memmove. 1229 if (target->type() == source->type()) { 1230 memmove(target_base + offset * target->element_size(), 1231 source_base, source_byte_length); 1232 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); 1233 } 1234 1235 // Typed arrays of different types over the same backing store 1236 if ((source_base <= target_base && 1237 source_base + source_byte_length > target_base) || 1238 (target_base <= source_base && 1239 target_base + target_byte_length > source_base)) { 1240 // We do not support overlapping ArrayBuffers 1241 ASSERT( 1242 target->GetBuffer()->backing_store() == 1243 source->GetBuffer()->backing_store()); 1244 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); 1245 } else { // Non-overlapping typed arrays 1246 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); 1247 } 1248 } 1249 1250 1251 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) { 1252 ASSERT(args.length() == 0); 1253 ASSERT_OBJECT_SIZE( 1254 FLAG_typed_array_max_size_in_heap + FixedTypedArrayBase::kDataOffset); 1255 return Smi::FromInt(FLAG_typed_array_max_size_in_heap); 1256 } 1257 1258 1259 RUNTIME_FUNCTION(Runtime_DataViewInitialize) { 1260 HandleScope scope(isolate); 1261 ASSERT(args.length() == 4); 1262 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); 1263 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); 1264 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2); 1265 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3); 1266 1267 ASSERT(holder->GetInternalFieldCount() == 1268 v8::ArrayBufferView::kInternalFieldCount); 1269 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 1270 holder->SetInternalField(i, Smi::FromInt(0)); 1271 } 1272 size_t buffer_length = 0; 1273 size_t offset = 0; 1274 size_t length = 0; 1275 RUNTIME_ASSERT( 1276 TryNumberToSize(isolate, buffer->byte_length(), &buffer_length)); 1277 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset)); 1278 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length)); 1279 1280 // TODO(jkummerow): When we have a "safe numerics" helper class, use it here. 1281 // Entire range [offset, offset + length] must be in bounds. 1282 RUNTIME_ASSERT(offset <= buffer_length); 1283 RUNTIME_ASSERT(offset + length <= buffer_length); 1284 // No overflow. 1285 RUNTIME_ASSERT(offset + length >= offset); 1286 1287 holder->set_buffer(*buffer); 1288 holder->set_byte_offset(*byte_offset); 1289 holder->set_byte_length(*byte_length); 1290 1291 holder->set_weak_next(buffer->weak_first_view()); 1292 buffer->set_weak_first_view(*holder); 1293 1294 return isolate->heap()->undefined_value(); 1295 } 1296 1297 1298 inline static bool NeedToFlipBytes(bool is_little_endian) { 1299 #ifdef V8_TARGET_LITTLE_ENDIAN 1300 return !is_little_endian; 1301 #else 1302 return is_little_endian; 1303 #endif 1304 } 1305 1306 1307 template<int n> 1308 inline void CopyBytes(uint8_t* target, uint8_t* source) { 1309 for (int i = 0; i < n; i++) { 1310 *(target++) = *(source++); 1311 } 1312 } 1313 1314 1315 template<int n> 1316 inline void FlipBytes(uint8_t* target, uint8_t* source) { 1317 source = source + (n-1); 1318 for (int i = 0; i < n; i++) { 1319 *(target++) = *(source--); 1320 } 1321 } 1322 1323 1324 template<typename T> 1325 inline static bool DataViewGetValue( 1326 Isolate* isolate, 1327 Handle<JSDataView> data_view, 1328 Handle<Object> byte_offset_obj, 1329 bool is_little_endian, 1330 T* result) { 1331 size_t byte_offset = 0; 1332 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { 1333 return false; 1334 } 1335 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1336 1337 size_t data_view_byte_offset = 1338 NumberToSize(isolate, data_view->byte_offset()); 1339 size_t data_view_byte_length = 1340 NumberToSize(isolate, data_view->byte_length()); 1341 if (byte_offset + sizeof(T) > data_view_byte_length || 1342 byte_offset + sizeof(T) < byte_offset) { // overflow 1343 return false; 1344 } 1345 1346 union Value { 1347 T data; 1348 uint8_t bytes[sizeof(T)]; 1349 }; 1350 1351 Value value; 1352 size_t buffer_offset = data_view_byte_offset + byte_offset; 1353 ASSERT( 1354 NumberToSize(isolate, buffer->byte_length()) 1355 >= buffer_offset + sizeof(T)); 1356 uint8_t* source = 1357 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1358 if (NeedToFlipBytes(is_little_endian)) { 1359 FlipBytes<sizeof(T)>(value.bytes, source); 1360 } else { 1361 CopyBytes<sizeof(T)>(value.bytes, source); 1362 } 1363 *result = value.data; 1364 return true; 1365 } 1366 1367 1368 template<typename T> 1369 static bool DataViewSetValue( 1370 Isolate* isolate, 1371 Handle<JSDataView> data_view, 1372 Handle<Object> byte_offset_obj, 1373 bool is_little_endian, 1374 T data) { 1375 size_t byte_offset = 0; 1376 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { 1377 return false; 1378 } 1379 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1380 1381 size_t data_view_byte_offset = 1382 NumberToSize(isolate, data_view->byte_offset()); 1383 size_t data_view_byte_length = 1384 NumberToSize(isolate, data_view->byte_length()); 1385 if (byte_offset + sizeof(T) > data_view_byte_length || 1386 byte_offset + sizeof(T) < byte_offset) { // overflow 1387 return false; 1388 } 1389 1390 union Value { 1391 T data; 1392 uint8_t bytes[sizeof(T)]; 1393 }; 1394 1395 Value value; 1396 value.data = data; 1397 size_t buffer_offset = data_view_byte_offset + byte_offset; 1398 ASSERT( 1399 NumberToSize(isolate, buffer->byte_length()) 1400 >= buffer_offset + sizeof(T)); 1401 uint8_t* target = 1402 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1403 if (NeedToFlipBytes(is_little_endian)) { 1404 FlipBytes<sizeof(T)>(target, value.bytes); 1405 } else { 1406 CopyBytes<sizeof(T)>(target, value.bytes); 1407 } 1408 return true; 1409 } 1410 1411 1412 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ 1413 RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \ 1414 HandleScope scope(isolate); \ 1415 ASSERT(args.length() == 3); \ 1416 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1417 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ 1418 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ 1419 Type result; \ 1420 if (DataViewGetValue( \ 1421 isolate, holder, offset, is_little_endian, &result)) { \ 1422 return *isolate->factory()->Converter(result); \ 1423 } else { \ 1424 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1425 "invalid_data_view_accessor_offset", \ 1426 HandleVector<Object>(NULL, 0))); \ 1427 } \ 1428 } 1429 1430 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint) 1431 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt) 1432 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint) 1433 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt) 1434 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint) 1435 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt) 1436 DATA_VIEW_GETTER(Float32, float, NewNumber) 1437 DATA_VIEW_GETTER(Float64, double, NewNumber) 1438 1439 #undef DATA_VIEW_GETTER 1440 1441 1442 template <typename T> 1443 static T DataViewConvertValue(double value); 1444 1445 1446 template <> 1447 int8_t DataViewConvertValue<int8_t>(double value) { 1448 return static_cast<int8_t>(DoubleToInt32(value)); 1449 } 1450 1451 1452 template <> 1453 int16_t DataViewConvertValue<int16_t>(double value) { 1454 return static_cast<int16_t>(DoubleToInt32(value)); 1455 } 1456 1457 1458 template <> 1459 int32_t DataViewConvertValue<int32_t>(double value) { 1460 return DoubleToInt32(value); 1461 } 1462 1463 1464 template <> 1465 uint8_t DataViewConvertValue<uint8_t>(double value) { 1466 return static_cast<uint8_t>(DoubleToUint32(value)); 1467 } 1468 1469 1470 template <> 1471 uint16_t DataViewConvertValue<uint16_t>(double value) { 1472 return static_cast<uint16_t>(DoubleToUint32(value)); 1473 } 1474 1475 1476 template <> 1477 uint32_t DataViewConvertValue<uint32_t>(double value) { 1478 return DoubleToUint32(value); 1479 } 1480 1481 1482 template <> 1483 float DataViewConvertValue<float>(double value) { 1484 return static_cast<float>(value); 1485 } 1486 1487 1488 template <> 1489 double DataViewConvertValue<double>(double value) { 1490 return value; 1491 } 1492 1493 1494 #define DATA_VIEW_SETTER(TypeName, Type) \ 1495 RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \ 1496 HandleScope scope(isolate); \ 1497 ASSERT(args.length() == 4); \ 1498 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1499 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \ 1500 CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \ 1501 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ 1502 Type v = DataViewConvertValue<Type>(value->Number()); \ 1503 if (DataViewSetValue( \ 1504 isolate, holder, offset, is_little_endian, v)) { \ 1505 return isolate->heap()->undefined_value(); \ 1506 } else { \ 1507 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1508 "invalid_data_view_accessor_offset", \ 1509 HandleVector<Object>(NULL, 0))); \ 1510 } \ 1511 } 1512 1513 DATA_VIEW_SETTER(Uint8, uint8_t) 1514 DATA_VIEW_SETTER(Int8, int8_t) 1515 DATA_VIEW_SETTER(Uint16, uint16_t) 1516 DATA_VIEW_SETTER(Int16, int16_t) 1517 DATA_VIEW_SETTER(Uint32, uint32_t) 1518 DATA_VIEW_SETTER(Int32, int32_t) 1519 DATA_VIEW_SETTER(Float32, float) 1520 DATA_VIEW_SETTER(Float64, double) 1521 1522 #undef DATA_VIEW_SETTER 1523 1524 1525 RUNTIME_FUNCTION(Runtime_SetInitialize) { 1526 HandleScope scope(isolate); 1527 ASSERT(args.length() == 1); 1528 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1529 Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet(); 1530 holder->set_table(*table); 1531 return *holder; 1532 } 1533 1534 1535 RUNTIME_FUNCTION(Runtime_SetAdd) { 1536 HandleScope scope(isolate); 1537 ASSERT(args.length() == 2); 1538 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1539 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1540 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); 1541 table = OrderedHashSet::Add(table, key); 1542 holder->set_table(*table); 1543 return isolate->heap()->undefined_value(); 1544 } 1545 1546 1547 RUNTIME_FUNCTION(Runtime_SetHas) { 1548 HandleScope scope(isolate); 1549 ASSERT(args.length() == 2); 1550 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1551 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1552 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); 1553 return isolate->heap()->ToBoolean(table->Contains(key)); 1554 } 1555 1556 1557 RUNTIME_FUNCTION(Runtime_SetDelete) { 1558 HandleScope scope(isolate); 1559 ASSERT(args.length() == 2); 1560 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1561 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1562 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); 1563 bool was_present = false; 1564 table = OrderedHashSet::Remove(table, key, &was_present); 1565 holder->set_table(*table); 1566 return isolate->heap()->ToBoolean(was_present); 1567 } 1568 1569 1570 RUNTIME_FUNCTION(Runtime_SetClear) { 1571 HandleScope scope(isolate); 1572 ASSERT(args.length() == 1); 1573 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1574 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); 1575 table = OrderedHashSet::Clear(table); 1576 holder->set_table(*table); 1577 return isolate->heap()->undefined_value(); 1578 } 1579 1580 1581 RUNTIME_FUNCTION(Runtime_SetGetSize) { 1582 HandleScope scope(isolate); 1583 ASSERT(args.length() == 1); 1584 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1585 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table())); 1586 return Smi::FromInt(table->NumberOfElements()); 1587 } 1588 1589 1590 RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) { 1591 HandleScope scope(isolate); 1592 ASSERT(args.length() == 3); 1593 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); 1594 CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1); 1595 CONVERT_SMI_ARG_CHECKED(kind, 2) 1596 RUNTIME_ASSERT(kind == JSSetIterator::kKindValues || 1597 kind == JSSetIterator::kKindEntries); 1598 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); 1599 holder->set_table(*table); 1600 holder->set_index(Smi::FromInt(0)); 1601 holder->set_kind(Smi::FromInt(kind)); 1602 return isolate->heap()->undefined_value(); 1603 } 1604 1605 1606 RUNTIME_FUNCTION(Runtime_SetIteratorNext) { 1607 HandleScope scope(isolate); 1608 ASSERT(args.length() == 1); 1609 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); 1610 return *JSSetIterator::Next(holder); 1611 } 1612 1613 1614 RUNTIME_FUNCTION(Runtime_MapInitialize) { 1615 HandleScope scope(isolate); 1616 ASSERT(args.length() == 1); 1617 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1618 Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap(); 1619 holder->set_table(*table); 1620 return *holder; 1621 } 1622 1623 1624 RUNTIME_FUNCTION(Runtime_MapGet) { 1625 HandleScope scope(isolate); 1626 ASSERT(args.length() == 2); 1627 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1628 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1629 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1630 Handle<Object> lookup(table->Lookup(key), isolate); 1631 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1632 } 1633 1634 1635 RUNTIME_FUNCTION(Runtime_MapHas) { 1636 HandleScope scope(isolate); 1637 ASSERT(args.length() == 2); 1638 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1639 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1640 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1641 Handle<Object> lookup(table->Lookup(key), isolate); 1642 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1643 } 1644 1645 1646 RUNTIME_FUNCTION(Runtime_MapDelete) { 1647 HandleScope scope(isolate); 1648 ASSERT(args.length() == 2); 1649 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1650 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1651 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1652 bool was_present = false; 1653 Handle<OrderedHashMap> new_table = 1654 OrderedHashMap::Remove(table, key, &was_present); 1655 holder->set_table(*new_table); 1656 return isolate->heap()->ToBoolean(was_present); 1657 } 1658 1659 1660 RUNTIME_FUNCTION(Runtime_MapClear) { 1661 HandleScope scope(isolate); 1662 ASSERT(args.length() == 1); 1663 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1664 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1665 table = OrderedHashMap::Clear(table); 1666 holder->set_table(*table); 1667 return isolate->heap()->undefined_value(); 1668 } 1669 1670 1671 RUNTIME_FUNCTION(Runtime_MapSet) { 1672 HandleScope scope(isolate); 1673 ASSERT(args.length() == 3); 1674 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1675 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1676 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 1677 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1678 Handle<OrderedHashMap> new_table = OrderedHashMap::Put(table, key, value); 1679 holder->set_table(*new_table); 1680 return isolate->heap()->undefined_value(); 1681 } 1682 1683 1684 RUNTIME_FUNCTION(Runtime_MapGetSize) { 1685 HandleScope scope(isolate); 1686 ASSERT(args.length() == 1); 1687 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1688 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table())); 1689 return Smi::FromInt(table->NumberOfElements()); 1690 } 1691 1692 1693 RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) { 1694 HandleScope scope(isolate); 1695 ASSERT(args.length() == 3); 1696 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); 1697 CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1); 1698 CONVERT_SMI_ARG_CHECKED(kind, 2) 1699 RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys 1700 || kind == JSMapIterator::kKindValues 1701 || kind == JSMapIterator::kKindEntries); 1702 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); 1703 holder->set_table(*table); 1704 holder->set_index(Smi::FromInt(0)); 1705 holder->set_kind(Smi::FromInt(kind)); 1706 return isolate->heap()->undefined_value(); 1707 } 1708 1709 1710 RUNTIME_FUNCTION(Runtime_MapIteratorNext) { 1711 HandleScope scope(isolate); 1712 ASSERT(args.length() == 1); 1713 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); 1714 return *JSMapIterator::Next(holder); 1715 } 1716 1717 1718 static Handle<JSWeakCollection> WeakCollectionInitialize( 1719 Isolate* isolate, 1720 Handle<JSWeakCollection> weak_collection) { 1721 ASSERT(weak_collection->map()->inobject_properties() == 0); 1722 Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0); 1723 weak_collection->set_table(*table); 1724 return weak_collection; 1725 } 1726 1727 1728 RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) { 1729 HandleScope scope(isolate); 1730 ASSERT(args.length() == 1); 1731 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1732 return *WeakCollectionInitialize(isolate, weak_collection); 1733 } 1734 1735 1736 RUNTIME_FUNCTION(Runtime_WeakCollectionGet) { 1737 HandleScope scope(isolate); 1738 ASSERT(args.length() == 2); 1739 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1740 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1741 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); 1742 Handle<ObjectHashTable> table( 1743 ObjectHashTable::cast(weak_collection->table())); 1744 RUNTIME_ASSERT(table->IsKey(*key)); 1745 Handle<Object> lookup(table->Lookup(key), isolate); 1746 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1747 } 1748 1749 1750 RUNTIME_FUNCTION(Runtime_WeakCollectionHas) { 1751 HandleScope scope(isolate); 1752 ASSERT(args.length() == 2); 1753 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1754 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1755 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); 1756 Handle<ObjectHashTable> table( 1757 ObjectHashTable::cast(weak_collection->table())); 1758 RUNTIME_ASSERT(table->IsKey(*key)); 1759 Handle<Object> lookup(table->Lookup(key), isolate); 1760 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1761 } 1762 1763 1764 RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) { 1765 HandleScope scope(isolate); 1766 ASSERT(args.length() == 2); 1767 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1768 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1769 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); 1770 Handle<ObjectHashTable> table(ObjectHashTable::cast( 1771 weak_collection->table())); 1772 RUNTIME_ASSERT(table->IsKey(*key)); 1773 bool was_present = false; 1774 Handle<ObjectHashTable> new_table = 1775 ObjectHashTable::Remove(table, key, &was_present); 1776 weak_collection->set_table(*new_table); 1777 return isolate->heap()->ToBoolean(was_present); 1778 } 1779 1780 1781 RUNTIME_FUNCTION(Runtime_WeakCollectionSet) { 1782 HandleScope scope(isolate); 1783 ASSERT(args.length() == 3); 1784 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1785 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1786 RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol()); 1787 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 1788 Handle<ObjectHashTable> table( 1789 ObjectHashTable::cast(weak_collection->table())); 1790 RUNTIME_ASSERT(table->IsKey(*key)); 1791 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); 1792 weak_collection->set_table(*new_table); 1793 return isolate->heap()->undefined_value(); 1794 } 1795 1796 1797 RUNTIME_FUNCTION(Runtime_ClassOf) { 1798 SealHandleScope shs(isolate); 1799 ASSERT(args.length() == 1); 1800 CONVERT_ARG_CHECKED(Object, obj, 0); 1801 if (!obj->IsJSObject()) return isolate->heap()->null_value(); 1802 return JSObject::cast(obj)->class_name(); 1803 } 1804 1805 1806 RUNTIME_FUNCTION(Runtime_GetPrototype) { 1807 HandleScope scope(isolate); 1808 ASSERT(args.length() == 1); 1809 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 1810 // We don't expect access checks to be needed on JSProxy objects. 1811 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); 1812 do { 1813 if (obj->IsAccessCheckNeeded() && 1814 !isolate->MayNamedAccess(Handle<JSObject>::cast(obj), 1815 isolate->factory()->proto_string(), 1816 v8::ACCESS_GET)) { 1817 isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(obj), 1818 v8::ACCESS_GET); 1819 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 1820 return isolate->heap()->undefined_value(); 1821 } 1822 obj = Object::GetPrototype(isolate, obj); 1823 } while (obj->IsJSObject() && 1824 JSObject::cast(*obj)->map()->is_hidden_prototype()); 1825 return *obj; 1826 } 1827 1828 1829 static inline Handle<Object> GetPrototypeSkipHiddenPrototypes( 1830 Isolate* isolate, Handle<Object> receiver) { 1831 Handle<Object> current = Object::GetPrototype(isolate, receiver); 1832 while (current->IsJSObject() && 1833 JSObject::cast(*current)->map()->is_hidden_prototype()) { 1834 current = Object::GetPrototype(isolate, current); 1835 } 1836 return current; 1837 } 1838 1839 1840 RUNTIME_FUNCTION(Runtime_SetPrototype) { 1841 HandleScope scope(isolate); 1842 ASSERT(args.length() == 2); 1843 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1844 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 1845 if (obj->IsAccessCheckNeeded() && 1846 !isolate->MayNamedAccess( 1847 obj, isolate->factory()->proto_string(), v8::ACCESS_SET)) { 1848 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET); 1849 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 1850 return isolate->heap()->undefined_value(); 1851 } 1852 if (obj->map()->is_observed()) { 1853 Handle<Object> old_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); 1854 Handle<Object> result; 1855 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1856 isolate, result, 1857 JSObject::SetPrototype(obj, prototype, true)); 1858 1859 Handle<Object> new_value = GetPrototypeSkipHiddenPrototypes(isolate, obj); 1860 if (!new_value->SameValue(*old_value)) { 1861 JSObject::EnqueueChangeRecord(obj, "setPrototype", 1862 isolate->factory()->proto_string(), 1863 old_value); 1864 } 1865 return *result; 1866 } 1867 Handle<Object> result; 1868 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1869 isolate, result, 1870 JSObject::SetPrototype(obj, prototype, true)); 1871 return *result; 1872 } 1873 1874 1875 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) { 1876 HandleScope shs(isolate); 1877 ASSERT(args.length() == 2); 1878 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). 1879 CONVERT_ARG_HANDLE_CHECKED(Object, O, 0); 1880 CONVERT_ARG_HANDLE_CHECKED(Object, V, 1); 1881 while (true) { 1882 Handle<Object> prototype = Object::GetPrototype(isolate, V); 1883 if (prototype->IsNull()) return isolate->heap()->false_value(); 1884 if (*O == *prototype) return isolate->heap()->true_value(); 1885 V = prototype; 1886 } 1887 } 1888 1889 1890 static bool CheckAccessException(Object* callback, 1891 v8::AccessType access_type) { 1892 DisallowHeapAllocation no_gc; 1893 ASSERT(!callback->IsForeign()); 1894 if (callback->IsAccessorInfo()) { 1895 AccessorInfo* info = AccessorInfo::cast(callback); 1896 return 1897 (access_type == v8::ACCESS_HAS && 1898 (info->all_can_read() || info->all_can_write())) || 1899 (access_type == v8::ACCESS_GET && info->all_can_read()) || 1900 (access_type == v8::ACCESS_SET && info->all_can_write()); 1901 } 1902 if (callback->IsAccessorPair()) { 1903 AccessorPair* info = AccessorPair::cast(callback); 1904 return 1905 (access_type == v8::ACCESS_HAS && 1906 (info->all_can_read() || info->all_can_write())) || 1907 (access_type == v8::ACCESS_GET && info->all_can_read()) || 1908 (access_type == v8::ACCESS_SET && info->all_can_write()); 1909 } 1910 return false; 1911 } 1912 1913 1914 template<class Key> 1915 static bool CheckGenericAccess( 1916 Handle<JSObject> receiver, 1917 Handle<JSObject> holder, 1918 Key key, 1919 v8::AccessType access_type, 1920 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) { 1921 Isolate* isolate = receiver->GetIsolate(); 1922 for (Handle<JSObject> current = receiver; 1923 true; 1924 current = handle(JSObject::cast(current->GetPrototype()), isolate)) { 1925 if (current->IsAccessCheckNeeded() && 1926 !(isolate->*mayAccess)(current, key, access_type)) { 1927 return false; 1928 } 1929 if (current.is_identical_to(holder)) break; 1930 } 1931 return true; 1932 } 1933 1934 1935 enum AccessCheckResult { 1936 ACCESS_FORBIDDEN, 1937 ACCESS_ALLOWED, 1938 ACCESS_ABSENT 1939 }; 1940 1941 1942 static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj, 1943 Handle<Name> name, 1944 v8::AccessType access_type) { 1945 uint32_t index; 1946 if (name->AsArrayIndex(&index)) { 1947 // TODO(1095): we should traverse hidden prototype hierachy as well. 1948 if (CheckGenericAccess( 1949 obj, obj, index, access_type, &Isolate::MayIndexedAccess)) { 1950 return ACCESS_ALLOWED; 1951 } 1952 1953 obj->GetIsolate()->ReportFailedAccessCheck(obj, access_type); 1954 return ACCESS_FORBIDDEN; 1955 } 1956 1957 Isolate* isolate = obj->GetIsolate(); 1958 LookupResult lookup(isolate); 1959 obj->LookupOwn(name, &lookup, true); 1960 1961 if (!lookup.IsProperty()) return ACCESS_ABSENT; 1962 Handle<JSObject> holder(lookup.holder(), isolate); 1963 if (CheckGenericAccess<Handle<Object> >( 1964 obj, holder, name, access_type, &Isolate::MayNamedAccess)) { 1965 return ACCESS_ALLOWED; 1966 } 1967 1968 // Access check callback denied the access, but some properties 1969 // can have a special permissions which override callbacks descision 1970 // (currently see v8::AccessControl). 1971 // API callbacks can have per callback access exceptions. 1972 switch (lookup.type()) { 1973 case CALLBACKS: 1974 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1975 return ACCESS_ALLOWED; 1976 } 1977 break; 1978 case INTERCEPTOR: 1979 // If the object has an interceptor, try real named properties. 1980 // Overwrite the result to fetch the correct property later. 1981 holder->LookupRealNamedProperty(name, &lookup); 1982 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) { 1983 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1984 return ACCESS_ALLOWED; 1985 } 1986 } 1987 break; 1988 default: 1989 break; 1990 } 1991 1992 isolate->ReportFailedAccessCheck(obj, access_type); 1993 return ACCESS_FORBIDDEN; 1994 } 1995 1996 1997 // Enumerator used as indices into the array returned from GetOwnProperty 1998 enum PropertyDescriptorIndices { 1999 IS_ACCESSOR_INDEX, 2000 VALUE_INDEX, 2001 GETTER_INDEX, 2002 SETTER_INDEX, 2003 WRITABLE_INDEX, 2004 ENUMERABLE_INDEX, 2005 CONFIGURABLE_INDEX, 2006 DESCRIPTOR_SIZE 2007 }; 2008 2009 2010 MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate, 2011 Handle<JSObject> obj, 2012 Handle<Name> name) { 2013 Heap* heap = isolate->heap(); 2014 Factory* factory = isolate->factory(); 2015 // Due to some WebKit tests, we want to make sure that we do not log 2016 // more than one access failure here. 2017 AccessCheckResult access_check_result = 2018 CheckPropertyAccess(obj, name, v8::ACCESS_HAS); 2019 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 2020 switch (access_check_result) { 2021 case ACCESS_FORBIDDEN: return factory->false_value(); 2022 case ACCESS_ALLOWED: break; 2023 case ACCESS_ABSENT: return factory->undefined_value(); 2024 } 2025 2026 PropertyAttributes attrs = JSReceiver::GetOwnPropertyAttributes(obj, name); 2027 if (attrs == ABSENT) { 2028 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 2029 return factory->undefined_value(); 2030 } 2031 ASSERT(!isolate->has_scheduled_exception()); 2032 Handle<AccessorPair> accessors; 2033 bool has_accessors = 2034 JSObject::GetOwnPropertyAccessorPair(obj, name).ToHandle(&accessors); 2035 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); 2036 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); 2037 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); 2038 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(has_accessors)); 2039 2040 if (!has_accessors) { 2041 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); 2042 // Runtime::GetObjectProperty does access check. 2043 Handle<Object> value; 2044 ASSIGN_RETURN_ON_EXCEPTION( 2045 isolate, value, Runtime::GetObjectProperty(isolate, obj, name), 2046 Object); 2047 elms->set(VALUE_INDEX, *value); 2048 } else { 2049 // Access checks are performed for both accessors separately. 2050 // When they fail, the respective field is not set in the descriptor. 2051 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); 2052 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); 2053 2054 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) { 2055 ASSERT(!isolate->has_scheduled_exception()); 2056 elms->set(GETTER_INDEX, *getter); 2057 } else { 2058 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 2059 } 2060 2061 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) { 2062 ASSERT(!isolate->has_scheduled_exception()); 2063 elms->set(SETTER_INDEX, *setter); 2064 } else { 2065 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 2066 } 2067 } 2068 2069 return isolate->factory()->NewJSArrayWithElements(elms); 2070 } 2071 2072 2073 // Returns an array with the property description: 2074 // if args[1] is not a property on args[0] 2075 // returns undefined 2076 // if args[1] is a data property on args[0] 2077 // [false, value, Writeable, Enumerable, Configurable] 2078 // if args[1] is an accessor on args[0] 2079 // [true, GetFunction, SetFunction, Enumerable, Configurable] 2080 RUNTIME_FUNCTION(Runtime_GetOwnProperty) { 2081 HandleScope scope(isolate); 2082 ASSERT(args.length() == 2); 2083 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 2084 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 2085 Handle<Object> result; 2086 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2087 isolate, result, GetOwnProperty(isolate, obj, name)); 2088 return *result; 2089 } 2090 2091 2092 RUNTIME_FUNCTION(Runtime_PreventExtensions) { 2093 HandleScope scope(isolate); 2094 ASSERT(args.length() == 1); 2095 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 2096 Handle<Object> result; 2097 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2098 isolate, result, JSObject::PreventExtensions(obj)); 2099 return *result; 2100 } 2101 2102 2103 RUNTIME_FUNCTION(Runtime_IsExtensible) { 2104 SealHandleScope shs(isolate); 2105 ASSERT(args.length() == 1); 2106 CONVERT_ARG_CHECKED(JSObject, obj, 0); 2107 if (obj->IsJSGlobalProxy()) { 2108 Object* proto = obj->GetPrototype(); 2109 if (proto->IsNull()) return isolate->heap()->false_value(); 2110 ASSERT(proto->IsJSGlobalObject()); 2111 obj = JSObject::cast(proto); 2112 } 2113 return isolate->heap()->ToBoolean(obj->map()->is_extensible()); 2114 } 2115 2116 2117 RUNTIME_FUNCTION(Runtime_RegExpCompile) { 2118 HandleScope scope(isolate); 2119 ASSERT(args.length() == 3); 2120 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); 2121 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 2122 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); 2123 Handle<Object> result; 2124 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2125 isolate, result, RegExpImpl::Compile(re, pattern, flags)); 2126 return *result; 2127 } 2128 2129 2130 RUNTIME_FUNCTION(Runtime_CreateApiFunction) { 2131 HandleScope scope(isolate); 2132 ASSERT(args.length() == 2); 2133 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); 2134 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 2135 return *isolate->factory()->CreateApiFunction(data, prototype); 2136 } 2137 2138 2139 RUNTIME_FUNCTION(Runtime_IsTemplate) { 2140 SealHandleScope shs(isolate); 2141 ASSERT(args.length() == 1); 2142 CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0); 2143 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); 2144 return isolate->heap()->ToBoolean(result); 2145 } 2146 2147 2148 RUNTIME_FUNCTION(Runtime_GetTemplateField) { 2149 SealHandleScope shs(isolate); 2150 ASSERT(args.length() == 2); 2151 CONVERT_ARG_CHECKED(HeapObject, templ, 0); 2152 CONVERT_SMI_ARG_CHECKED(index, 1); 2153 int offset = index * kPointerSize + HeapObject::kHeaderSize; 2154 InstanceType type = templ->map()->instance_type(); 2155 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || 2156 type == OBJECT_TEMPLATE_INFO_TYPE); 2157 RUNTIME_ASSERT(offset > 0); 2158 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { 2159 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); 2160 } else { 2161 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 2162 } 2163 return *HeapObject::RawField(templ, offset); 2164 } 2165 2166 2167 RUNTIME_FUNCTION(Runtime_DisableAccessChecks) { 2168 HandleScope scope(isolate); 2169 ASSERT(args.length() == 1); 2170 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); 2171 Handle<Map> old_map(object->map()); 2172 bool needs_access_checks = old_map->is_access_check_needed(); 2173 if (needs_access_checks) { 2174 // Copy map so it won't interfere constructor's initial map. 2175 Handle<Map> new_map = Map::Copy(old_map); 2176 new_map->set_is_access_check_needed(false); 2177 if (object->IsJSObject()) { 2178 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); 2179 } else { 2180 object->set_map(*new_map); 2181 } 2182 } 2183 return isolate->heap()->ToBoolean(needs_access_checks); 2184 } 2185 2186 2187 RUNTIME_FUNCTION(Runtime_EnableAccessChecks) { 2188 HandleScope scope(isolate); 2189 ASSERT(args.length() == 1); 2190 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0); 2191 Handle<Map> old_map(object->map()); 2192 if (!old_map->is_access_check_needed()) { 2193 // Copy map so it won't interfere constructor's initial map. 2194 Handle<Map> new_map = Map::Copy(old_map); 2195 new_map->set_is_access_check_needed(true); 2196 if (object->IsJSObject()) { 2197 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); 2198 } else { 2199 object->set_map(*new_map); 2200 } 2201 } 2202 return isolate->heap()->undefined_value(); 2203 } 2204 2205 2206 // Transform getter or setter into something DefineAccessor can handle. 2207 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate, 2208 Handle<Object> component) { 2209 if (component->IsUndefined()) return isolate->factory()->null_value(); 2210 Handle<FunctionTemplateInfo> info = 2211 Handle<FunctionTemplateInfo>::cast(component); 2212 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction()); 2213 } 2214 2215 2216 RUNTIME_FUNCTION(Runtime_SetAccessorProperty) { 2217 HandleScope scope(isolate); 2218 ASSERT(args.length() == 6); 2219 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 2220 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 2221 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 2222 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 2223 CONVERT_SMI_ARG_CHECKED(attribute, 4); 2224 CONVERT_SMI_ARG_CHECKED(access_control, 5); 2225 RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo()); 2226 RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo()); 2227 RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid( 2228 static_cast<PropertyAttributes>(attribute))); 2229 JSObject::DefineAccessor(object, 2230 name, 2231 InstantiateAccessorComponent(isolate, getter), 2232 InstantiateAccessorComponent(isolate, setter), 2233 static_cast<PropertyAttributes>(attribute), 2234 static_cast<v8::AccessControl>(access_control)); 2235 return isolate->heap()->undefined_value(); 2236 } 2237 2238 2239 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) { 2240 HandleScope scope(isolate); 2241 Handle<Object> args[1] = { name }; 2242 Handle<Object> error = isolate->factory()->NewTypeError( 2243 "var_redeclaration", HandleVector(args, 1)); 2244 return isolate->Throw(*error); 2245 } 2246 2247 2248 RUNTIME_FUNCTION(RuntimeHidden_DeclareGlobals) { 2249 HandleScope scope(isolate); 2250 ASSERT(args.length() == 3); 2251 Handle<GlobalObject> global = Handle<GlobalObject>( 2252 isolate->context()->global_object()); 2253 2254 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 2255 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); 2256 CONVERT_SMI_ARG_CHECKED(flags, 2); 2257 2258 // Traverse the name/value pairs and set the properties. 2259 int length = pairs->length(); 2260 for (int i = 0; i < length; i += 2) { 2261 HandleScope scope(isolate); 2262 Handle<String> name(String::cast(pairs->get(i))); 2263 Handle<Object> value(pairs->get(i + 1), isolate); 2264 2265 // We have to declare a global const property. To capture we only 2266 // assign to it when evaluating the assignment for "const x = 2267 // <expr>" the initial value is the hole. 2268 bool is_var = value->IsUndefined(); 2269 bool is_const = value->IsTheHole(); 2270 bool is_function = value->IsSharedFunctionInfo(); 2271 ASSERT(is_var + is_const + is_function == 1); 2272 2273 if (is_var || is_const) { 2274 // Lookup the property in the global object, and don't set the 2275 // value of the variable if the property is already there. 2276 // Do the lookup own properties only, see ES5 erratum. 2277 LookupResult lookup(isolate); 2278 global->LookupOwn(name, &lookup, true); 2279 if (lookup.IsFound()) { 2280 // We found an existing property. Unless it was an interceptor 2281 // that claims the property is absent, skip this declaration. 2282 if (!lookup.IsInterceptor()) continue; 2283 if (JSReceiver::GetPropertyAttributes(global, name) != ABSENT) continue; 2284 // Fall-through and introduce the absent property by using 2285 // SetProperty. 2286 } 2287 } else if (is_function) { 2288 // Copy the function and update its context. Use it as value. 2289 Handle<SharedFunctionInfo> shared = 2290 Handle<SharedFunctionInfo>::cast(value); 2291 Handle<JSFunction> function = 2292 isolate->factory()->NewFunctionFromSharedFunctionInfo( 2293 shared, context, TENURED); 2294 value = function; 2295 } 2296 2297 LookupResult lookup(isolate); 2298 global->LookupOwn(name, &lookup, true); 2299 2300 // Compute the property attributes. According to ECMA-262, 2301 // the property must be non-configurable except in eval. 2302 int attr = NONE; 2303 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); 2304 if (!is_eval) { 2305 attr |= DONT_DELETE; 2306 } 2307 bool is_native = DeclareGlobalsNativeFlag::decode(flags); 2308 if (is_const || (is_native && is_function)) { 2309 attr |= READ_ONLY; 2310 } 2311 2312 StrictMode strict_mode = DeclareGlobalsStrictMode::decode(flags); 2313 2314 if (!lookup.IsFound() || is_function) { 2315 // If the own property exists, check that we can reconfigure it 2316 // as required for function declarations. 2317 if (lookup.IsFound() && lookup.IsDontDelete()) { 2318 if (lookup.IsReadOnly() || lookup.IsDontEnum() || 2319 lookup.IsPropertyCallbacks()) { 2320 return ThrowRedeclarationError(isolate, name); 2321 } 2322 // If the existing property is not configurable, keep its attributes. 2323 attr = lookup.GetAttributes(); 2324 } 2325 // Define or redefine own property. 2326 RETURN_FAILURE_ON_EXCEPTION(isolate, 2327 JSObject::SetOwnPropertyIgnoreAttributes( 2328 global, name, value, static_cast<PropertyAttributes>(attr))); 2329 } else { 2330 // Do a [[Put]] on the existing (own) property. 2331 RETURN_FAILURE_ON_EXCEPTION( 2332 isolate, 2333 JSObject::SetProperty( 2334 global, name, value, static_cast<PropertyAttributes>(attr), 2335 strict_mode)); 2336 } 2337 } 2338 2339 ASSERT(!isolate->has_pending_exception()); 2340 return isolate->heap()->undefined_value(); 2341 } 2342 2343 2344 RUNTIME_FUNCTION(RuntimeHidden_DeclareContextSlot) { 2345 HandleScope scope(isolate); 2346 ASSERT(args.length() == 4); 2347 2348 // Declarations are always made in a function or native context. In the 2349 // case of eval code, the context passed is the context of the caller, 2350 // which may be some nested context and not the declaration context. 2351 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0); 2352 Handle<Context> context(context_arg->declaration_context()); 2353 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 2354 CONVERT_SMI_ARG_CHECKED(mode_arg, 2); 2355 PropertyAttributes mode = static_cast<PropertyAttributes>(mode_arg); 2356 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); 2357 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3); 2358 2359 int index; 2360 PropertyAttributes attributes; 2361 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 2362 BindingFlags binding_flags; 2363 Handle<Object> holder = 2364 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2365 2366 if (attributes != ABSENT) { 2367 // The name was declared before; check for conflicting re-declarations. 2368 // Note: this is actually inconsistent with what happens for globals (where 2369 // we silently ignore such declarations). 2370 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 2371 // Functions are not read-only. 2372 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 2373 return ThrowRedeclarationError(isolate, name); 2374 } 2375 2376 // Initialize it if necessary. 2377 if (*initial_value != NULL) { 2378 if (index >= 0) { 2379 ASSERT(holder.is_identical_to(context)); 2380 if (((attributes & READ_ONLY) == 0) || 2381 context->get(index)->IsTheHole()) { 2382 context->set(index, *initial_value); 2383 } 2384 } else { 2385 // Slow case: The property is in the context extension object of a 2386 // function context or the global object of a native context. 2387 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2388 RETURN_FAILURE_ON_EXCEPTION( 2389 isolate, 2390 JSReceiver::SetProperty(object, name, initial_value, mode, SLOPPY)); 2391 } 2392 } 2393 2394 } else { 2395 // The property is not in the function context. It needs to be 2396 // "declared" in the function context's extension context or as a 2397 // property of the the global object. 2398 Handle<JSObject> object; 2399 if (context->has_extension()) { 2400 object = Handle<JSObject>(JSObject::cast(context->extension())); 2401 } else { 2402 // Context extension objects are allocated lazily. 2403 ASSERT(context->IsFunctionContext()); 2404 object = isolate->factory()->NewJSObject( 2405 isolate->context_extension_function()); 2406 context->set_extension(*object); 2407 } 2408 ASSERT(*object != NULL); 2409 2410 // Declare the property by setting it to the initial value if provided, 2411 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 2412 // constant declarations). 2413 ASSERT(!JSReceiver::HasOwnProperty(object, name)); 2414 Handle<Object> value(isolate->heap()->undefined_value(), isolate); 2415 if (*initial_value != NULL) value = initial_value; 2416 // Declaring a const context slot is a conflicting declaration if 2417 // there is a callback with that name in a prototype. It is 2418 // allowed to introduce const variables in 2419 // JSContextExtensionObjects. They are treated specially in 2420 // SetProperty and no setters are invoked for those since they are 2421 // not real JSObjects. 2422 if (initial_value->IsTheHole() && 2423 !object->IsJSContextExtensionObject()) { 2424 LookupResult lookup(isolate); 2425 object->Lookup(name, &lookup); 2426 if (lookup.IsPropertyCallbacks()) { 2427 return ThrowRedeclarationError(isolate, name); 2428 } 2429 } 2430 if (object->IsJSGlobalObject()) { 2431 // Define own property on the global object. 2432 RETURN_FAILURE_ON_EXCEPTION(isolate, 2433 JSObject::SetOwnPropertyIgnoreAttributes(object, name, value, mode)); 2434 } else { 2435 RETURN_FAILURE_ON_EXCEPTION(isolate, 2436 JSReceiver::SetProperty(object, name, value, mode, SLOPPY)); 2437 } 2438 } 2439 2440 return isolate->heap()->undefined_value(); 2441 } 2442 2443 2444 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) { 2445 HandleScope scope(isolate); 2446 // args[0] == name 2447 // args[1] == language_mode 2448 // args[2] == value (optional) 2449 2450 // Determine if we need to assign to the variable if it already 2451 // exists (based on the number of arguments). 2452 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); 2453 bool assign = args.length() == 3; 2454 2455 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2456 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 1); 2457 2458 // According to ECMA-262, section 12.2, page 62, the property must 2459 // not be deletable. 2460 PropertyAttributes attributes = DONT_DELETE; 2461 2462 // Lookup the property as own on the global object. If it isn't 2463 // there, there is a property with this name in the prototype chain. 2464 // We follow Safari and Firefox behavior and only set the property 2465 // if there is an explicit initialization value that we have 2466 // to assign to the property. 2467 // Note that objects can have hidden prototypes, so we need to traverse 2468 // the whole chain of hidden prototypes to do an 'own' lookup. 2469 LookupResult lookup(isolate); 2470 isolate->context()->global_object()->LookupOwn(name, &lookup, true); 2471 if (lookup.IsInterceptor()) { 2472 Handle<JSObject> holder(lookup.holder()); 2473 PropertyAttributes intercepted = 2474 JSReceiver::GetPropertyAttributes(holder, name); 2475 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 2476 // Found an interceptor that's not read only. 2477 if (assign) { 2478 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 2479 Handle<Object> result; 2480 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2481 isolate, result, 2482 JSObject::SetPropertyForResult( 2483 holder, &lookup, name, value, attributes, strict_mode)); 2484 return *result; 2485 } else { 2486 return isolate->heap()->undefined_value(); 2487 } 2488 } 2489 } 2490 2491 if (assign) { 2492 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 2493 Handle<GlobalObject> global(isolate->context()->global_object()); 2494 Handle<Object> result; 2495 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2496 isolate, result, 2497 JSReceiver::SetProperty(global, name, value, attributes, strict_mode)); 2498 return *result; 2499 } 2500 return isolate->heap()->undefined_value(); 2501 } 2502 2503 2504 RUNTIME_FUNCTION(RuntimeHidden_InitializeConstGlobal) { 2505 SealHandleScope shs(isolate); 2506 // All constants are declared with an initial value. The name 2507 // of the constant is the first argument and the initial value 2508 // is the second. 2509 RUNTIME_ASSERT(args.length() == 2); 2510 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2511 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 2512 2513 // Get the current global object from top. 2514 GlobalObject* global = isolate->context()->global_object(); 2515 2516 // According to ECMA-262, section 12.2, page 62, the property must 2517 // not be deletable. Since it's a const, it must be READ_ONLY too. 2518 PropertyAttributes attributes = 2519 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 2520 2521 // Lookup the property as own on the global object. If it isn't 2522 // there, we add the property and take special precautions to always 2523 // add it even in case of callbacks in the prototype chain (this rules 2524 // out using SetProperty). We use SetOwnPropertyIgnoreAttributes instead 2525 LookupResult lookup(isolate); 2526 global->LookupOwn(name, &lookup); 2527 if (!lookup.IsFound()) { 2528 HandleScope handle_scope(isolate); 2529 Handle<GlobalObject> global(isolate->context()->global_object()); 2530 RETURN_FAILURE_ON_EXCEPTION( 2531 isolate, 2532 JSObject::SetOwnPropertyIgnoreAttributes(global, name, value, 2533 attributes)); 2534 return *value; 2535 } 2536 2537 if (!lookup.IsReadOnly()) { 2538 // Restore global object from context (in case of GC) and continue 2539 // with setting the value. 2540 HandleScope handle_scope(isolate); 2541 Handle<GlobalObject> global(isolate->context()->global_object()); 2542 2543 // BUG 1213575: Handle the case where we have to set a read-only 2544 // property through an interceptor and only do it if it's 2545 // uninitialized, e.g. the hole. Nirk... 2546 // Passing sloppy mode because the property is writable. 2547 RETURN_FAILURE_ON_EXCEPTION( 2548 isolate, 2549 JSReceiver::SetProperty(global, name, value, attributes, SLOPPY)); 2550 return *value; 2551 } 2552 2553 // Set the value, but only if we're assigning the initial value to a 2554 // constant. For now, we determine this by checking if the 2555 // current value is the hole. 2556 // Strict mode handling not needed (const is disallowed in strict mode). 2557 if (lookup.IsField()) { 2558 FixedArray* properties = global->properties(); 2559 int index = lookup.GetFieldIndex().outobject_array_index(); 2560 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { 2561 properties->set(index, *value); 2562 } 2563 } else if (lookup.IsNormal()) { 2564 if (global->GetNormalizedProperty(&lookup)->IsTheHole() || 2565 !lookup.IsReadOnly()) { 2566 HandleScope scope(isolate); 2567 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value); 2568 } 2569 } else { 2570 // Ignore re-initialization of constants that have already been 2571 // assigned a constant value. 2572 ASSERT(lookup.IsReadOnly() && lookup.IsConstant()); 2573 } 2574 2575 // Use the set value as the result of the operation. 2576 return *value; 2577 } 2578 2579 2580 RUNTIME_FUNCTION(RuntimeHidden_InitializeConstContextSlot) { 2581 HandleScope scope(isolate); 2582 ASSERT(args.length() == 3); 2583 2584 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 2585 ASSERT(!value->IsTheHole()); 2586 // Initializations are always done in a function or native context. 2587 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1); 2588 Handle<Context> context(context_arg->declaration_context()); 2589 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); 2590 2591 int index; 2592 PropertyAttributes attributes; 2593 ContextLookupFlags flags = FOLLOW_CHAINS; 2594 BindingFlags binding_flags; 2595 Handle<Object> holder = 2596 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2597 2598 if (index >= 0) { 2599 ASSERT(holder->IsContext()); 2600 // Property was found in a context. Perform the assignment if we 2601 // found some non-constant or an uninitialized constant. 2602 Handle<Context> context = Handle<Context>::cast(holder); 2603 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { 2604 context->set(index, *value); 2605 } 2606 return *value; 2607 } 2608 2609 // The property could not be found, we introduce it as a property of the 2610 // global object. 2611 if (attributes == ABSENT) { 2612 Handle<JSObject> global = Handle<JSObject>( 2613 isolate->context()->global_object()); 2614 // Strict mode not needed (const disallowed in strict mode). 2615 RETURN_FAILURE_ON_EXCEPTION( 2616 isolate, 2617 JSReceiver::SetProperty(global, name, value, NONE, SLOPPY)); 2618 return *value; 2619 } 2620 2621 // The property was present in some function's context extension object, 2622 // as a property on the subject of a with, or as a property of the global 2623 // object. 2624 // 2625 // In most situations, eval-introduced consts should still be present in 2626 // the context extension object. However, because declaration and 2627 // initialization are separate, the property might have been deleted 2628 // before we reach the initialization point. 2629 // 2630 // Example: 2631 // 2632 // function f() { eval("delete x; const x;"); } 2633 // 2634 // In that case, the initialization behaves like a normal assignment. 2635 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2636 2637 if (*object == context->extension()) { 2638 // This is the property that was introduced by the const declaration. 2639 // Set it if it hasn't been set before. NOTE: We cannot use 2640 // GetProperty() to get the current value as it 'unholes' the value. 2641 LookupResult lookup(isolate); 2642 object->LookupOwnRealNamedProperty(name, &lookup); 2643 ASSERT(lookup.IsFound()); // the property was declared 2644 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 2645 2646 if (lookup.IsField()) { 2647 FixedArray* properties = object->properties(); 2648 FieldIndex index = lookup.GetFieldIndex(); 2649 ASSERT(!index.is_inobject()); 2650 if (properties->get(index.outobject_array_index())->IsTheHole()) { 2651 properties->set(index.outobject_array_index(), *value); 2652 } 2653 } else if (lookup.IsNormal()) { 2654 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { 2655 JSObject::SetNormalizedProperty(object, &lookup, value); 2656 } 2657 } else { 2658 // We should not reach here. Any real, named property should be 2659 // either a field or a dictionary slot. 2660 UNREACHABLE(); 2661 } 2662 } else { 2663 // The property was found on some other object. Set it if it is not a 2664 // read-only property. 2665 if ((attributes & READ_ONLY) == 0) { 2666 // Strict mode not needed (const disallowed in strict mode). 2667 RETURN_FAILURE_ON_EXCEPTION( 2668 isolate, 2669 JSReceiver::SetProperty(object, name, value, attributes, SLOPPY)); 2670 } 2671 } 2672 2673 return *value; 2674 } 2675 2676 2677 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) { 2678 HandleScope scope(isolate); 2679 ASSERT(args.length() == 2); 2680 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 2681 CONVERT_SMI_ARG_CHECKED(properties, 1); 2682 // Conservative upper limit to prevent fuzz tests from going OOM. 2683 RUNTIME_ASSERT(properties <= 100000); 2684 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) { 2685 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 2686 } 2687 return *object; 2688 } 2689 2690 2691 RUNTIME_FUNCTION(RuntimeHidden_RegExpExec) { 2692 HandleScope scope(isolate); 2693 ASSERT(args.length() == 4); 2694 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 2695 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 2696 // Due to the way the JS calls are constructed this must be less than the 2697 // length of a string, i.e. it is always a Smi. We check anyway for security. 2698 CONVERT_SMI_ARG_CHECKED(index, 2); 2699 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 2700 RUNTIME_ASSERT(index >= 0); 2701 RUNTIME_ASSERT(index <= subject->length()); 2702 isolate->counters()->regexp_entry_runtime()->Increment(); 2703 Handle<Object> result; 2704 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2705 isolate, result, 2706 RegExpImpl::Exec(regexp, subject, index, last_match_info)); 2707 return *result; 2708 } 2709 2710 2711 RUNTIME_FUNCTION(RuntimeHidden_RegExpConstructResult) { 2712 HandleScope handle_scope(isolate); 2713 ASSERT(args.length() == 3); 2714 CONVERT_SMI_ARG_CHECKED(size, 0); 2715 RUNTIME_ASSERT(size >= 0 && size <= FixedArray::kMaxLength); 2716 CONVERT_ARG_HANDLE_CHECKED(Object, index, 1); 2717 CONVERT_ARG_HANDLE_CHECKED(Object, input, 2); 2718 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(size); 2719 Handle<Map> regexp_map(isolate->native_context()->regexp_result_map()); 2720 Handle<JSObject> object = 2721 isolate->factory()->NewJSObjectFromMap(regexp_map, NOT_TENURED, false); 2722 Handle<JSArray> array = Handle<JSArray>::cast(object); 2723 array->set_elements(*elements); 2724 array->set_length(Smi::FromInt(size)); 2725 // Write in-object properties after the length of the array. 2726 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, *index); 2727 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, *input); 2728 return *array; 2729 } 2730 2731 2732 RUNTIME_FUNCTION(Runtime_RegExpInitializeObject) { 2733 HandleScope scope(isolate); 2734 ASSERT(args.length() == 5); 2735 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 2736 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 2737 // If source is the empty string we set it to "(?:)" instead as 2738 // suggested by ECMA-262, 5th, section 15.10.4.1. 2739 if (source->length() == 0) source = isolate->factory()->query_colon_string(); 2740 2741 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2); 2742 if (!global->IsTrue()) global = isolate->factory()->false_value(); 2743 2744 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3); 2745 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value(); 2746 2747 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4); 2748 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value(); 2749 2750 Map* map = regexp->map(); 2751 Object* constructor = map->constructor(); 2752 if (constructor->IsJSFunction() && 2753 JSFunction::cast(constructor)->initial_map() == map) { 2754 // If we still have the original map, set in-object properties directly. 2755 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source); 2756 // Both true and false are immovable immortal objects so no need for write 2757 // barrier. 2758 regexp->InObjectPropertyAtPut( 2759 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER); 2760 regexp->InObjectPropertyAtPut( 2761 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER); 2762 regexp->InObjectPropertyAtPut( 2763 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER); 2764 regexp->InObjectPropertyAtPut( 2765 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER); 2766 return *regexp; 2767 } 2768 2769 // Map has changed, so use generic, but slower, method. 2770 PropertyAttributes final = 2771 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 2772 PropertyAttributes writable = 2773 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 2774 Handle<Object> zero(Smi::FromInt(0), isolate); 2775 Factory* factory = isolate->factory(); 2776 JSObject::SetOwnPropertyIgnoreAttributes( 2777 regexp, factory->source_string(), source, final).Check(); 2778 JSObject::SetOwnPropertyIgnoreAttributes( 2779 regexp, factory->global_string(), global, final).Check(); 2780 JSObject::SetOwnPropertyIgnoreAttributes( 2781 regexp, factory->ignore_case_string(), ignoreCase, final).Check(); 2782 JSObject::SetOwnPropertyIgnoreAttributes( 2783 regexp, factory->multiline_string(), multiline, final).Check(); 2784 JSObject::SetOwnPropertyIgnoreAttributes( 2785 regexp, factory->last_index_string(), zero, writable).Check(); 2786 return *regexp; 2787 } 2788 2789 2790 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) { 2791 HandleScope scope(isolate); 2792 ASSERT(args.length() == 1); 2793 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); 2794 Object* length = prototype->length(); 2795 RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0); 2796 RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements()); 2797 // This is necessary to enable fast checks for absence of elements 2798 // on Array.prototype and below. 2799 prototype->set_elements(isolate->heap()->empty_fixed_array()); 2800 return Smi::FromInt(0); 2801 } 2802 2803 2804 static void InstallBuiltin(Isolate* isolate, 2805 Handle<JSObject> holder, 2806 const char* name, 2807 Builtins::Name builtin_name) { 2808 Handle<String> key = isolate->factory()->InternalizeUtf8String(name); 2809 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); 2810 Handle<JSFunction> optimized = 2811 isolate->factory()->NewFunctionWithoutPrototype(key, code); 2812 optimized->shared()->DontAdaptArguments(); 2813 JSReceiver::SetProperty(holder, key, optimized, NONE, STRICT).Assert(); 2814 } 2815 2816 2817 RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) { 2818 HandleScope scope(isolate); 2819 ASSERT(args.length() == 0); 2820 Handle<JSObject> holder = 2821 isolate->factory()->NewJSObject(isolate->object_function()); 2822 2823 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); 2824 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); 2825 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); 2826 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); 2827 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); 2828 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); 2829 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); 2830 2831 return *holder; 2832 } 2833 2834 2835 RUNTIME_FUNCTION(Runtime_IsSloppyModeFunction) { 2836 SealHandleScope shs(isolate); 2837 ASSERT(args.length() == 1); 2838 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2839 if (!callable->IsJSFunction()) { 2840 HandleScope scope(isolate); 2841 Handle<Object> delegate; 2842 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2843 isolate, delegate, 2844 Execution::TryGetFunctionDelegate( 2845 isolate, Handle<JSReceiver>(callable))); 2846 callable = JSFunction::cast(*delegate); 2847 } 2848 JSFunction* function = JSFunction::cast(callable); 2849 SharedFunctionInfo* shared = function->shared(); 2850 return isolate->heap()->ToBoolean(shared->strict_mode() == SLOPPY); 2851 } 2852 2853 2854 RUNTIME_FUNCTION(Runtime_GetDefaultReceiver) { 2855 SealHandleScope shs(isolate); 2856 ASSERT(args.length() == 1); 2857 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2858 2859 if (!callable->IsJSFunction()) { 2860 HandleScope scope(isolate); 2861 Handle<Object> delegate; 2862 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2863 isolate, delegate, 2864 Execution::TryGetFunctionDelegate( 2865 isolate, Handle<JSReceiver>(callable))); 2866 callable = JSFunction::cast(*delegate); 2867 } 2868 JSFunction* function = JSFunction::cast(callable); 2869 2870 SharedFunctionInfo* shared = function->shared(); 2871 if (shared->native() || shared->strict_mode() == STRICT) { 2872 return isolate->heap()->undefined_value(); 2873 } 2874 // Returns undefined for strict or native functions, or 2875 // the associated global receiver for "normal" functions. 2876 2877 Context* native_context = 2878 function->context()->global_object()->native_context(); 2879 return native_context->global_object()->global_receiver(); 2880 } 2881 2882 2883 RUNTIME_FUNCTION(RuntimeHidden_MaterializeRegExpLiteral) { 2884 HandleScope scope(isolate); 2885 ASSERT(args.length() == 4); 2886 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 2887 CONVERT_SMI_ARG_CHECKED(index, 1); 2888 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); 2889 CONVERT_ARG_HANDLE_CHECKED(String, flags, 3); 2890 2891 // Get the RegExp function from the context in the literals array. 2892 // This is the RegExp function from the context in which the 2893 // function was created. We do not use the RegExp function from the 2894 // current native context because this might be the RegExp function 2895 // from another context which we should not have access to. 2896 Handle<JSFunction> constructor = 2897 Handle<JSFunction>( 2898 JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); 2899 // Compute the regular expression literal. 2900 Handle<Object> regexp; 2901 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2902 isolate, regexp, 2903 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags)); 2904 literals->set(index, *regexp); 2905 return *regexp; 2906 } 2907 2908 2909 RUNTIME_FUNCTION(Runtime_FunctionGetName) { 2910 SealHandleScope shs(isolate); 2911 ASSERT(args.length() == 1); 2912 2913 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2914 return f->shared()->name(); 2915 } 2916 2917 2918 RUNTIME_FUNCTION(Runtime_FunctionSetName) { 2919 SealHandleScope shs(isolate); 2920 ASSERT(args.length() == 2); 2921 2922 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2923 CONVERT_ARG_CHECKED(String, name, 1); 2924 f->shared()->set_name(name); 2925 return isolate->heap()->undefined_value(); 2926 } 2927 2928 2929 RUNTIME_FUNCTION(Runtime_FunctionNameShouldPrintAsAnonymous) { 2930 SealHandleScope shs(isolate); 2931 ASSERT(args.length() == 1); 2932 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2933 return isolate->heap()->ToBoolean( 2934 f->shared()->name_should_print_as_anonymous()); 2935 } 2936 2937 2938 RUNTIME_FUNCTION(Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 2939 SealHandleScope shs(isolate); 2940 ASSERT(args.length() == 1); 2941 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2942 f->shared()->set_name_should_print_as_anonymous(true); 2943 return isolate->heap()->undefined_value(); 2944 } 2945 2946 2947 RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) { 2948 SealHandleScope shs(isolate); 2949 ASSERT(args.length() == 1); 2950 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2951 return isolate->heap()->ToBoolean(f->shared()->is_generator()); 2952 } 2953 2954 2955 RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) { 2956 SealHandleScope shs(isolate); 2957 ASSERT(args.length() == 1); 2958 2959 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2960 RUNTIME_ASSERT(f->RemovePrototype()); 2961 2962 return isolate->heap()->undefined_value(); 2963 } 2964 2965 2966 RUNTIME_FUNCTION(Runtime_FunctionGetScript) { 2967 HandleScope scope(isolate); 2968 ASSERT(args.length() == 1); 2969 2970 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2971 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); 2972 if (!script->IsScript()) return isolate->heap()->undefined_value(); 2973 2974 return *Script::GetWrapper(Handle<Script>::cast(script)); 2975 } 2976 2977 2978 RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) { 2979 HandleScope scope(isolate); 2980 ASSERT(args.length() == 1); 2981 2982 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); 2983 Handle<SharedFunctionInfo> shared(f->shared()); 2984 return *shared->GetSourceCode(); 2985 } 2986 2987 2988 RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) { 2989 SealHandleScope shs(isolate); 2990 ASSERT(args.length() == 1); 2991 2992 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2993 int pos = fun->shared()->start_position(); 2994 return Smi::FromInt(pos); 2995 } 2996 2997 2998 RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) { 2999 SealHandleScope shs(isolate); 3000 ASSERT(args.length() == 2); 3001 3002 CONVERT_ARG_CHECKED(Code, code, 0); 3003 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 3004 3005 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 3006 3007 Address pc = code->address() + offset; 3008 return Smi::FromInt(code->SourcePosition(pc)); 3009 } 3010 3011 3012 RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) { 3013 SealHandleScope shs(isolate); 3014 ASSERT(args.length() == 2); 3015 3016 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 3017 CONVERT_ARG_CHECKED(String, name, 1); 3018 fun->SetInstanceClassName(name); 3019 return isolate->heap()->undefined_value(); 3020 } 3021 3022 3023 RUNTIME_FUNCTION(Runtime_FunctionSetLength) { 3024 SealHandleScope shs(isolate); 3025 ASSERT(args.length() == 2); 3026 3027 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 3028 CONVERT_SMI_ARG_CHECKED(length, 1); 3029 RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 || 3030 (length & 0xC0000000) == 0x0); 3031 fun->shared()->set_length(length); 3032 return isolate->heap()->undefined_value(); 3033 } 3034 3035 3036 RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { 3037 HandleScope scope(isolate); 3038 ASSERT(args.length() == 2); 3039 3040 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 3041 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 3042 RUNTIME_ASSERT(fun->should_have_prototype()); 3043 Accessors::FunctionSetPrototype(fun, value); 3044 return args[0]; // return TOS 3045 } 3046 3047 3048 RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) { 3049 SealHandleScope shs(isolate); 3050 ASSERT(args.length() == 1); 3051 3052 CONVERT_ARG_CHECKED(JSFunction, f, 0); 3053 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); 3054 } 3055 3056 3057 RUNTIME_FUNCTION(Runtime_FunctionIsBuiltin) { 3058 SealHandleScope shs(isolate); 3059 ASSERT(args.length() == 1); 3060 3061 CONVERT_ARG_CHECKED(JSFunction, f, 0); 3062 return isolate->heap()->ToBoolean(f->IsBuiltin()); 3063 } 3064 3065 3066 RUNTIME_FUNCTION(Runtime_SetCode) { 3067 HandleScope scope(isolate); 3068 ASSERT(args.length() == 2); 3069 3070 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 3071 CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1); 3072 3073 Handle<SharedFunctionInfo> target_shared(target->shared()); 3074 Handle<SharedFunctionInfo> source_shared(source->shared()); 3075 RUNTIME_ASSERT(!source_shared->bound()); 3076 3077 if (!Compiler::EnsureCompiled(source, KEEP_EXCEPTION)) { 3078 return isolate->heap()->exception(); 3079 } 3080 3081 // Mark both, the source and the target, as un-flushable because the 3082 // shared unoptimized code makes them impossible to enqueue in a list. 3083 ASSERT(target_shared->code()->gc_metadata() == NULL); 3084 ASSERT(source_shared->code()->gc_metadata() == NULL); 3085 target_shared->set_dont_flush(true); 3086 source_shared->set_dont_flush(true); 3087 3088 // Set the code, scope info, formal parameter count, and the length 3089 // of the target shared function info. 3090 target_shared->ReplaceCode(source_shared->code()); 3091 target_shared->set_scope_info(source_shared->scope_info()); 3092 target_shared->set_length(source_shared->length()); 3093 target_shared->set_feedback_vector(source_shared->feedback_vector()); 3094 target_shared->set_formal_parameter_count( 3095 source_shared->formal_parameter_count()); 3096 target_shared->set_script(source_shared->script()); 3097 target_shared->set_start_position_and_type( 3098 source_shared->start_position_and_type()); 3099 target_shared->set_end_position(source_shared->end_position()); 3100 bool was_native = target_shared->native(); 3101 target_shared->set_compiler_hints(source_shared->compiler_hints()); 3102 target_shared->set_native(was_native); 3103 target_shared->set_profiler_ticks(source_shared->profiler_ticks()); 3104 3105 // Set the code of the target function. 3106 target->ReplaceCode(source_shared->code()); 3107 ASSERT(target->next_function_link()->IsUndefined()); 3108 3109 // Make sure we get a fresh copy of the literal vector to avoid cross 3110 // context contamination. 3111 Handle<Context> context(source->context()); 3112 int number_of_literals = source->NumberOfLiterals(); 3113 Handle<FixedArray> literals = 3114 isolate->factory()->NewFixedArray(number_of_literals, TENURED); 3115 if (number_of_literals > 0) { 3116 literals->set(JSFunction::kLiteralNativeContextIndex, 3117 context->native_context()); 3118 } 3119 target->set_context(*context); 3120 target->set_literals(*literals); 3121 3122 if (isolate->logger()->is_logging_code_events() || 3123 isolate->cpu_profiler()->is_profiling()) { 3124 isolate->logger()->LogExistingFunction( 3125 source_shared, Handle<Code>(source_shared->code())); 3126 } 3127 3128 return *target; 3129 } 3130 3131 3132 RUNTIME_FUNCTION(RuntimeHidden_CreateJSGeneratorObject) { 3133 HandleScope scope(isolate); 3134 ASSERT(args.length() == 0); 3135 3136 JavaScriptFrameIterator it(isolate); 3137 JavaScriptFrame* frame = it.frame(); 3138 Handle<JSFunction> function(frame->function()); 3139 RUNTIME_ASSERT(function->shared()->is_generator()); 3140 3141 Handle<JSGeneratorObject> generator; 3142 if (frame->IsConstructor()) { 3143 generator = handle(JSGeneratorObject::cast(frame->receiver())); 3144 } else { 3145 generator = isolate->factory()->NewJSGeneratorObject(function); 3146 } 3147 generator->set_function(*function); 3148 generator->set_context(Context::cast(frame->context())); 3149 generator->set_receiver(frame->receiver()); 3150 generator->set_continuation(0); 3151 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); 3152 generator->set_stack_handler_index(-1); 3153 3154 return *generator; 3155 } 3156 3157 3158 RUNTIME_FUNCTION(RuntimeHidden_SuspendJSGeneratorObject) { 3159 HandleScope handle_scope(isolate); 3160 ASSERT(args.length() == 1); 3161 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0); 3162 3163 JavaScriptFrameIterator stack_iterator(isolate); 3164 JavaScriptFrame* frame = stack_iterator.frame(); 3165 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); 3166 ASSERT_EQ(frame->function(), generator_object->function()); 3167 3168 // The caller should have saved the context and continuation already. 3169 ASSERT_EQ(generator_object->context(), Context::cast(frame->context())); 3170 ASSERT_LT(0, generator_object->continuation()); 3171 3172 // We expect there to be at least two values on the operand stack: the return 3173 // value of the yield expression, and the argument to this runtime call. 3174 // Neither of those should be saved. 3175 int operands_count = frame->ComputeOperandsCount(); 3176 ASSERT_GE(operands_count, 2); 3177 operands_count -= 2; 3178 3179 if (operands_count == 0) { 3180 // Although it's semantically harmless to call this function with an 3181 // operands_count of zero, it is also unnecessary. 3182 ASSERT_EQ(generator_object->operand_stack(), 3183 isolate->heap()->empty_fixed_array()); 3184 ASSERT_EQ(generator_object->stack_handler_index(), -1); 3185 // If there are no operands on the stack, there shouldn't be a handler 3186 // active either. 3187 ASSERT(!frame->HasHandler()); 3188 } else { 3189 int stack_handler_index = -1; 3190 Handle<FixedArray> operand_stack = 3191 isolate->factory()->NewFixedArray(operands_count); 3192 frame->SaveOperandStack(*operand_stack, &stack_handler_index); 3193 generator_object->set_operand_stack(*operand_stack); 3194 generator_object->set_stack_handler_index(stack_handler_index); 3195 } 3196 3197 return isolate->heap()->undefined_value(); 3198 } 3199 3200 3201 // Note that this function is the slow path for resuming generators. It is only 3202 // called if the suspended activation had operands on the stack, stack handlers 3203 // needing rewinding, or if the resume should throw an exception. The fast path 3204 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is 3205 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is 3206 // called in any case, as it needs to reconstruct the stack frame and make space 3207 // for arguments and operands. 3208 RUNTIME_FUNCTION(RuntimeHidden_ResumeJSGeneratorObject) { 3209 SealHandleScope shs(isolate); 3210 ASSERT(args.length() == 3); 3211 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); 3212 CONVERT_ARG_CHECKED(Object, value, 1); 3213 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); 3214 JavaScriptFrameIterator stack_iterator(isolate); 3215 JavaScriptFrame* frame = stack_iterator.frame(); 3216 3217 ASSERT_EQ(frame->function(), generator_object->function()); 3218 ASSERT(frame->function()->is_compiled()); 3219 3220 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0); 3221 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0); 3222 3223 Address pc = generator_object->function()->code()->instruction_start(); 3224 int offset = generator_object->continuation(); 3225 ASSERT(offset > 0); 3226 frame->set_pc(pc + offset); 3227 if (FLAG_enable_ool_constant_pool) { 3228 frame->set_constant_pool( 3229 generator_object->function()->code()->constant_pool()); 3230 } 3231 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); 3232 3233 FixedArray* operand_stack = generator_object->operand_stack(); 3234 int operands_count = operand_stack->length(); 3235 if (operands_count != 0) { 3236 frame->RestoreOperandStack(operand_stack, 3237 generator_object->stack_handler_index()); 3238 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); 3239 generator_object->set_stack_handler_index(-1); 3240 } 3241 3242 JSGeneratorObject::ResumeMode resume_mode = 3243 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); 3244 switch (resume_mode) { 3245 case JSGeneratorObject::NEXT: 3246 return value; 3247 case JSGeneratorObject::THROW: 3248 return isolate->Throw(value); 3249 } 3250 3251 UNREACHABLE(); 3252 return isolate->ThrowIllegalOperation(); 3253 } 3254 3255 3256 RUNTIME_FUNCTION(RuntimeHidden_ThrowGeneratorStateError) { 3257 HandleScope scope(isolate); 3258 ASSERT(args.length() == 1); 3259 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); 3260 int continuation = generator->continuation(); 3261 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ? 3262 "generator_finished" : "generator_running"; 3263 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0); 3264 Handle<Object> error = isolate->factory()->NewError(message, argv); 3265 return isolate->Throw(*error); 3266 } 3267 3268 3269 RUNTIME_FUNCTION(Runtime_ObjectFreeze) { 3270 HandleScope scope(isolate); 3271 ASSERT(args.length() == 1); 3272 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 3273 3274 // %ObjectFreeze is a fast path and these cases are handled elsewhere. 3275 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() && 3276 !object->map()->is_observed() && 3277 !object->IsJSProxy()); 3278 3279 Handle<Object> result; 3280 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object)); 3281 return *result; 3282 } 3283 3284 3285 RUNTIME_FUNCTION(RuntimeHidden_StringCharCodeAt) { 3286 HandleScope handle_scope(isolate); 3287 ASSERT(args.length() == 2); 3288 3289 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 3290 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); 3291 3292 // Flatten the string. If someone wants to get a char at an index 3293 // in a cons string, it is likely that more indices will be 3294 // accessed. 3295 subject = String::Flatten(subject); 3296 3297 if (i >= static_cast<uint32_t>(subject->length())) { 3298 return isolate->heap()->nan_value(); 3299 } 3300 3301 return Smi::FromInt(subject->Get(i)); 3302 } 3303 3304 3305 RUNTIME_FUNCTION(Runtime_CharFromCode) { 3306 HandleScope handlescope(isolate); 3307 ASSERT(args.length() == 1); 3308 if (args[0]->IsNumber()) { 3309 CONVERT_NUMBER_CHECKED(uint32_t, code, Uint32, args[0]); 3310 code &= 0xffff; 3311 return *isolate->factory()->LookupSingleCharacterStringFromCode(code); 3312 } 3313 return isolate->heap()->empty_string(); 3314 } 3315 3316 3317 class FixedArrayBuilder { 3318 public: 3319 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) 3320 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), 3321 length_(0), 3322 has_non_smi_elements_(false) { 3323 // Require a non-zero initial size. Ensures that doubling the size to 3324 // extend the array will work. 3325 ASSERT(initial_capacity > 0); 3326 } 3327 3328 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) 3329 : array_(backing_store), 3330 length_(0), 3331 has_non_smi_elements_(false) { 3332 // Require a non-zero initial size. Ensures that doubling the size to 3333 // extend the array will work. 3334 ASSERT(backing_store->length() > 0); 3335 } 3336 3337 bool HasCapacity(int elements) { 3338 int length = array_->length(); 3339 int required_length = length_ + elements; 3340 return (length >= required_length); 3341 } 3342 3343 void EnsureCapacity(int elements) { 3344 int length = array_->length(); 3345 int required_length = length_ + elements; 3346 if (length < required_length) { 3347 int new_length = length; 3348 do { 3349 new_length *= 2; 3350 } while (new_length < required_length); 3351 Handle<FixedArray> extended_array = 3352 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); 3353 array_->CopyTo(0, *extended_array, 0, length_); 3354 array_ = extended_array; 3355 } 3356 } 3357 3358 void Add(Object* value) { 3359 ASSERT(!value->IsSmi()); 3360 ASSERT(length_ < capacity()); 3361 array_->set(length_, value); 3362 length_++; 3363 has_non_smi_elements_ = true; 3364 } 3365 3366 void Add(Smi* value) { 3367 ASSERT(value->IsSmi()); 3368 ASSERT(length_ < capacity()); 3369 array_->set(length_, value); 3370 length_++; 3371 } 3372 3373 Handle<FixedArray> array() { 3374 return array_; 3375 } 3376 3377 int length() { 3378 return length_; 3379 } 3380 3381 int capacity() { 3382 return array_->length(); 3383 } 3384 3385 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { 3386 JSArray::SetContent(target_array, array_); 3387 target_array->set_length(Smi::FromInt(length_)); 3388 return target_array; 3389 } 3390 3391 3392 private: 3393 Handle<FixedArray> array_; 3394 int length_; 3395 bool has_non_smi_elements_; 3396 }; 3397 3398 3399 // Forward declarations. 3400 const int kStringBuilderConcatHelperLengthBits = 11; 3401 const int kStringBuilderConcatHelperPositionBits = 19; 3402 3403 template <typename schar> 3404 static inline void StringBuilderConcatHelper(String*, 3405 schar*, 3406 FixedArray*, 3407 int); 3408 3409 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> 3410 StringBuilderSubstringLength; 3411 typedef BitField<int, 3412 kStringBuilderConcatHelperLengthBits, 3413 kStringBuilderConcatHelperPositionBits> 3414 StringBuilderSubstringPosition; 3415 3416 3417 class ReplacementStringBuilder { 3418 public: 3419 ReplacementStringBuilder(Heap* heap, 3420 Handle<String> subject, 3421 int estimated_part_count) 3422 : heap_(heap), 3423 array_builder_(heap->isolate(), estimated_part_count), 3424 subject_(subject), 3425 character_count_(0), 3426 is_ascii_(subject->IsOneByteRepresentation()) { 3427 // Require a non-zero initial size. Ensures that doubling the size to 3428 // extend the array will work. 3429 ASSERT(estimated_part_count > 0); 3430 } 3431 3432 static inline void AddSubjectSlice(FixedArrayBuilder* builder, 3433 int from, 3434 int to) { 3435 ASSERT(from >= 0); 3436 int length = to - from; 3437 ASSERT(length > 0); 3438 if (StringBuilderSubstringLength::is_valid(length) && 3439 StringBuilderSubstringPosition::is_valid(from)) { 3440 int encoded_slice = StringBuilderSubstringLength::encode(length) | 3441 StringBuilderSubstringPosition::encode(from); 3442 builder->Add(Smi::FromInt(encoded_slice)); 3443 } else { 3444 // Otherwise encode as two smis. 3445 builder->Add(Smi::FromInt(-length)); 3446 builder->Add(Smi::FromInt(from)); 3447 } 3448 } 3449 3450 3451 void EnsureCapacity(int elements) { 3452 array_builder_.EnsureCapacity(elements); 3453 } 3454 3455 3456 void AddSubjectSlice(int from, int to) { 3457 AddSubjectSlice(&array_builder_, from, to); 3458 IncrementCharacterCount(to - from); 3459 } 3460 3461 3462 void AddString(Handle<String> string) { 3463 int length = string->length(); 3464 ASSERT(length > 0); 3465 AddElement(*string); 3466 if (!string->IsOneByteRepresentation()) { 3467 is_ascii_ = false; 3468 } 3469 IncrementCharacterCount(length); 3470 } 3471 3472 3473 MaybeHandle<String> ToString() { 3474 Isolate* isolate = heap_->isolate(); 3475 if (array_builder_.length() == 0) { 3476 return isolate->factory()->empty_string(); 3477 } 3478 3479 Handle<String> joined_string; 3480 if (is_ascii_) { 3481 Handle<SeqOneByteString> seq; 3482 ASSIGN_RETURN_ON_EXCEPTION( 3483 isolate, seq, 3484 isolate->factory()->NewRawOneByteString(character_count_), 3485 String); 3486 3487 DisallowHeapAllocation no_gc; 3488 uint8_t* char_buffer = seq->GetChars(); 3489 StringBuilderConcatHelper(*subject_, 3490 char_buffer, 3491 *array_builder_.array(), 3492 array_builder_.length()); 3493 joined_string = Handle<String>::cast(seq); 3494 } else { 3495 // Non-ASCII. 3496 Handle<SeqTwoByteString> seq; 3497 ASSIGN_RETURN_ON_EXCEPTION( 3498 isolate, seq, 3499 isolate->factory()->NewRawTwoByteString(character_count_), 3500 String); 3501 3502 DisallowHeapAllocation no_gc; 3503 uc16* char_buffer = seq->GetChars(); 3504 StringBuilderConcatHelper(*subject_, 3505 char_buffer, 3506 *array_builder_.array(), 3507 array_builder_.length()); 3508 joined_string = Handle<String>::cast(seq); 3509 } 3510 return joined_string; 3511 } 3512 3513 3514 void IncrementCharacterCount(int by) { 3515 if (character_count_ > String::kMaxLength - by) { 3516 STATIC_ASSERT(String::kMaxLength < kMaxInt); 3517 character_count_ = kMaxInt; 3518 } else { 3519 character_count_ += by; 3520 } 3521 } 3522 3523 private: 3524 void AddElement(Object* element) { 3525 ASSERT(element->IsSmi() || element->IsString()); 3526 ASSERT(array_builder_.capacity() > array_builder_.length()); 3527 array_builder_.Add(element); 3528 } 3529 3530 Heap* heap_; 3531 FixedArrayBuilder array_builder_; 3532 Handle<String> subject_; 3533 int character_count_; 3534 bool is_ascii_; 3535 }; 3536 3537 3538 class CompiledReplacement { 3539 public: 3540 explicit CompiledReplacement(Zone* zone) 3541 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} 3542 3543 // Return whether the replacement is simple. 3544 bool Compile(Handle<String> replacement, 3545 int capture_count, 3546 int subject_length); 3547 3548 // Use Apply only if Compile returned false. 3549 void Apply(ReplacementStringBuilder* builder, 3550 int match_from, 3551 int match_to, 3552 int32_t* match); 3553 3554 // Number of distinct parts of the replacement pattern. 3555 int parts() { 3556 return parts_.length(); 3557 } 3558 3559 Zone* zone() const { return zone_; } 3560 3561 private: 3562 enum PartType { 3563 SUBJECT_PREFIX = 1, 3564 SUBJECT_SUFFIX, 3565 SUBJECT_CAPTURE, 3566 REPLACEMENT_SUBSTRING, 3567 REPLACEMENT_STRING, 3568 3569 NUMBER_OF_PART_TYPES 3570 }; 3571 3572 struct ReplacementPart { 3573 static inline ReplacementPart SubjectMatch() { 3574 return ReplacementPart(SUBJECT_CAPTURE, 0); 3575 } 3576 static inline ReplacementPart SubjectCapture(int capture_index) { 3577 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 3578 } 3579 static inline ReplacementPart SubjectPrefix() { 3580 return ReplacementPart(SUBJECT_PREFIX, 0); 3581 } 3582 static inline ReplacementPart SubjectSuffix(int subject_length) { 3583 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 3584 } 3585 static inline ReplacementPart ReplacementString() { 3586 return ReplacementPart(REPLACEMENT_STRING, 0); 3587 } 3588 static inline ReplacementPart ReplacementSubString(int from, int to) { 3589 ASSERT(from >= 0); 3590 ASSERT(to > from); 3591 return ReplacementPart(-from, to); 3592 } 3593 3594 // If tag <= 0 then it is the negation of a start index of a substring of 3595 // the replacement pattern, otherwise it's a value from PartType. 3596 ReplacementPart(int tag, int data) 3597 : tag(tag), data(data) { 3598 // Must be non-positive or a PartType value. 3599 ASSERT(tag < NUMBER_OF_PART_TYPES); 3600 } 3601 // Either a value of PartType or a non-positive number that is 3602 // the negation of an index into the replacement string. 3603 int tag; 3604 // The data value's interpretation depends on the value of tag: 3605 // tag == SUBJECT_PREFIX || 3606 // tag == SUBJECT_SUFFIX: data is unused. 3607 // tag == SUBJECT_CAPTURE: data is the number of the capture. 3608 // tag == REPLACEMENT_SUBSTRING || 3609 // tag == REPLACEMENT_STRING: data is index into array of substrings 3610 // of the replacement string. 3611 // tag <= 0: Temporary representation of the substring of the replacement 3612 // string ranging over -tag .. data. 3613 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 3614 // substring objects. 3615 int data; 3616 }; 3617 3618 template<typename Char> 3619 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 3620 Vector<Char> characters, 3621 int capture_count, 3622 int subject_length, 3623 Zone* zone) { 3624 int length = characters.length(); 3625 int last = 0; 3626 for (int i = 0; i < length; i++) { 3627 Char c = characters[i]; 3628 if (c == '$') { 3629 int next_index = i + 1; 3630 if (next_index == length) { // No next character! 3631 break; 3632 } 3633 Char c2 = characters[next_index]; 3634 switch (c2) { 3635 case '$': 3636 if (i > last) { 3637 // There is a substring before. Include the first "$". 3638 parts->Add(ReplacementPart::ReplacementSubString(last, next_index), 3639 zone); 3640 last = next_index + 1; // Continue after the second "$". 3641 } else { 3642 // Let the next substring start with the second "$". 3643 last = next_index; 3644 } 3645 i = next_index; 3646 break; 3647 case '`': 3648 if (i > last) { 3649 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3650 } 3651 parts->Add(ReplacementPart::SubjectPrefix(), zone); 3652 i = next_index; 3653 last = i + 1; 3654 break; 3655 case '\'': 3656 if (i > last) { 3657 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3658 } 3659 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone); 3660 i = next_index; 3661 last = i + 1; 3662 break; 3663 case '&': 3664 if (i > last) { 3665 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3666 } 3667 parts->Add(ReplacementPart::SubjectMatch(), zone); 3668 i = next_index; 3669 last = i + 1; 3670 break; 3671 case '0': 3672 case '1': 3673 case '2': 3674 case '3': 3675 case '4': 3676 case '5': 3677 case '6': 3678 case '7': 3679 case '8': 3680 case '9': { 3681 int capture_ref = c2 - '0'; 3682 if (capture_ref > capture_count) { 3683 i = next_index; 3684 continue; 3685 } 3686 int second_digit_index = next_index + 1; 3687 if (second_digit_index < length) { 3688 // Peek ahead to see if we have two digits. 3689 Char c3 = characters[second_digit_index]; 3690 if ('0' <= c3 && c3 <= '9') { // Double digits. 3691 int double_digit_ref = capture_ref * 10 + c3 - '0'; 3692 if (double_digit_ref <= capture_count) { 3693 next_index = second_digit_index; 3694 capture_ref = double_digit_ref; 3695 } 3696 } 3697 } 3698 if (capture_ref > 0) { 3699 if (i > last) { 3700 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3701 } 3702 ASSERT(capture_ref <= capture_count); 3703 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); 3704 last = next_index + 1; 3705 } 3706 i = next_index; 3707 break; 3708 } 3709 default: 3710 i = next_index; 3711 break; 3712 } 3713 } 3714 } 3715 if (length > last) { 3716 if (last == 0) { 3717 // Replacement is simple. Do not use Apply to do the replacement. 3718 return true; 3719 } else { 3720 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); 3721 } 3722 } 3723 return false; 3724 } 3725 3726 ZoneList<ReplacementPart> parts_; 3727 ZoneList<Handle<String> > replacement_substrings_; 3728 Zone* zone_; 3729 }; 3730 3731 3732 bool CompiledReplacement::Compile(Handle<String> replacement, 3733 int capture_count, 3734 int subject_length) { 3735 { 3736 DisallowHeapAllocation no_gc; 3737 String::FlatContent content = replacement->GetFlatContent(); 3738 ASSERT(content.IsFlat()); 3739 bool simple = false; 3740 if (content.IsAscii()) { 3741 simple = ParseReplacementPattern(&parts_, 3742 content.ToOneByteVector(), 3743 capture_count, 3744 subject_length, 3745 zone()); 3746 } else { 3747 ASSERT(content.IsTwoByte()); 3748 simple = ParseReplacementPattern(&parts_, 3749 content.ToUC16Vector(), 3750 capture_count, 3751 subject_length, 3752 zone()); 3753 } 3754 if (simple) return true; 3755 } 3756 3757 Isolate* isolate = replacement->GetIsolate(); 3758 // Find substrings of replacement string and create them as String objects. 3759 int substring_index = 0; 3760 for (int i = 0, n = parts_.length(); i < n; i++) { 3761 int tag = parts_[i].tag; 3762 if (tag <= 0) { // A replacement string slice. 3763 int from = -tag; 3764 int to = parts_[i].data; 3765 replacement_substrings_.Add( 3766 isolate->factory()->NewSubString(replacement, from, to), zone()); 3767 parts_[i].tag = REPLACEMENT_SUBSTRING; 3768 parts_[i].data = substring_index; 3769 substring_index++; 3770 } else if (tag == REPLACEMENT_STRING) { 3771 replacement_substrings_.Add(replacement, zone()); 3772 parts_[i].data = substring_index; 3773 substring_index++; 3774 } 3775 } 3776 return false; 3777 } 3778 3779 3780 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 3781 int match_from, 3782 int match_to, 3783 int32_t* match) { 3784 ASSERT_LT(0, parts_.length()); 3785 for (int i = 0, n = parts_.length(); i < n; i++) { 3786 ReplacementPart part = parts_[i]; 3787 switch (part.tag) { 3788 case SUBJECT_PREFIX: 3789 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 3790 break; 3791 case SUBJECT_SUFFIX: { 3792 int subject_length = part.data; 3793 if (match_to < subject_length) { 3794 builder->AddSubjectSlice(match_to, subject_length); 3795 } 3796 break; 3797 } 3798 case SUBJECT_CAPTURE: { 3799 int capture = part.data; 3800 int from = match[capture * 2]; 3801 int to = match[capture * 2 + 1]; 3802 if (from >= 0 && to > from) { 3803 builder->AddSubjectSlice(from, to); 3804 } 3805 break; 3806 } 3807 case REPLACEMENT_SUBSTRING: 3808 case REPLACEMENT_STRING: 3809 builder->AddString(replacement_substrings_[part.data]); 3810 break; 3811 default: 3812 UNREACHABLE(); 3813 } 3814 } 3815 } 3816 3817 3818 void FindAsciiStringIndices(Vector<const uint8_t> subject, 3819 char pattern, 3820 ZoneList<int>* indices, 3821 unsigned int limit, 3822 Zone* zone) { 3823 ASSERT(limit > 0); 3824 // Collect indices of pattern in subject using memchr. 3825 // Stop after finding at most limit values. 3826 const uint8_t* subject_start = subject.start(); 3827 const uint8_t* subject_end = subject_start + subject.length(); 3828 const uint8_t* pos = subject_start; 3829 while (limit > 0) { 3830 pos = reinterpret_cast<const uint8_t*>( 3831 memchr(pos, pattern, subject_end - pos)); 3832 if (pos == NULL) return; 3833 indices->Add(static_cast<int>(pos - subject_start), zone); 3834 pos++; 3835 limit--; 3836 } 3837 } 3838 3839 3840 void FindTwoByteStringIndices(const Vector<const uc16> subject, 3841 uc16 pattern, 3842 ZoneList<int>* indices, 3843 unsigned int limit, 3844 Zone* zone) { 3845 ASSERT(limit > 0); 3846 const uc16* subject_start = subject.start(); 3847 const uc16* subject_end = subject_start + subject.length(); 3848 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { 3849 if (*pos == pattern) { 3850 indices->Add(static_cast<int>(pos - subject_start), zone); 3851 limit--; 3852 } 3853 } 3854 } 3855 3856 3857 template <typename SubjectChar, typename PatternChar> 3858 void FindStringIndices(Isolate* isolate, 3859 Vector<const SubjectChar> subject, 3860 Vector<const PatternChar> pattern, 3861 ZoneList<int>* indices, 3862 unsigned int limit, 3863 Zone* zone) { 3864 ASSERT(limit > 0); 3865 // Collect indices of pattern in subject. 3866 // Stop after finding at most limit values. 3867 int pattern_length = pattern.length(); 3868 int index = 0; 3869 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); 3870 while (limit > 0) { 3871 index = search.Search(subject, index); 3872 if (index < 0) return; 3873 indices->Add(index, zone); 3874 index += pattern_length; 3875 limit--; 3876 } 3877 } 3878 3879 3880 void FindStringIndicesDispatch(Isolate* isolate, 3881 String* subject, 3882 String* pattern, 3883 ZoneList<int>* indices, 3884 unsigned int limit, 3885 Zone* zone) { 3886 { 3887 DisallowHeapAllocation no_gc; 3888 String::FlatContent subject_content = subject->GetFlatContent(); 3889 String::FlatContent pattern_content = pattern->GetFlatContent(); 3890 ASSERT(subject_content.IsFlat()); 3891 ASSERT(pattern_content.IsFlat()); 3892 if (subject_content.IsAscii()) { 3893 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector(); 3894 if (pattern_content.IsAscii()) { 3895 Vector<const uint8_t> pattern_vector = 3896 pattern_content.ToOneByteVector(); 3897 if (pattern_vector.length() == 1) { 3898 FindAsciiStringIndices(subject_vector, 3899 pattern_vector[0], 3900 indices, 3901 limit, 3902 zone); 3903 } else { 3904 FindStringIndices(isolate, 3905 subject_vector, 3906 pattern_vector, 3907 indices, 3908 limit, 3909 zone); 3910 } 3911 } else { 3912 FindStringIndices(isolate, 3913 subject_vector, 3914 pattern_content.ToUC16Vector(), 3915 indices, 3916 limit, 3917 zone); 3918 } 3919 } else { 3920 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); 3921 if (pattern_content.IsAscii()) { 3922 Vector<const uint8_t> pattern_vector = 3923 pattern_content.ToOneByteVector(); 3924 if (pattern_vector.length() == 1) { 3925 FindTwoByteStringIndices(subject_vector, 3926 pattern_vector[0], 3927 indices, 3928 limit, 3929 zone); 3930 } else { 3931 FindStringIndices(isolate, 3932 subject_vector, 3933 pattern_vector, 3934 indices, 3935 limit, 3936 zone); 3937 } 3938 } else { 3939 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); 3940 if (pattern_vector.length() == 1) { 3941 FindTwoByteStringIndices(subject_vector, 3942 pattern_vector[0], 3943 indices, 3944 limit, 3945 zone); 3946 } else { 3947 FindStringIndices(isolate, 3948 subject_vector, 3949 pattern_vector, 3950 indices, 3951 limit, 3952 zone); 3953 } 3954 } 3955 } 3956 } 3957 } 3958 3959 3960 template<typename ResultSeqString> 3961 MUST_USE_RESULT static Object* StringReplaceGlobalAtomRegExpWithString( 3962 Isolate* isolate, 3963 Handle<String> subject, 3964 Handle<JSRegExp> pattern_regexp, 3965 Handle<String> replacement, 3966 Handle<JSArray> last_match_info) { 3967 ASSERT(subject->IsFlat()); 3968 ASSERT(replacement->IsFlat()); 3969 3970 ZoneScope zone_scope(isolate->runtime_zone()); 3971 ZoneList<int> indices(8, zone_scope.zone()); 3972 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 3973 String* pattern = 3974 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 3975 int subject_len = subject->length(); 3976 int pattern_len = pattern->length(); 3977 int replacement_len = replacement->length(); 3978 3979 FindStringIndicesDispatch( 3980 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone()); 3981 3982 int matches = indices.length(); 3983 if (matches == 0) return *subject; 3984 3985 // Detect integer overflow. 3986 int64_t result_len_64 = 3987 (static_cast<int64_t>(replacement_len) - 3988 static_cast<int64_t>(pattern_len)) * 3989 static_cast<int64_t>(matches) + 3990 static_cast<int64_t>(subject_len); 3991 int result_len; 3992 if (result_len_64 > static_cast<int64_t>(String::kMaxLength)) { 3993 STATIC_ASSERT(String::kMaxLength < kMaxInt); 3994 result_len = kMaxInt; // Provoke exception. 3995 } else { 3996 result_len = static_cast<int>(result_len_64); 3997 } 3998 3999 int subject_pos = 0; 4000 int result_pos = 0; 4001 4002 MaybeHandle<SeqString> maybe_res; 4003 if (ResultSeqString::kHasAsciiEncoding) { 4004 maybe_res = isolate->factory()->NewRawOneByteString(result_len); 4005 } else { 4006 maybe_res = isolate->factory()->NewRawTwoByteString(result_len); 4007 } 4008 Handle<SeqString> untyped_res; 4009 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, untyped_res, maybe_res); 4010 Handle<ResultSeqString> result = Handle<ResultSeqString>::cast(untyped_res); 4011 4012 for (int i = 0; i < matches; i++) { 4013 // Copy non-matched subject content. 4014 if (subject_pos < indices.at(i)) { 4015 String::WriteToFlat(*subject, 4016 result->GetChars() + result_pos, 4017 subject_pos, 4018 indices.at(i)); 4019 result_pos += indices.at(i) - subject_pos; 4020 } 4021 4022 // Replace match. 4023 if (replacement_len > 0) { 4024 String::WriteToFlat(*replacement, 4025 result->GetChars() + result_pos, 4026 0, 4027 replacement_len); 4028 result_pos += replacement_len; 4029 } 4030 4031 subject_pos = indices.at(i) + pattern_len; 4032 } 4033 // Add remaining subject content at the end. 4034 if (subject_pos < subject_len) { 4035 String::WriteToFlat(*subject, 4036 result->GetChars() + result_pos, 4037 subject_pos, 4038 subject_len); 4039 } 4040 4041 int32_t match_indices[] = { indices.at(matches - 1), 4042 indices.at(matches - 1) + pattern_len }; 4043 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); 4044 4045 return *result; 4046 } 4047 4048 4049 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithString( 4050 Isolate* isolate, 4051 Handle<String> subject, 4052 Handle<JSRegExp> regexp, 4053 Handle<String> replacement, 4054 Handle<JSArray> last_match_info) { 4055 ASSERT(subject->IsFlat()); 4056 ASSERT(replacement->IsFlat()); 4057 4058 int capture_count = regexp->CaptureCount(); 4059 int subject_length = subject->length(); 4060 4061 // CompiledReplacement uses zone allocation. 4062 ZoneScope zone_scope(isolate->runtime_zone()); 4063 CompiledReplacement compiled_replacement(zone_scope.zone()); 4064 bool simple_replace = compiled_replacement.Compile(replacement, 4065 capture_count, 4066 subject_length); 4067 4068 // Shortcut for simple non-regexp global replacements 4069 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { 4070 if (subject->HasOnlyOneByteChars() && 4071 replacement->HasOnlyOneByteChars()) { 4072 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 4073 isolate, subject, regexp, replacement, last_match_info); 4074 } else { 4075 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 4076 isolate, subject, regexp, replacement, last_match_info); 4077 } 4078 } 4079 4080 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4081 if (global_cache.HasException()) return isolate->heap()->exception(); 4082 4083 int32_t* current_match = global_cache.FetchNext(); 4084 if (current_match == NULL) { 4085 if (global_cache.HasException()) return isolate->heap()->exception(); 4086 return *subject; 4087 } 4088 4089 // Guessing the number of parts that the final result string is built 4090 // from. Global regexps can match any number of times, so we guess 4091 // conservatively. 4092 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1; 4093 ReplacementStringBuilder builder(isolate->heap(), 4094 subject, 4095 expected_parts); 4096 4097 // Number of parts added by compiled replacement plus preceeding 4098 // string and possibly suffix after last match. It is possible for 4099 // all components to use two elements when encoded as two smis. 4100 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 4101 4102 int prev = 0; 4103 4104 do { 4105 builder.EnsureCapacity(parts_added_per_loop); 4106 4107 int start = current_match[0]; 4108 int end = current_match[1]; 4109 4110 if (prev < start) { 4111 builder.AddSubjectSlice(prev, start); 4112 } 4113 4114 if (simple_replace) { 4115 builder.AddString(replacement); 4116 } else { 4117 compiled_replacement.Apply(&builder, 4118 start, 4119 end, 4120 current_match); 4121 } 4122 prev = end; 4123 4124 current_match = global_cache.FetchNext(); 4125 } while (current_match != NULL); 4126 4127 if (global_cache.HasException()) return isolate->heap()->exception(); 4128 4129 if (prev < subject_length) { 4130 builder.EnsureCapacity(2); 4131 builder.AddSubjectSlice(prev, subject_length); 4132 } 4133 4134 RegExpImpl::SetLastMatchInfo(last_match_info, 4135 subject, 4136 capture_count, 4137 global_cache.LastSuccessfulMatch()); 4138 4139 Handle<String> result; 4140 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, builder.ToString()); 4141 return *result; 4142 } 4143 4144 4145 template <typename ResultSeqString> 4146 MUST_USE_RESULT static Object* StringReplaceGlobalRegExpWithEmptyString( 4147 Isolate* isolate, 4148 Handle<String> subject, 4149 Handle<JSRegExp> regexp, 4150 Handle<JSArray> last_match_info) { 4151 ASSERT(subject->IsFlat()); 4152 4153 // Shortcut for simple non-regexp global replacements 4154 if (regexp->TypeTag() == JSRegExp::ATOM) { 4155 Handle<String> empty_string = isolate->factory()->empty_string(); 4156 if (subject->IsOneByteRepresentation()) { 4157 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 4158 isolate, subject, regexp, empty_string, last_match_info); 4159 } else { 4160 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 4161 isolate, subject, regexp, empty_string, last_match_info); 4162 } 4163 } 4164 4165 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4166 if (global_cache.HasException()) return isolate->heap()->exception(); 4167 4168 int32_t* current_match = global_cache.FetchNext(); 4169 if (current_match == NULL) { 4170 if (global_cache.HasException()) return isolate->heap()->exception(); 4171 return *subject; 4172 } 4173 4174 int start = current_match[0]; 4175 int end = current_match[1]; 4176 int capture_count = regexp->CaptureCount(); 4177 int subject_length = subject->length(); 4178 4179 int new_length = subject_length - (end - start); 4180 if (new_length == 0) return isolate->heap()->empty_string(); 4181 4182 Handle<ResultSeqString> answer; 4183 if (ResultSeqString::kHasAsciiEncoding) { 4184 answer = Handle<ResultSeqString>::cast( 4185 isolate->factory()->NewRawOneByteString(new_length).ToHandleChecked()); 4186 } else { 4187 answer = Handle<ResultSeqString>::cast( 4188 isolate->factory()->NewRawTwoByteString(new_length).ToHandleChecked()); 4189 } 4190 4191 int prev = 0; 4192 int position = 0; 4193 4194 do { 4195 start = current_match[0]; 4196 end = current_match[1]; 4197 if (prev < start) { 4198 // Add substring subject[prev;start] to answer string. 4199 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start); 4200 position += start - prev; 4201 } 4202 prev = end; 4203 4204 current_match = global_cache.FetchNext(); 4205 } while (current_match != NULL); 4206 4207 if (global_cache.HasException()) return isolate->heap()->exception(); 4208 4209 RegExpImpl::SetLastMatchInfo(last_match_info, 4210 subject, 4211 capture_count, 4212 global_cache.LastSuccessfulMatch()); 4213 4214 if (prev < subject_length) { 4215 // Add substring subject[prev;length] to answer string. 4216 String::WriteToFlat( 4217 *subject, answer->GetChars() + position, prev, subject_length); 4218 position += subject_length - prev; 4219 } 4220 4221 if (position == 0) return isolate->heap()->empty_string(); 4222 4223 // Shorten string and fill 4224 int string_size = ResultSeqString::SizeFor(position); 4225 int allocated_string_size = ResultSeqString::SizeFor(new_length); 4226 int delta = allocated_string_size - string_size; 4227 4228 answer->set_length(position); 4229 if (delta == 0) return *answer; 4230 4231 Address end_of_string = answer->address() + string_size; 4232 Heap* heap = isolate->heap(); 4233 4234 // The trimming is performed on a newly allocated object, which is on a 4235 // fresly allocated page or on an already swept page. Hence, the sweeper 4236 // thread can not get confused with the filler creation. No synchronization 4237 // needed. 4238 heap->CreateFillerObjectAt(end_of_string, delta); 4239 heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR); 4240 return *answer; 4241 } 4242 4243 4244 RUNTIME_FUNCTION(Runtime_StringReplaceGlobalRegExpWithString) { 4245 HandleScope scope(isolate); 4246 ASSERT(args.length() == 4); 4247 4248 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4249 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); 4250 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4251 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 4252 4253 RUNTIME_ASSERT(regexp->GetFlags().is_global()); 4254 RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); 4255 4256 subject = String::Flatten(subject); 4257 4258 if (replacement->length() == 0) { 4259 if (subject->HasOnlyOneByteChars()) { 4260 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( 4261 isolate, subject, regexp, last_match_info); 4262 } else { 4263 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( 4264 isolate, subject, regexp, last_match_info); 4265 } 4266 } 4267 4268 replacement = String::Flatten(replacement); 4269 4270 return StringReplaceGlobalRegExpWithString( 4271 isolate, subject, regexp, replacement, last_match_info); 4272 } 4273 4274 4275 // This may return an empty MaybeHandle if an exception is thrown or 4276 // we abort due to reaching the recursion limit. 4277 MaybeHandle<String> StringReplaceOneCharWithString(Isolate* isolate, 4278 Handle<String> subject, 4279 Handle<String> search, 4280 Handle<String> replace, 4281 bool* found, 4282 int recursion_limit) { 4283 StackLimitCheck stackLimitCheck(isolate); 4284 if (stackLimitCheck.HasOverflowed() || (recursion_limit == 0)) { 4285 return MaybeHandle<String>(); 4286 } 4287 recursion_limit--; 4288 if (subject->IsConsString()) { 4289 ConsString* cons = ConsString::cast(*subject); 4290 Handle<String> first = Handle<String>(cons->first()); 4291 Handle<String> second = Handle<String>(cons->second()); 4292 Handle<String> new_first; 4293 if (!StringReplaceOneCharWithString( 4294 isolate, first, search, replace, found, recursion_limit) 4295 .ToHandle(&new_first)) { 4296 return MaybeHandle<String>(); 4297 } 4298 if (*found) return isolate->factory()->NewConsString(new_first, second); 4299 4300 Handle<String> new_second; 4301 if (!StringReplaceOneCharWithString( 4302 isolate, second, search, replace, found, recursion_limit) 4303 .ToHandle(&new_second)) { 4304 return MaybeHandle<String>(); 4305 } 4306 if (*found) return isolate->factory()->NewConsString(first, new_second); 4307 4308 return subject; 4309 } else { 4310 int index = Runtime::StringMatch(isolate, subject, search, 0); 4311 if (index == -1) return subject; 4312 *found = true; 4313 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); 4314 Handle<String> cons1; 4315 ASSIGN_RETURN_ON_EXCEPTION( 4316 isolate, cons1, 4317 isolate->factory()->NewConsString(first, replace), 4318 String); 4319 Handle<String> second = 4320 isolate->factory()->NewSubString(subject, index + 1, subject->length()); 4321 return isolate->factory()->NewConsString(cons1, second); 4322 } 4323 } 4324 4325 4326 RUNTIME_FUNCTION(Runtime_StringReplaceOneCharWithString) { 4327 HandleScope scope(isolate); 4328 ASSERT(args.length() == 3); 4329 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4330 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); 4331 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); 4332 4333 // If the cons string tree is too deep, we simply abort the recursion and 4334 // retry with a flattened subject string. 4335 const int kRecursionLimit = 0x1000; 4336 bool found = false; 4337 Handle<String> result; 4338 if (StringReplaceOneCharWithString( 4339 isolate, subject, search, replace, &found, kRecursionLimit) 4340 .ToHandle(&result)) { 4341 return *result; 4342 } 4343 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 4344 4345 subject = String::Flatten(subject); 4346 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4347 isolate, result, 4348 StringReplaceOneCharWithString( 4349 isolate, subject, search, replace, &found, kRecursionLimit)); 4350 return *result; 4351 } 4352 4353 4354 // Perform string match of pattern on subject, starting at start index. 4355 // Caller must ensure that 0 <= start_index <= sub->length(), 4356 // and should check that pat->length() + start_index <= sub->length(). 4357 int Runtime::StringMatch(Isolate* isolate, 4358 Handle<String> sub, 4359 Handle<String> pat, 4360 int start_index) { 4361 ASSERT(0 <= start_index); 4362 ASSERT(start_index <= sub->length()); 4363 4364 int pattern_length = pat->length(); 4365 if (pattern_length == 0) return start_index; 4366 4367 int subject_length = sub->length(); 4368 if (start_index + pattern_length > subject_length) return -1; 4369 4370 sub = String::Flatten(sub); 4371 pat = String::Flatten(pat); 4372 4373 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4374 // Extract flattened substrings of cons strings before determining asciiness. 4375 String::FlatContent seq_sub = sub->GetFlatContent(); 4376 String::FlatContent seq_pat = pat->GetFlatContent(); 4377 4378 // dispatch on type of strings 4379 if (seq_pat.IsAscii()) { 4380 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector(); 4381 if (seq_sub.IsAscii()) { 4382 return SearchString(isolate, 4383 seq_sub.ToOneByteVector(), 4384 pat_vector, 4385 start_index); 4386 } 4387 return SearchString(isolate, 4388 seq_sub.ToUC16Vector(), 4389 pat_vector, 4390 start_index); 4391 } 4392 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); 4393 if (seq_sub.IsAscii()) { 4394 return SearchString(isolate, 4395 seq_sub.ToOneByteVector(), 4396 pat_vector, 4397 start_index); 4398 } 4399 return SearchString(isolate, 4400 seq_sub.ToUC16Vector(), 4401 pat_vector, 4402 start_index); 4403 } 4404 4405 4406 RUNTIME_FUNCTION(Runtime_StringIndexOf) { 4407 HandleScope scope(isolate); 4408 ASSERT(args.length() == 3); 4409 4410 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4411 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4412 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); 4413 4414 uint32_t start_index; 4415 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4416 4417 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 4418 int position = Runtime::StringMatch(isolate, sub, pat, start_index); 4419 return Smi::FromInt(position); 4420 } 4421 4422 4423 template <typename schar, typename pchar> 4424 static int StringMatchBackwards(Vector<const schar> subject, 4425 Vector<const pchar> pattern, 4426 int idx) { 4427 int pattern_length = pattern.length(); 4428 ASSERT(pattern_length >= 1); 4429 ASSERT(idx + pattern_length <= subject.length()); 4430 4431 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 4432 for (int i = 0; i < pattern_length; i++) { 4433 uc16 c = pattern[i]; 4434 if (c > String::kMaxOneByteCharCode) { 4435 return -1; 4436 } 4437 } 4438 } 4439 4440 pchar pattern_first_char = pattern[0]; 4441 for (int i = idx; i >= 0; i--) { 4442 if (subject[i] != pattern_first_char) continue; 4443 int j = 1; 4444 while (j < pattern_length) { 4445 if (pattern[j] != subject[i+j]) { 4446 break; 4447 } 4448 j++; 4449 } 4450 if (j == pattern_length) { 4451 return i; 4452 } 4453 } 4454 return -1; 4455 } 4456 4457 4458 RUNTIME_FUNCTION(Runtime_StringLastIndexOf) { 4459 HandleScope scope(isolate); 4460 ASSERT(args.length() == 3); 4461 4462 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4463 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4464 CONVERT_ARG_HANDLE_CHECKED(Object, index, 2); 4465 4466 uint32_t start_index; 4467 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4468 4469 uint32_t pat_length = pat->length(); 4470 uint32_t sub_length = sub->length(); 4471 4472 if (start_index + pat_length > sub_length) { 4473 start_index = sub_length - pat_length; 4474 } 4475 4476 if (pat_length == 0) { 4477 return Smi::FromInt(start_index); 4478 } 4479 4480 sub = String::Flatten(sub); 4481 pat = String::Flatten(pat); 4482 4483 int position = -1; 4484 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4485 4486 String::FlatContent sub_content = sub->GetFlatContent(); 4487 String::FlatContent pat_content = pat->GetFlatContent(); 4488 4489 if (pat_content.IsAscii()) { 4490 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector(); 4491 if (sub_content.IsAscii()) { 4492 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4493 pat_vector, 4494 start_index); 4495 } else { 4496 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4497 pat_vector, 4498 start_index); 4499 } 4500 } else { 4501 Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); 4502 if (sub_content.IsAscii()) { 4503 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4504 pat_vector, 4505 start_index); 4506 } else { 4507 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4508 pat_vector, 4509 start_index); 4510 } 4511 } 4512 4513 return Smi::FromInt(position); 4514 } 4515 4516 4517 RUNTIME_FUNCTION(Runtime_StringLocaleCompare) { 4518 HandleScope handle_scope(isolate); 4519 ASSERT(args.length() == 2); 4520 4521 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); 4522 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); 4523 4524 if (str1.is_identical_to(str2)) return Smi::FromInt(0); // Equal. 4525 int str1_length = str1->length(); 4526 int str2_length = str2->length(); 4527 4528 // Decide trivial cases without flattening. 4529 if (str1_length == 0) { 4530 if (str2_length == 0) return Smi::FromInt(0); // Equal. 4531 return Smi::FromInt(-str2_length); 4532 } else { 4533 if (str2_length == 0) return Smi::FromInt(str1_length); 4534 } 4535 4536 int end = str1_length < str2_length ? str1_length : str2_length; 4537 4538 // No need to flatten if we are going to find the answer on the first 4539 // character. At this point we know there is at least one character 4540 // in each string, due to the trivial case handling above. 4541 int d = str1->Get(0) - str2->Get(0); 4542 if (d != 0) return Smi::FromInt(d); 4543 4544 str1 = String::Flatten(str1); 4545 str2 = String::Flatten(str2); 4546 4547 DisallowHeapAllocation no_gc; 4548 String::FlatContent flat1 = str1->GetFlatContent(); 4549 String::FlatContent flat2 = str2->GetFlatContent(); 4550 4551 for (int i = 0; i < end; i++) { 4552 if (flat1.Get(i) != flat2.Get(i)) { 4553 return Smi::FromInt(flat1.Get(i) - flat2.Get(i)); 4554 } 4555 } 4556 4557 return Smi::FromInt(str1_length - str2_length); 4558 } 4559 4560 4561 RUNTIME_FUNCTION(RuntimeHidden_SubString) { 4562 HandleScope scope(isolate); 4563 ASSERT(args.length() == 3); 4564 4565 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 4566 int start, end; 4567 // We have a fast integer-only case here to avoid a conversion to double in 4568 // the common case where from and to are Smis. 4569 if (args[1]->IsSmi() && args[2]->IsSmi()) { 4570 CONVERT_SMI_ARG_CHECKED(from_number, 1); 4571 CONVERT_SMI_ARG_CHECKED(to_number, 2); 4572 start = from_number; 4573 end = to_number; 4574 } else { 4575 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); 4576 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); 4577 start = FastD2IChecked(from_number); 4578 end = FastD2IChecked(to_number); 4579 } 4580 RUNTIME_ASSERT(end >= start); 4581 RUNTIME_ASSERT(start >= 0); 4582 RUNTIME_ASSERT(end <= string->length()); 4583 isolate->counters()->sub_string_runtime()->Increment(); 4584 4585 return *isolate->factory()->NewSubString(string, start, end); 4586 } 4587 4588 4589 RUNTIME_FUNCTION(Runtime_StringMatch) { 4590 HandleScope handles(isolate); 4591 ASSERT(args.length() == 3); 4592 4593 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4594 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4595 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); 4596 4597 RUNTIME_ASSERT(regexp_info->HasFastObjectElements()); 4598 4599 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4600 if (global_cache.HasException()) return isolate->heap()->exception(); 4601 4602 int capture_count = regexp->CaptureCount(); 4603 4604 ZoneScope zone_scope(isolate->runtime_zone()); 4605 ZoneList<int> offsets(8, zone_scope.zone()); 4606 4607 while (true) { 4608 int32_t* match = global_cache.FetchNext(); 4609 if (match == NULL) break; 4610 offsets.Add(match[0], zone_scope.zone()); // start 4611 offsets.Add(match[1], zone_scope.zone()); // end 4612 } 4613 4614 if (global_cache.HasException()) return isolate->heap()->exception(); 4615 4616 if (offsets.length() == 0) { 4617 // Not a single match. 4618 return isolate->heap()->null_value(); 4619 } 4620 4621 RegExpImpl::SetLastMatchInfo(regexp_info, 4622 subject, 4623 capture_count, 4624 global_cache.LastSuccessfulMatch()); 4625 4626 int matches = offsets.length() / 2; 4627 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); 4628 Handle<String> substring = 4629 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); 4630 elements->set(0, *substring); 4631 for (int i = 1; i < matches; i++) { 4632 HandleScope temp_scope(isolate); 4633 int from = offsets.at(i * 2); 4634 int to = offsets.at(i * 2 + 1); 4635 Handle<String> substring = 4636 isolate->factory()->NewProperSubString(subject, from, to); 4637 elements->set(i, *substring); 4638 } 4639 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); 4640 result->set_length(Smi::FromInt(matches)); 4641 return *result; 4642 } 4643 4644 4645 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain 4646 // separate last match info. See comment on that function. 4647 template<bool has_capture> 4648 static Object* SearchRegExpMultiple( 4649 Isolate* isolate, 4650 Handle<String> subject, 4651 Handle<JSRegExp> regexp, 4652 Handle<JSArray> last_match_array, 4653 Handle<JSArray> result_array) { 4654 ASSERT(subject->IsFlat()); 4655 ASSERT_NE(has_capture, regexp->CaptureCount() == 0); 4656 4657 int capture_count = regexp->CaptureCount(); 4658 int subject_length = subject->length(); 4659 4660 static const int kMinLengthToCache = 0x1000; 4661 4662 if (subject_length > kMinLengthToCache) { 4663 Handle<Object> cached_answer(RegExpResultsCache::Lookup( 4664 isolate->heap(), 4665 *subject, 4666 regexp->data(), 4667 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate); 4668 if (*cached_answer != Smi::FromInt(0)) { 4669 Handle<FixedArray> cached_fixed_array = 4670 Handle<FixedArray>(FixedArray::cast(*cached_answer)); 4671 // The cache FixedArray is a COW-array and can therefore be reused. 4672 JSArray::SetContent(result_array, cached_fixed_array); 4673 // The actual length of the result array is stored in the last element of 4674 // the backing store (the backing FixedArray may have a larger capacity). 4675 Object* cached_fixed_array_last_element = 4676 cached_fixed_array->get(cached_fixed_array->length() - 1); 4677 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element); 4678 result_array->set_length(js_array_length); 4679 RegExpImpl::SetLastMatchInfo( 4680 last_match_array, subject, capture_count, NULL); 4681 return *result_array; 4682 } 4683 } 4684 4685 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4686 if (global_cache.HasException()) return isolate->heap()->exception(); 4687 4688 // Ensured in Runtime_RegExpExecMultiple. 4689 ASSERT(result_array->HasFastObjectElements()); 4690 Handle<FixedArray> result_elements( 4691 FixedArray::cast(result_array->elements())); 4692 if (result_elements->length() < 16) { 4693 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 4694 } 4695 4696 FixedArrayBuilder builder(result_elements); 4697 4698 // Position to search from. 4699 int match_start = -1; 4700 int match_end = 0; 4701 bool first = true; 4702 4703 // Two smis before and after the match, for very long strings. 4704 static const int kMaxBuilderEntriesPerRegExpMatch = 5; 4705 4706 while (true) { 4707 int32_t* current_match = global_cache.FetchNext(); 4708 if (current_match == NULL) break; 4709 match_start = current_match[0]; 4710 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 4711 if (match_end < match_start) { 4712 ReplacementStringBuilder::AddSubjectSlice(&builder, 4713 match_end, 4714 match_start); 4715 } 4716 match_end = current_match[1]; 4717 { 4718 // Avoid accumulating new handles inside loop. 4719 HandleScope temp_scope(isolate); 4720 Handle<String> match; 4721 if (!first) { 4722 match = isolate->factory()->NewProperSubString(subject, 4723 match_start, 4724 match_end); 4725 } else { 4726 match = isolate->factory()->NewSubString(subject, 4727 match_start, 4728 match_end); 4729 first = false; 4730 } 4731 4732 if (has_capture) { 4733 // Arguments array to replace function is match, captures, index and 4734 // subject, i.e., 3 + capture count in total. 4735 Handle<FixedArray> elements = 4736 isolate->factory()->NewFixedArray(3 + capture_count); 4737 4738 elements->set(0, *match); 4739 for (int i = 1; i <= capture_count; i++) { 4740 int start = current_match[i * 2]; 4741 if (start >= 0) { 4742 int end = current_match[i * 2 + 1]; 4743 ASSERT(start <= end); 4744 Handle<String> substring = 4745 isolate->factory()->NewSubString(subject, start, end); 4746 elements->set(i, *substring); 4747 } else { 4748 ASSERT(current_match[i * 2 + 1] < 0); 4749 elements->set(i, isolate->heap()->undefined_value()); 4750 } 4751 } 4752 elements->set(capture_count + 1, Smi::FromInt(match_start)); 4753 elements->set(capture_count + 2, *subject); 4754 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 4755 } else { 4756 builder.Add(*match); 4757 } 4758 } 4759 } 4760 4761 if (global_cache.HasException()) return isolate->heap()->exception(); 4762 4763 if (match_start >= 0) { 4764 // Finished matching, with at least one match. 4765 if (match_end < subject_length) { 4766 ReplacementStringBuilder::AddSubjectSlice(&builder, 4767 match_end, 4768 subject_length); 4769 } 4770 4771 RegExpImpl::SetLastMatchInfo( 4772 last_match_array, subject, capture_count, NULL); 4773 4774 if (subject_length > kMinLengthToCache) { 4775 // Store the length of the result array into the last element of the 4776 // backing FixedArray. 4777 builder.EnsureCapacity(1); 4778 Handle<FixedArray> fixed_array = builder.array(); 4779 fixed_array->set(fixed_array->length() - 1, 4780 Smi::FromInt(builder.length())); 4781 // Cache the result and turn the FixedArray into a COW array. 4782 RegExpResultsCache::Enter(isolate, 4783 subject, 4784 handle(regexp->data(), isolate), 4785 fixed_array, 4786 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 4787 } 4788 return *builder.ToJSArray(result_array); 4789 } else { 4790 return isolate->heap()->null_value(); // No matches at all. 4791 } 4792 } 4793 4794 4795 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets 4796 // lastMatchInfoOverride to maintain the last match info, so we don't need to 4797 // set any other last match array info. 4798 RUNTIME_FUNCTION(Runtime_RegExpExecMultiple) { 4799 HandleScope handles(isolate); 4800 ASSERT(args.length() == 4); 4801 4802 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 4803 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 4804 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); 4805 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); 4806 RUNTIME_ASSERT(last_match_info->HasFastObjectElements()); 4807 RUNTIME_ASSERT(result_array->HasFastObjectElements()); 4808 4809 subject = String::Flatten(subject); 4810 RUNTIME_ASSERT(regexp->GetFlags().is_global()); 4811 4812 if (regexp->CaptureCount() == 0) { 4813 return SearchRegExpMultiple<false>( 4814 isolate, subject, regexp, last_match_info, result_array); 4815 } else { 4816 return SearchRegExpMultiple<true>( 4817 isolate, subject, regexp, last_match_info, result_array); 4818 } 4819 } 4820 4821 4822 RUNTIME_FUNCTION(Runtime_NumberToRadixString) { 4823 HandleScope scope(isolate); 4824 ASSERT(args.length() == 2); 4825 CONVERT_SMI_ARG_CHECKED(radix, 1); 4826 RUNTIME_ASSERT(2 <= radix && radix <= 36); 4827 4828 // Fast case where the result is a one character string. 4829 if (args[0]->IsSmi()) { 4830 int value = args.smi_at(0); 4831 if (value >= 0 && value < radix) { 4832 // Character array used for conversion. 4833 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 4834 return *isolate->factory()-> 4835 LookupSingleCharacterStringFromCode(kCharTable[value]); 4836 } 4837 } 4838 4839 // Slow case. 4840 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4841 if (std::isnan(value)) { 4842 return isolate->heap()->nan_string(); 4843 } 4844 if (std::isinf(value)) { 4845 if (value < 0) { 4846 return isolate->heap()->minus_infinity_string(); 4847 } 4848 return isolate->heap()->infinity_string(); 4849 } 4850 char* str = DoubleToRadixCString(value, radix); 4851 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); 4852 DeleteArray(str); 4853 return *result; 4854 } 4855 4856 4857 RUNTIME_FUNCTION(Runtime_NumberToFixed) { 4858 HandleScope scope(isolate); 4859 ASSERT(args.length() == 2); 4860 4861 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4862 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4863 int f = FastD2IChecked(f_number); 4864 // See DoubleToFixedCString for these constants: 4865 RUNTIME_ASSERT(f >= 0 && f <= 20); 4866 RUNTIME_ASSERT(!Double(value).IsSpecial()); 4867 char* str = DoubleToFixedCString(value, f); 4868 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); 4869 DeleteArray(str); 4870 return *result; 4871 } 4872 4873 4874 RUNTIME_FUNCTION(Runtime_NumberToExponential) { 4875 HandleScope scope(isolate); 4876 ASSERT(args.length() == 2); 4877 4878 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4879 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4880 int f = FastD2IChecked(f_number); 4881 RUNTIME_ASSERT(f >= -1 && f <= 20); 4882 RUNTIME_ASSERT(!Double(value).IsSpecial()); 4883 char* str = DoubleToExponentialCString(value, f); 4884 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); 4885 DeleteArray(str); 4886 return *result; 4887 } 4888 4889 4890 RUNTIME_FUNCTION(Runtime_NumberToPrecision) { 4891 HandleScope scope(isolate); 4892 ASSERT(args.length() == 2); 4893 4894 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4895 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4896 int f = FastD2IChecked(f_number); 4897 RUNTIME_ASSERT(f >= 1 && f <= 21); 4898 RUNTIME_ASSERT(!Double(value).IsSpecial()); 4899 char* str = DoubleToPrecisionCString(value, f); 4900 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); 4901 DeleteArray(str); 4902 return *result; 4903 } 4904 4905 4906 RUNTIME_FUNCTION(Runtime_IsValidSmi) { 4907 SealHandleScope shs(isolate); 4908 ASSERT(args.length() == 1); 4909 4910 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]); 4911 return isolate->heap()->ToBoolean(Smi::IsValid(number)); 4912 } 4913 4914 4915 // Returns a single character string where first character equals 4916 // string->Get(index). 4917 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 4918 if (index < static_cast<uint32_t>(string->length())) { 4919 Factory* factory = string->GetIsolate()->factory(); 4920 return factory->LookupSingleCharacterStringFromCode( 4921 String::Flatten(string)->Get(index)); 4922 } 4923 return Execution::CharAt(string, index); 4924 } 4925 4926 4927 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate, 4928 Handle<Object> object, 4929 uint32_t index) { 4930 // Handle [] indexing on Strings 4931 if (object->IsString()) { 4932 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 4933 if (!result->IsUndefined()) return result; 4934 } 4935 4936 // Handle [] indexing on String objects 4937 if (object->IsStringObjectWithCharacterAt(index)) { 4938 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 4939 Handle<Object> result = 4940 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 4941 if (!result->IsUndefined()) return result; 4942 } 4943 4944 Handle<Object> result; 4945 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 4946 Handle<Object> proto(object->GetPrototype(isolate), isolate); 4947 return Object::GetElement(isolate, proto, index); 4948 } else { 4949 return Object::GetElement(isolate, object, index); 4950 } 4951 } 4952 4953 4954 MUST_USE_RESULT 4955 static MaybeHandle<Name> ToName(Isolate* isolate, Handle<Object> key) { 4956 if (key->IsName()) { 4957 return Handle<Name>::cast(key); 4958 } else { 4959 Handle<Object> converted; 4960 ASSIGN_RETURN_ON_EXCEPTION( 4961 isolate, converted, Execution::ToString(isolate, key), Name); 4962 return Handle<Name>::cast(converted); 4963 } 4964 } 4965 4966 4967 MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate, 4968 Handle<JSReceiver> object, 4969 Handle<Object> key) { 4970 // Check if the given key is an array index. 4971 uint32_t index; 4972 if (key->ToArrayIndex(&index)) { 4973 return isolate->factory()->ToBoolean(JSReceiver::HasElement(object, index)); 4974 } 4975 4976 // Convert the key to a name - possibly by calling back into JavaScript. 4977 Handle<Name> name; 4978 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); 4979 4980 return isolate->factory()->ToBoolean(JSReceiver::HasProperty(object, name)); 4981 } 4982 4983 4984 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate, 4985 Handle<Object> object, 4986 Handle<Object> key) { 4987 if (object->IsUndefined() || object->IsNull()) { 4988 Handle<Object> args[2] = { key, object }; 4989 return isolate->Throw<Object>( 4990 isolate->factory()->NewTypeError("non_object_property_load", 4991 HandleVector(args, 2))); 4992 } 4993 4994 // Check if the given key is an array index. 4995 uint32_t index; 4996 if (key->ToArrayIndex(&index)) { 4997 return GetElementOrCharAt(isolate, object, index); 4998 } 4999 5000 // Convert the key to a name - possibly by calling back into JavaScript. 5001 Handle<Name> name; 5002 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object); 5003 5004 // Check if the name is trivially convertible to an index and get 5005 // the element if so. 5006 if (name->AsArrayIndex(&index)) { 5007 return GetElementOrCharAt(isolate, object, index); 5008 } else { 5009 return Object::GetProperty(object, name); 5010 } 5011 } 5012 5013 5014 RUNTIME_FUNCTION(Runtime_GetProperty) { 5015 HandleScope scope(isolate); 5016 ASSERT(args.length() == 2); 5017 5018 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 5019 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 5020 Handle<Object> result; 5021 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5022 isolate, result, 5023 Runtime::GetObjectProperty(isolate, object, key)); 5024 return *result; 5025 } 5026 5027 5028 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. 5029 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { 5030 HandleScope scope(isolate); 5031 ASSERT(args.length() == 2); 5032 5033 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); 5034 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); 5035 5036 // Fast cases for getting named properties of the receiver JSObject 5037 // itself. 5038 // 5039 // The global proxy objects has to be excluded since LookupOwn on 5040 // the global proxy object can return a valid result even though the 5041 // global proxy object never has properties. This is the case 5042 // because the global proxy object forwards everything to its hidden 5043 // prototype including own lookups. 5044 // 5045 // Additionally, we need to make sure that we do not cache results 5046 // for objects that require access checks. 5047 if (receiver_obj->IsJSObject()) { 5048 if (!receiver_obj->IsJSGlobalProxy() && 5049 !receiver_obj->IsAccessCheckNeeded() && 5050 key_obj->IsName()) { 5051 DisallowHeapAllocation no_allocation; 5052 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj); 5053 Handle<Name> key = Handle<Name>::cast(key_obj); 5054 if (receiver->HasFastProperties()) { 5055 // Attempt to use lookup cache. 5056 Handle<Map> receiver_map(receiver->map(), isolate); 5057 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); 5058 int index = keyed_lookup_cache->Lookup(receiver_map, key); 5059 if (index != -1) { 5060 // Doubles are not cached, so raw read the value. 5061 Object* value = receiver->RawFastPropertyAt( 5062 FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index)); 5063 return value->IsTheHole() 5064 ? isolate->heap()->undefined_value() 5065 : value; 5066 } 5067 // Lookup cache miss. Perform lookup and update the cache if 5068 // appropriate. 5069 LookupResult result(isolate); 5070 receiver->LookupOwn(key, &result); 5071 if (result.IsField()) { 5072 FieldIndex field_index = result.GetFieldIndex(); 5073 // Do not track double fields in the keyed lookup cache. Reading 5074 // double values requires boxing. 5075 if (!result.representation().IsDouble()) { 5076 keyed_lookup_cache->Update(receiver_map, key, 5077 field_index.GetKeyedLookupCacheIndex()); 5078 } 5079 AllowHeapAllocation allow_allocation; 5080 return *JSObject::FastPropertyAt(receiver, result.representation(), 5081 field_index); 5082 } 5083 } else { 5084 // Attempt dictionary lookup. 5085 NameDictionary* dictionary = receiver->property_dictionary(); 5086 int entry = dictionary->FindEntry(key); 5087 if ((entry != NameDictionary::kNotFound) && 5088 (dictionary->DetailsAt(entry).type() == NORMAL)) { 5089 Object* value = dictionary->ValueAt(entry); 5090 if (!receiver->IsGlobalObject()) return value; 5091 value = PropertyCell::cast(value)->value(); 5092 if (!value->IsTheHole()) return value; 5093 // If value is the hole do the general lookup. 5094 } 5095 } 5096 } else if (FLAG_smi_only_arrays && key_obj->IsSmi()) { 5097 // JSObject without a name key. If the key is a Smi, check for a 5098 // definite out-of-bounds access to elements, which is a strong indicator 5099 // that subsequent accesses will also call the runtime. Proactively 5100 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of 5101 // doubles for those future calls in the case that the elements would 5102 // become FAST_DOUBLE_ELEMENTS. 5103 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj); 5104 ElementsKind elements_kind = js_object->GetElementsKind(); 5105 if (IsFastDoubleElementsKind(elements_kind)) { 5106 Handle<Smi> key = Handle<Smi>::cast(key_obj); 5107 if (key->value() >= js_object->elements()->length()) { 5108 if (IsFastHoleyElementsKind(elements_kind)) { 5109 elements_kind = FAST_HOLEY_ELEMENTS; 5110 } else { 5111 elements_kind = FAST_ELEMENTS; 5112 } 5113 RETURN_FAILURE_ON_EXCEPTION( 5114 isolate, TransitionElements(js_object, elements_kind, isolate)); 5115 } 5116 } else { 5117 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || 5118 !IsFastElementsKind(elements_kind)); 5119 } 5120 } 5121 } else if (receiver_obj->IsString() && key_obj->IsSmi()) { 5122 // Fast case for string indexing using [] with a smi index. 5123 Handle<String> str = Handle<String>::cast(receiver_obj); 5124 int index = args.smi_at(1); 5125 if (index >= 0 && index < str->length()) { 5126 return *GetCharAt(str, index); 5127 } 5128 } 5129 5130 // Fall back to GetObjectProperty. 5131 Handle<Object> result; 5132 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5133 isolate, result, 5134 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); 5135 return *result; 5136 } 5137 5138 5139 static bool IsValidAccessor(Handle<Object> obj) { 5140 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull(); 5141 } 5142 5143 5144 // Implements part of 8.12.9 DefineOwnProperty. 5145 // There are 3 cases that lead here: 5146 // Step 4b - define a new accessor property. 5147 // Steps 9c & 12 - replace an existing data property with an accessor property. 5148 // Step 12 - update an existing accessor property with an accessor or generic 5149 // descriptor. 5150 RUNTIME_FUNCTION(Runtime_DefineOrRedefineAccessorProperty) { 5151 HandleScope scope(isolate); 5152 ASSERT(args.length() == 5); 5153 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5154 RUNTIME_ASSERT(!obj->IsNull()); 5155 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5156 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 5157 RUNTIME_ASSERT(IsValidAccessor(getter)); 5158 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 5159 RUNTIME_ASSERT(IsValidAccessor(setter)); 5160 CONVERT_SMI_ARG_CHECKED(unchecked, 4); 5161 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5162 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 5163 5164 bool fast = obj->HasFastProperties(); 5165 // DefineAccessor checks access rights. 5166 JSObject::DefineAccessor(obj, name, getter, setter, attr); 5167 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5168 if (fast) JSObject::TransformToFastProperties(obj, 0); 5169 return isolate->heap()->undefined_value(); 5170 } 5171 5172 5173 // Implements part of 8.12.9 DefineOwnProperty. 5174 // There are 3 cases that lead here: 5175 // Step 4a - define a new data property. 5176 // Steps 9b & 12 - replace an existing accessor property with a data property. 5177 // Step 12 - update an existing data property with a data or generic 5178 // descriptor. 5179 RUNTIME_FUNCTION(Runtime_DefineOrRedefineDataProperty) { 5180 HandleScope scope(isolate); 5181 ASSERT(args.length() == 4); 5182 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); 5183 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5184 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2); 5185 CONVERT_SMI_ARG_CHECKED(unchecked, 3); 5186 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5187 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 5188 5189 // Check access rights if needed. 5190 if (js_object->IsAccessCheckNeeded() && 5191 !isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) { 5192 return isolate->heap()->undefined_value(); 5193 } 5194 5195 LookupResult lookup(isolate); 5196 js_object->LookupOwnRealNamedProperty(name, &lookup); 5197 5198 // Take special care when attributes are different and there is already 5199 // a property. For simplicity we normalize the property which enables us 5200 // to not worry about changing the instance_descriptor and creating a new 5201 // map. The current version of SetObjectProperty does not handle attributes 5202 // correctly in the case where a property is a field and is reset with 5203 // new attributes. 5204 if (lookup.IsFound() && 5205 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) { 5206 // New attributes - normalize to avoid writing to instance descriptor 5207 if (js_object->IsJSGlobalProxy()) { 5208 // Since the result is a property, the prototype will exist so 5209 // we don't have to check for null. 5210 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); 5211 } 5212 5213 if (attr != lookup.GetAttributes() || 5214 (lookup.IsPropertyCallbacks() && 5215 !lookup.GetCallbackObject()->IsAccessorInfo())) { 5216 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); 5217 } 5218 5219 // Use IgnoreAttributes version since a readonly property may be 5220 // overridden and SetProperty does not allow this. 5221 Handle<Object> result; 5222 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5223 isolate, result, 5224 JSObject::SetOwnPropertyIgnoreAttributes( 5225 js_object, name, obj_value, attr, 5226 Object::OPTIMAL_REPRESENTATION, 5227 ALLOW_AS_CONSTANT, 5228 JSReceiver::PERFORM_EXTENSIBILITY_CHECK, 5229 JSReceiver::MAY_BE_STORE_FROM_KEYED, 5230 JSObject::DONT_FORCE_FIELD)); 5231 return *result; 5232 } 5233 5234 Handle<Object> result; 5235 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5236 isolate, result, 5237 Runtime::ForceSetObjectProperty( 5238 js_object, name, obj_value, attr, 5239 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED)); 5240 return *result; 5241 } 5242 5243 5244 // Return property without being observable by accessors or interceptors. 5245 RUNTIME_FUNCTION(Runtime_GetDataProperty) { 5246 HandleScope scope(isolate); 5247 ASSERT(args.length() == 2); 5248 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5249 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5250 return *JSObject::GetDataProperty(object, key); 5251 } 5252 5253 5254 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate, 5255 Handle<Object> object, 5256 Handle<Object> key, 5257 Handle<Object> value, 5258 PropertyAttributes attr, 5259 StrictMode strict_mode) { 5260 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; 5261 5262 if (object->IsUndefined() || object->IsNull()) { 5263 Handle<Object> args[2] = { key, object }; 5264 Handle<Object> error = 5265 isolate->factory()->NewTypeError("non_object_property_store", 5266 HandleVector(args, 2)); 5267 return isolate->Throw<Object>(error); 5268 } 5269 5270 if (object->IsJSProxy()) { 5271 Handle<Object> name_object; 5272 if (key->IsSymbol()) { 5273 name_object = key; 5274 } else { 5275 ASSIGN_RETURN_ON_EXCEPTION( 5276 isolate, name_object, Execution::ToString(isolate, key), Object); 5277 } 5278 Handle<Name> name = Handle<Name>::cast(name_object); 5279 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value, 5280 attr, 5281 strict_mode); 5282 } 5283 5284 // If the object isn't a JavaScript object, we ignore the store. 5285 if (!object->IsJSObject()) return value; 5286 5287 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 5288 5289 // Check if the given key is an array index. 5290 uint32_t index; 5291 if (key->ToArrayIndex(&index)) { 5292 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5293 // of a string using [] notation. We need to support this too in 5294 // JavaScript. 5295 // In the case of a String object we just need to redirect the assignment to 5296 // the underlying string if the index is in range. Since the underlying 5297 // string does nothing with the assignment then we can ignore such 5298 // assignments. 5299 if (js_object->IsStringObjectWithCharacterAt(index)) { 5300 return value; 5301 } 5302 5303 JSObject::ValidateElements(js_object); 5304 if (js_object->HasExternalArrayElements() || 5305 js_object->HasFixedTypedArrayElements()) { 5306 if (!value->IsNumber() && !value->IsUndefined()) { 5307 ASSIGN_RETURN_ON_EXCEPTION( 5308 isolate, value, Execution::ToNumber(isolate, value), Object); 5309 } 5310 } 5311 5312 MaybeHandle<Object> result = JSObject::SetElement( 5313 js_object, index, value, attr, strict_mode, true, set_mode); 5314 JSObject::ValidateElements(js_object); 5315 5316 return result.is_null() ? result : value; 5317 } 5318 5319 if (key->IsName()) { 5320 Handle<Name> name = Handle<Name>::cast(key); 5321 if (name->AsArrayIndex(&index)) { 5322 if (js_object->HasExternalArrayElements()) { 5323 if (!value->IsNumber() && !value->IsUndefined()) { 5324 ASSIGN_RETURN_ON_EXCEPTION( 5325 isolate, value, Execution::ToNumber(isolate, value), Object); 5326 } 5327 } 5328 return JSObject::SetElement(js_object, index, value, attr, 5329 strict_mode, true, set_mode); 5330 } else { 5331 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); 5332 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); 5333 } 5334 } 5335 5336 // Call-back into JavaScript to convert the key to a string. 5337 Handle<Object> converted; 5338 ASSIGN_RETURN_ON_EXCEPTION( 5339 isolate, converted, Execution::ToString(isolate, key), Object); 5340 Handle<String> name = Handle<String>::cast(converted); 5341 5342 if (name->AsArrayIndex(&index)) { 5343 return JSObject::SetElement(js_object, index, value, attr, 5344 strict_mode, true, set_mode); 5345 } else { 5346 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); 5347 } 5348 } 5349 5350 5351 MaybeHandle<Object> Runtime::ForceSetObjectProperty( 5352 Handle<JSObject> js_object, 5353 Handle<Object> key, 5354 Handle<Object> value, 5355 PropertyAttributes attr, 5356 JSReceiver::StoreFromKeyed store_from_keyed) { 5357 Isolate* isolate = js_object->GetIsolate(); 5358 // Check if the given key is an array index. 5359 uint32_t index; 5360 if (key->ToArrayIndex(&index)) { 5361 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5362 // of a string using [] notation. We need to support this too in 5363 // JavaScript. 5364 // In the case of a String object we just need to redirect the assignment to 5365 // the underlying string if the index is in range. Since the underlying 5366 // string does nothing with the assignment then we can ignore such 5367 // assignments. 5368 if (js_object->IsStringObjectWithCharacterAt(index)) { 5369 return value; 5370 } 5371 5372 return JSObject::SetElement(js_object, index, value, attr, 5373 SLOPPY, false, DEFINE_PROPERTY); 5374 } 5375 5376 if (key->IsName()) { 5377 Handle<Name> name = Handle<Name>::cast(key); 5378 if (name->AsArrayIndex(&index)) { 5379 return JSObject::SetElement(js_object, index, value, attr, 5380 SLOPPY, false, DEFINE_PROPERTY); 5381 } else { 5382 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); 5383 return JSObject::SetOwnPropertyIgnoreAttributes( 5384 js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION, 5385 ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK, 5386 store_from_keyed); 5387 } 5388 } 5389 5390 // Call-back into JavaScript to convert the key to a string. 5391 Handle<Object> converted; 5392 ASSIGN_RETURN_ON_EXCEPTION( 5393 isolate, converted, Execution::ToString(isolate, key), Object); 5394 Handle<String> name = Handle<String>::cast(converted); 5395 5396 if (name->AsArrayIndex(&index)) { 5397 return JSObject::SetElement(js_object, index, value, attr, 5398 SLOPPY, false, DEFINE_PROPERTY); 5399 } else { 5400 return JSObject::SetOwnPropertyIgnoreAttributes( 5401 js_object, name, value, attr, Object::OPTIMAL_REPRESENTATION, 5402 ALLOW_AS_CONSTANT, JSReceiver::PERFORM_EXTENSIBILITY_CHECK, 5403 store_from_keyed); 5404 } 5405 } 5406 5407 5408 MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate, 5409 Handle<JSReceiver> receiver, 5410 Handle<Object> key, 5411 JSReceiver::DeleteMode mode) { 5412 // Check if the given key is an array index. 5413 uint32_t index; 5414 if (key->ToArrayIndex(&index)) { 5415 // In Firefox/SpiderMonkey, Safari and Opera you can access the 5416 // characters of a string using [] notation. In the case of a 5417 // String object we just need to redirect the deletion to the 5418 // underlying string if the index is in range. Since the 5419 // underlying string does nothing with the deletion, we can ignore 5420 // such deletions. 5421 if (receiver->IsStringObjectWithCharacterAt(index)) { 5422 return isolate->factory()->true_value(); 5423 } 5424 5425 return JSReceiver::DeleteElement(receiver, index, mode); 5426 } 5427 5428 Handle<Name> name; 5429 if (key->IsName()) { 5430 name = Handle<Name>::cast(key); 5431 } else { 5432 // Call-back into JavaScript to convert the key to a string. 5433 Handle<Object> converted; 5434 ASSIGN_RETURN_ON_EXCEPTION( 5435 isolate, converted, Execution::ToString(isolate, key), Object); 5436 name = Handle<String>::cast(converted); 5437 } 5438 5439 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name)); 5440 return JSReceiver::DeleteProperty(receiver, name, mode); 5441 } 5442 5443 5444 RUNTIME_FUNCTION(Runtime_SetHiddenProperty) { 5445 HandleScope scope(isolate); 5446 RUNTIME_ASSERT(args.length() == 3); 5447 5448 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5449 CONVERT_ARG_HANDLE_CHECKED(String, key, 1); 5450 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5451 RUNTIME_ASSERT(key->IsUniqueName()); 5452 return *JSObject::SetHiddenProperty(object, key, value); 5453 } 5454 5455 5456 RUNTIME_FUNCTION(Runtime_SetProperty) { 5457 HandleScope scope(isolate); 5458 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 5459 5460 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 5461 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 5462 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5463 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); 5464 RUNTIME_ASSERT( 5465 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5466 // Compute attributes. 5467 PropertyAttributes attributes = 5468 static_cast<PropertyAttributes>(unchecked_attributes); 5469 5470 StrictMode strict_mode = SLOPPY; 5471 if (args.length() == 5) { 5472 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 4); 5473 strict_mode = strict_mode_arg; 5474 } 5475 5476 Handle<Object> result; 5477 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5478 isolate, result, 5479 Runtime::SetObjectProperty( 5480 isolate, object, key, value, attributes, strict_mode)); 5481 return *result; 5482 } 5483 5484 5485 RUNTIME_FUNCTION(Runtime_TransitionElementsKind) { 5486 HandleScope scope(isolate); 5487 RUNTIME_ASSERT(args.length() == 2); 5488 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 5489 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1); 5490 JSObject::TransitionElementsKind(array, map->elements_kind()); 5491 return *array; 5492 } 5493 5494 5495 // Set the native flag on the function. 5496 // This is used to decide if we should transform null and undefined 5497 // into the global object when doing call and apply. 5498 RUNTIME_FUNCTION(Runtime_SetNativeFlag) { 5499 SealHandleScope shs(isolate); 5500 RUNTIME_ASSERT(args.length() == 1); 5501 5502 CONVERT_ARG_CHECKED(Object, object, 0); 5503 5504 if (object->IsJSFunction()) { 5505 JSFunction* func = JSFunction::cast(object); 5506 func->shared()->set_native(true); 5507 } 5508 return isolate->heap()->undefined_value(); 5509 } 5510 5511 5512 RUNTIME_FUNCTION(Runtime_SetInlineBuiltinFlag) { 5513 SealHandleScope shs(isolate); 5514 RUNTIME_ASSERT(args.length() == 1); 5515 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 5516 5517 if (object->IsJSFunction()) { 5518 JSFunction* func = JSFunction::cast(*object); 5519 func->shared()->set_inline_builtin(true); 5520 } 5521 return isolate->heap()->undefined_value(); 5522 } 5523 5524 5525 RUNTIME_FUNCTION(Runtime_StoreArrayLiteralElement) { 5526 HandleScope scope(isolate); 5527 RUNTIME_ASSERT(args.length() == 5); 5528 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5529 CONVERT_SMI_ARG_CHECKED(store_index, 1); 5530 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5531 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); 5532 CONVERT_SMI_ARG_CHECKED(literal_index, 4); 5533 5534 Object* raw_literal_cell = literals->get(literal_index); 5535 JSArray* boilerplate = NULL; 5536 if (raw_literal_cell->IsAllocationSite()) { 5537 AllocationSite* site = AllocationSite::cast(raw_literal_cell); 5538 boilerplate = JSArray::cast(site->transition_info()); 5539 } else { 5540 boilerplate = JSArray::cast(raw_literal_cell); 5541 } 5542 Handle<JSArray> boilerplate_object(boilerplate); 5543 ElementsKind elements_kind = object->GetElementsKind(); 5544 ASSERT(IsFastElementsKind(elements_kind)); 5545 // Smis should never trigger transitions. 5546 ASSERT(!value->IsSmi()); 5547 5548 if (value->IsNumber()) { 5549 ASSERT(IsFastSmiElementsKind(elements_kind)); 5550 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5551 ? FAST_HOLEY_DOUBLE_ELEMENTS 5552 : FAST_DOUBLE_ELEMENTS; 5553 if (IsMoreGeneralElementsKindTransition( 5554 boilerplate_object->GetElementsKind(), 5555 transitioned_kind)) { 5556 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5557 } 5558 JSObject::TransitionElementsKind(object, transitioned_kind); 5559 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind())); 5560 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements()); 5561 HeapNumber* number = HeapNumber::cast(*value); 5562 double_array->set(store_index, number->Number()); 5563 } else { 5564 if (!IsFastObjectElementsKind(elements_kind)) { 5565 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5566 ? FAST_HOLEY_ELEMENTS 5567 : FAST_ELEMENTS; 5568 JSObject::TransitionElementsKind(object, transitioned_kind); 5569 ElementsKind boilerplate_elements_kind = 5570 boilerplate_object->GetElementsKind(); 5571 if (IsMoreGeneralElementsKindTransition(boilerplate_elements_kind, 5572 transitioned_kind)) { 5573 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5574 } 5575 } 5576 FixedArray* object_array = FixedArray::cast(object->elements()); 5577 object_array->set(store_index, *value); 5578 } 5579 return *object; 5580 } 5581 5582 5583 // Check whether debugger and is about to step into the callback that is passed 5584 // to a built-in function such as Array.forEach. 5585 RUNTIME_FUNCTION(Runtime_DebugCallbackSupportsStepping) { 5586 ASSERT(args.length() == 1); 5587 if (!isolate->debug()->is_active() || !isolate->debug()->StepInActive()) { 5588 return isolate->heap()->false_value(); 5589 } 5590 CONVERT_ARG_CHECKED(Object, callback, 0); 5591 // We do not step into the callback if it's a builtin or not even a function. 5592 return isolate->heap()->ToBoolean( 5593 callback->IsJSFunction() && !JSFunction::cast(callback)->IsBuiltin()); 5594 } 5595 5596 5597 // Set one shot breakpoints for the callback function that is passed to a 5598 // built-in function such as Array.forEach to enable stepping into the callback. 5599 RUNTIME_FUNCTION(Runtime_DebugPrepareStepInIfStepping) { 5600 ASSERT(args.length() == 1); 5601 Debug* debug = isolate->debug(); 5602 if (!debug->IsStepping()) return isolate->heap()->undefined_value(); 5603 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0); 5604 HandleScope scope(isolate); 5605 // When leaving the callback, step out has been activated, but not performed 5606 // if we do not leave the builtin. To be able to step into the callback 5607 // again, we need to clear the step out at this point. 5608 debug->ClearStepOut(); 5609 debug->FloodWithOneShot(callback); 5610 return isolate->heap()->undefined_value(); 5611 } 5612 5613 5614 // The argument is a closure that is kept until the epilogue is called. 5615 // On exception, the closure is called, which returns the promise if the 5616 // exception is considered uncaught, or undefined otherwise. 5617 RUNTIME_FUNCTION(Runtime_DebugPromiseHandlePrologue) { 5618 ASSERT(args.length() == 1); 5619 HandleScope scope(isolate); 5620 CONVERT_ARG_HANDLE_CHECKED(JSFunction, promise_getter, 0); 5621 isolate->debug()->PromiseHandlePrologue(promise_getter); 5622 return isolate->heap()->undefined_value(); 5623 } 5624 5625 5626 RUNTIME_FUNCTION(Runtime_DebugPromiseHandleEpilogue) { 5627 ASSERT(args.length() == 0); 5628 SealHandleScope shs(isolate); 5629 isolate->debug()->PromiseHandleEpilogue(); 5630 return isolate->heap()->undefined_value(); 5631 } 5632 5633 5634 // Set an own property, even if it is READ_ONLY. If the property does not 5635 // exist, it will be added with attributes NONE. 5636 RUNTIME_FUNCTION(Runtime_IgnoreAttributesAndSetProperty) { 5637 HandleScope scope(isolate); 5638 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 5639 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5640 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5641 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5642 // Compute attributes. 5643 PropertyAttributes attributes = NONE; 5644 if (args.length() == 4) { 5645 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3); 5646 // Only attribute bits should be set. 5647 RUNTIME_ASSERT( 5648 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5649 attributes = static_cast<PropertyAttributes>(unchecked_value); 5650 } 5651 Handle<Object> result; 5652 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5653 isolate, result, 5654 JSObject::SetOwnPropertyIgnoreAttributes( 5655 object, name, value, attributes)); 5656 return *result; 5657 } 5658 5659 5660 RUNTIME_FUNCTION(Runtime_DeleteProperty) { 5661 HandleScope scope(isolate); 5662 ASSERT(args.length() == 3); 5663 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5664 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5665 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); 5666 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT 5667 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION; 5668 Handle<Object> result; 5669 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5670 isolate, result, 5671 JSReceiver::DeleteProperty(object, key, delete_mode)); 5672 return *result; 5673 } 5674 5675 5676 static Object* HasOwnPropertyImplementation(Isolate* isolate, 5677 Handle<JSObject> object, 5678 Handle<Name> key) { 5679 if (JSReceiver::HasOwnProperty(object, key)) { 5680 return isolate->heap()->true_value(); 5681 } 5682 // Handle hidden prototypes. If there's a hidden prototype above this thing 5683 // then we have to check it for properties, because they are supposed to 5684 // look like they are on this object. 5685 Handle<Object> proto(object->GetPrototype(), isolate); 5686 if (proto->IsJSObject() && 5687 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 5688 return HasOwnPropertyImplementation(isolate, 5689 Handle<JSObject>::cast(proto), 5690 key); 5691 } 5692 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5693 return isolate->heap()->false_value(); 5694 } 5695 5696 5697 RUNTIME_FUNCTION(Runtime_HasOwnProperty) { 5698 HandleScope scope(isolate); 5699 ASSERT(args.length() == 2); 5700 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0) 5701 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5702 5703 uint32_t index; 5704 const bool key_is_array_index = key->AsArrayIndex(&index); 5705 5706 // Only JS objects can have properties. 5707 if (object->IsJSObject()) { 5708 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); 5709 // Fast case: either the key is a real named property or it is not 5710 // an array index and there are no interceptors or hidden 5711 // prototypes. 5712 if (JSObject::HasRealNamedProperty(js_obj, key)) { 5713 ASSERT(!isolate->has_scheduled_exception()); 5714 return isolate->heap()->true_value(); 5715 } else { 5716 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5717 } 5718 Map* map = js_obj->map(); 5719 if (!key_is_array_index && 5720 !map->has_named_interceptor() && 5721 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) { 5722 return isolate->heap()->false_value(); 5723 } 5724 // Slow case. 5725 return HasOwnPropertyImplementation(isolate, 5726 Handle<JSObject>(js_obj), 5727 Handle<Name>(key)); 5728 } else if (object->IsString() && key_is_array_index) { 5729 // Well, there is one exception: Handle [] on strings. 5730 Handle<String> string = Handle<String>::cast(object); 5731 if (index < static_cast<uint32_t>(string->length())) { 5732 return isolate->heap()->true_value(); 5733 } 5734 } 5735 return isolate->heap()->false_value(); 5736 } 5737 5738 5739 RUNTIME_FUNCTION(Runtime_HasProperty) { 5740 HandleScope scope(isolate); 5741 ASSERT(args.length() == 2); 5742 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 5743 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5744 5745 bool result = JSReceiver::HasProperty(receiver, key); 5746 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5747 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 5748 return isolate->heap()->ToBoolean(result); 5749 } 5750 5751 5752 RUNTIME_FUNCTION(Runtime_HasElement) { 5753 HandleScope scope(isolate); 5754 ASSERT(args.length() == 2); 5755 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 5756 CONVERT_SMI_ARG_CHECKED(index, 1); 5757 5758 bool result = JSReceiver::HasElement(receiver, index); 5759 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5760 return isolate->heap()->ToBoolean(result); 5761 } 5762 5763 5764 RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) { 5765 HandleScope scope(isolate); 5766 ASSERT(args.length() == 2); 5767 5768 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5769 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5770 5771 PropertyAttributes att = JSReceiver::GetOwnPropertyAttributes(object, key); 5772 if (att == ABSENT || (att & DONT_ENUM) != 0) { 5773 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5774 return isolate->heap()->false_value(); 5775 } 5776 ASSERT(!isolate->has_scheduled_exception()); 5777 return isolate->heap()->true_value(); 5778 } 5779 5780 5781 RUNTIME_FUNCTION(Runtime_GetPropertyNames) { 5782 HandleScope scope(isolate); 5783 ASSERT(args.length() == 1); 5784 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5785 Handle<JSArray> result; 5786 5787 isolate->counters()->for_in()->Increment(); 5788 Handle<FixedArray> elements; 5789 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5790 isolate, elements, 5791 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); 5792 return *isolate->factory()->NewJSArrayWithElements(elements); 5793 } 5794 5795 5796 // Returns either a FixedArray as Runtime_GetPropertyNames, 5797 // or, if the given object has an enum cache that contains 5798 // all enumerable properties of the object and its prototypes 5799 // have none, the map of the object. This is used to speed up 5800 // the check for deletions during a for-in. 5801 RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) { 5802 SealHandleScope shs(isolate); 5803 ASSERT(args.length() == 1); 5804 5805 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0); 5806 5807 if (raw_object->IsSimpleEnum()) return raw_object->map(); 5808 5809 HandleScope scope(isolate); 5810 Handle<JSReceiver> object(raw_object); 5811 Handle<FixedArray> content; 5812 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 5813 isolate, content, 5814 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS)); 5815 5816 // Test again, since cache may have been built by preceding call. 5817 if (object->IsSimpleEnum()) return object->map(); 5818 5819 return *content; 5820 } 5821 5822 5823 // Find the length of the prototype chain that is to be handled as one. If a 5824 // prototype object is hidden it is to be viewed as part of the the object it 5825 // is prototype for. 5826 static int OwnPrototypeChainLength(JSObject* obj) { 5827 int count = 1; 5828 Object* proto = obj->GetPrototype(); 5829 while (proto->IsJSObject() && 5830 JSObject::cast(proto)->map()->is_hidden_prototype()) { 5831 count++; 5832 proto = JSObject::cast(proto)->GetPrototype(); 5833 } 5834 return count; 5835 } 5836 5837 5838 // Return the names of the own named properties. 5839 // args[0]: object 5840 // args[1]: PropertyAttributes as int 5841 RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) { 5842 HandleScope scope(isolate); 5843 ASSERT(args.length() == 2); 5844 if (!args[0]->IsJSObject()) { 5845 return isolate->heap()->undefined_value(); 5846 } 5847 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5848 CONVERT_SMI_ARG_CHECKED(filter_value, 1); 5849 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value); 5850 5851 // Skip the global proxy as it has no properties and always delegates to the 5852 // real global object. 5853 if (obj->IsJSGlobalProxy()) { 5854 // Only collect names if access is permitted. 5855 if (obj->IsAccessCheckNeeded() && 5856 !isolate->MayNamedAccess( 5857 obj, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { 5858 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS); 5859 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5860 return *isolate->factory()->NewJSArray(0); 5861 } 5862 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 5863 } 5864 5865 // Find the number of objects making up this. 5866 int length = OwnPrototypeChainLength(*obj); 5867 5868 // Find the number of own properties for each of the objects. 5869 ScopedVector<int> own_property_count(length); 5870 int total_property_count = 0; 5871 Handle<JSObject> jsproto = obj; 5872 for (int i = 0; i < length; i++) { 5873 // Only collect names if access is permitted. 5874 if (jsproto->IsAccessCheckNeeded() && 5875 !isolate->MayNamedAccess( 5876 jsproto, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { 5877 isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS); 5878 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5879 return *isolate->factory()->NewJSArray(0); 5880 } 5881 int n; 5882 n = jsproto->NumberOfOwnProperties(filter); 5883 own_property_count[i] = n; 5884 total_property_count += n; 5885 if (i < length - 1) { 5886 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5887 } 5888 } 5889 5890 // Allocate an array with storage for all the property names. 5891 Handle<FixedArray> names = 5892 isolate->factory()->NewFixedArray(total_property_count); 5893 5894 // Get the property names. 5895 jsproto = obj; 5896 int next_copy_index = 0; 5897 int hidden_strings = 0; 5898 for (int i = 0; i < length; i++) { 5899 jsproto->GetOwnPropertyNames(*names, next_copy_index, filter); 5900 if (i > 0) { 5901 // Names from hidden prototypes may already have been added 5902 // for inherited function template instances. Count the duplicates 5903 // and stub them out; the final copy pass at the end ignores holes. 5904 for (int j = next_copy_index; 5905 j < next_copy_index + own_property_count[i]; 5906 j++) { 5907 Object* name_from_hidden_proto = names->get(j); 5908 for (int k = 0; k < next_copy_index; k++) { 5909 if (names->get(k) != isolate->heap()->hidden_string()) { 5910 Object* name = names->get(k); 5911 if (name_from_hidden_proto == name) { 5912 names->set(j, isolate->heap()->hidden_string()); 5913 hidden_strings++; 5914 break; 5915 } 5916 } 5917 } 5918 } 5919 } 5920 next_copy_index += own_property_count[i]; 5921 5922 // Hidden properties only show up if the filter does not skip strings. 5923 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) { 5924 hidden_strings++; 5925 } 5926 if (i < length - 1) { 5927 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5928 } 5929 } 5930 5931 // Filter out name of hidden properties object and 5932 // hidden prototype duplicates. 5933 if (hidden_strings > 0) { 5934 Handle<FixedArray> old_names = names; 5935 names = isolate->factory()->NewFixedArray( 5936 names->length() - hidden_strings); 5937 int dest_pos = 0; 5938 for (int i = 0; i < total_property_count; i++) { 5939 Object* name = old_names->get(i); 5940 if (name == isolate->heap()->hidden_string()) { 5941 hidden_strings--; 5942 continue; 5943 } 5944 names->set(dest_pos++, name); 5945 } 5946 ASSERT_EQ(0, hidden_strings); 5947 } 5948 5949 return *isolate->factory()->NewJSArrayWithElements(names); 5950 } 5951 5952 5953 // Return the names of the own indexed properties. 5954 // args[0]: object 5955 RUNTIME_FUNCTION(Runtime_GetOwnElementNames) { 5956 HandleScope scope(isolate); 5957 ASSERT(args.length() == 1); 5958 if (!args[0]->IsJSObject()) { 5959 return isolate->heap()->undefined_value(); 5960 } 5961 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5962 5963 int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE)); 5964 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); 5965 obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 5966 return *isolate->factory()->NewJSArrayWithElements(names); 5967 } 5968 5969 5970 // Return information on whether an object has a named or indexed interceptor. 5971 // args[0]: object 5972 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) { 5973 HandleScope scope(isolate); 5974 ASSERT(args.length() == 1); 5975 if (!args[0]->IsJSObject()) { 5976 return Smi::FromInt(0); 5977 } 5978 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5979 5980 int result = 0; 5981 if (obj->HasNamedInterceptor()) result |= 2; 5982 if (obj->HasIndexedInterceptor()) result |= 1; 5983 5984 return Smi::FromInt(result); 5985 } 5986 5987 5988 // Return property names from named interceptor. 5989 // args[0]: object 5990 RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) { 5991 HandleScope scope(isolate); 5992 ASSERT(args.length() == 1); 5993 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5994 5995 if (obj->HasNamedInterceptor()) { 5996 Handle<JSObject> result; 5997 if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) { 5998 return *result; 5999 } 6000 } 6001 return isolate->heap()->undefined_value(); 6002 } 6003 6004 6005 // Return element names from indexed interceptor. 6006 // args[0]: object 6007 RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) { 6008 HandleScope scope(isolate); 6009 ASSERT(args.length() == 1); 6010 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 6011 6012 if (obj->HasIndexedInterceptor()) { 6013 Handle<JSObject> result; 6014 if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) { 6015 return *result; 6016 } 6017 } 6018 return isolate->heap()->undefined_value(); 6019 } 6020 6021 6022 RUNTIME_FUNCTION(Runtime_OwnKeys) { 6023 HandleScope scope(isolate); 6024 ASSERT(args.length() == 1); 6025 CONVERT_ARG_CHECKED(JSObject, raw_object, 0); 6026 Handle<JSObject> object(raw_object); 6027 6028 if (object->IsJSGlobalProxy()) { 6029 // Do access checks before going to the global object. 6030 if (object->IsAccessCheckNeeded() && 6031 !isolate->MayNamedAccess( 6032 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) { 6033 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS); 6034 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 6035 return *isolate->factory()->NewJSArray(0); 6036 } 6037 6038 Handle<Object> proto(object->GetPrototype(), isolate); 6039 // If proxy is detached we simply return an empty array. 6040 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); 6041 object = Handle<JSObject>::cast(proto); 6042 } 6043 6044 Handle<FixedArray> contents; 6045 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6046 isolate, contents, 6047 JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY)); 6048 6049 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 6050 // property array and since the result is mutable we have to create 6051 // a fresh clone on each invocation. 6052 int length = contents->length(); 6053 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); 6054 for (int i = 0; i < length; i++) { 6055 Object* entry = contents->get(i); 6056 if (entry->IsString()) { 6057 copy->set(i, entry); 6058 } else { 6059 ASSERT(entry->IsNumber()); 6060 HandleScope scope(isolate); 6061 Handle<Object> entry_handle(entry, isolate); 6062 Handle<Object> entry_str = 6063 isolate->factory()->NumberToString(entry_handle); 6064 copy->set(i, *entry_str); 6065 } 6066 } 6067 return *isolate->factory()->NewJSArrayWithElements(copy); 6068 } 6069 6070 6071 RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) { 6072 SealHandleScope shs(isolate); 6073 ASSERT(args.length() == 1); 6074 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0); 6075 6076 // Compute the frame holding the arguments. 6077 JavaScriptFrameIterator it(isolate); 6078 it.AdvanceToArgumentsFrame(); 6079 JavaScriptFrame* frame = it.frame(); 6080 6081 // Get the actual number of provided arguments. 6082 const uint32_t n = frame->ComputeParametersCount(); 6083 6084 // Try to convert the key to an index. If successful and within 6085 // index return the the argument from the frame. 6086 uint32_t index; 6087 if (raw_key->ToArrayIndex(&index) && index < n) { 6088 return frame->GetParameter(index); 6089 } 6090 6091 HandleScope scope(isolate); 6092 if (raw_key->IsSymbol()) { 6093 // Lookup in the initial Object.prototype object. 6094 Handle<Object> result; 6095 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6096 isolate, result, 6097 Object::GetProperty(isolate->initial_object_prototype(), 6098 Handle<Symbol>::cast(raw_key))); 6099 return *result; 6100 } 6101 6102 // Convert the key to a string. 6103 Handle<Object> converted; 6104 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6105 isolate, converted, Execution::ToString(isolate, raw_key)); 6106 Handle<String> key = Handle<String>::cast(converted); 6107 6108 // Try to convert the string key into an array index. 6109 if (key->AsArrayIndex(&index)) { 6110 if (index < n) { 6111 return frame->GetParameter(index); 6112 } else { 6113 Handle<Object> initial_prototype(isolate->initial_object_prototype()); 6114 Handle<Object> result; 6115 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6116 isolate, result, 6117 Object::GetElement(isolate, initial_prototype, index)); 6118 return *result; 6119 } 6120 } 6121 6122 // Handle special arguments properties. 6123 if (String::Equals(isolate->factory()->length_string(), key)) { 6124 return Smi::FromInt(n); 6125 } 6126 if (String::Equals(isolate->factory()->callee_string(), key)) { 6127 JSFunction* function = frame->function(); 6128 if (function->shared()->strict_mode() == STRICT) { 6129 return isolate->Throw(*isolate->factory()->NewTypeError( 6130 "strict_arguments_callee", HandleVector<Object>(NULL, 0))); 6131 } 6132 return function; 6133 } 6134 6135 // Lookup in the initial Object.prototype object. 6136 Handle<Object> result; 6137 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6138 isolate, result, 6139 Object::GetProperty(isolate->initial_object_prototype(), key)); 6140 return *result; 6141 } 6142 6143 6144 RUNTIME_FUNCTION(Runtime_ToFastProperties) { 6145 HandleScope scope(isolate); 6146 ASSERT(args.length() == 1); 6147 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 6148 if (object->IsJSObject() && !object->IsGlobalObject()) { 6149 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0); 6150 } 6151 return *object; 6152 } 6153 6154 6155 RUNTIME_FUNCTION(Runtime_ToBool) { 6156 SealHandleScope shs(isolate); 6157 ASSERT(args.length() == 1); 6158 CONVERT_ARG_CHECKED(Object, object, 0); 6159 6160 return isolate->heap()->ToBoolean(object->BooleanValue()); 6161 } 6162 6163 6164 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 6165 // Possible optimizations: put the type string into the oddballs. 6166 RUNTIME_FUNCTION(Runtime_Typeof) { 6167 SealHandleScope shs(isolate); 6168 ASSERT(args.length() == 1); 6169 CONVERT_ARG_CHECKED(Object, obj, 0); 6170 if (obj->IsNumber()) return isolate->heap()->number_string(); 6171 HeapObject* heap_obj = HeapObject::cast(obj); 6172 6173 // typeof an undetectable object is 'undefined' 6174 if (heap_obj->map()->is_undetectable()) { 6175 return isolate->heap()->undefined_string(); 6176 } 6177 6178 InstanceType instance_type = heap_obj->map()->instance_type(); 6179 if (instance_type < FIRST_NONSTRING_TYPE) { 6180 return isolate->heap()->string_string(); 6181 } 6182 6183 switch (instance_type) { 6184 case ODDBALL_TYPE: 6185 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 6186 return isolate->heap()->boolean_string(); 6187 } 6188 if (heap_obj->IsNull()) { 6189 return FLAG_harmony_typeof 6190 ? isolate->heap()->null_string() 6191 : isolate->heap()->object_string(); 6192 } 6193 ASSERT(heap_obj->IsUndefined()); 6194 return isolate->heap()->undefined_string(); 6195 case SYMBOL_TYPE: 6196 return isolate->heap()->symbol_string(); 6197 case JS_FUNCTION_TYPE: 6198 case JS_FUNCTION_PROXY_TYPE: 6199 return isolate->heap()->function_string(); 6200 default: 6201 // For any kind of object not handled above, the spec rule for 6202 // host objects gives that it is okay to return "object" 6203 return isolate->heap()->object_string(); 6204 } 6205 } 6206 6207 6208 static bool AreDigits(const uint8_t*s, int from, int to) { 6209 for (int i = from; i < to; i++) { 6210 if (s[i] < '0' || s[i] > '9') return false; 6211 } 6212 6213 return true; 6214 } 6215 6216 6217 static int ParseDecimalInteger(const uint8_t*s, int from, int to) { 6218 ASSERT(to - from < 10); // Overflow is not possible. 6219 ASSERT(from < to); 6220 int d = s[from] - '0'; 6221 6222 for (int i = from + 1; i < to; i++) { 6223 d = 10 * d + (s[i] - '0'); 6224 } 6225 6226 return d; 6227 } 6228 6229 6230 RUNTIME_FUNCTION(Runtime_StringToNumber) { 6231 HandleScope handle_scope(isolate); 6232 ASSERT(args.length() == 1); 6233 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6234 subject = String::Flatten(subject); 6235 6236 // Fast case: short integer or some sorts of junk values. 6237 if (subject->IsSeqOneByteString()) { 6238 int len = subject->length(); 6239 if (len == 0) return Smi::FromInt(0); 6240 6241 DisallowHeapAllocation no_gc; 6242 uint8_t const* data = Handle<SeqOneByteString>::cast(subject)->GetChars(); 6243 bool minus = (data[0] == '-'); 6244 int start_pos = (minus ? 1 : 0); 6245 6246 if (start_pos == len) { 6247 return isolate->heap()->nan_value(); 6248 } else if (data[start_pos] > '9') { 6249 // Fast check for a junk value. A valid string may start from a 6250 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit 6251 // or the 'I' character ('Infinity'). All of that have codes not greater 6252 // than '9' except 'I' and . 6253 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 6254 return isolate->heap()->nan_value(); 6255 } 6256 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 6257 // The maximal/minimal smi has 10 digits. If the string has less digits 6258 // we know it will fit into the smi-data type. 6259 int d = ParseDecimalInteger(data, start_pos, len); 6260 if (minus) { 6261 if (d == 0) return isolate->heap()->minus_zero_value(); 6262 d = -d; 6263 } else if (!subject->HasHashCode() && 6264 len <= String::kMaxArrayIndexSize && 6265 (len == 1 || data[0] != '0')) { 6266 // String hash is not calculated yet but all the data are present. 6267 // Update the hash field to speed up sequential convertions. 6268 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 6269 #ifdef DEBUG 6270 subject->Hash(); // Force hash calculation. 6271 ASSERT_EQ(static_cast<int>(subject->hash_field()), 6272 static_cast<int>(hash)); 6273 #endif 6274 subject->set_hash_field(hash); 6275 } 6276 return Smi::FromInt(d); 6277 } 6278 } 6279 6280 // Slower case. 6281 int flags = ALLOW_HEX; 6282 if (FLAG_harmony_numeric_literals) { 6283 // The current spec draft has not updated "ToNumber Applied to the String 6284 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 6285 flags |= ALLOW_OCTAL | ALLOW_BINARY; 6286 } 6287 6288 return *isolate->factory()->NewNumber(StringToDouble( 6289 isolate->unicode_cache(), *subject, flags)); 6290 } 6291 6292 6293 RUNTIME_FUNCTION(Runtime_NewString) { 6294 HandleScope scope(isolate); 6295 ASSERT(args.length() == 2); 6296 CONVERT_SMI_ARG_CHECKED(length, 0); 6297 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); 6298 if (length == 0) return isolate->heap()->empty_string(); 6299 Handle<String> result; 6300 if (is_one_byte) { 6301 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6302 isolate, result, isolate->factory()->NewRawOneByteString(length)); 6303 } else { 6304 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6305 isolate, result, isolate->factory()->NewRawTwoByteString(length)); 6306 } 6307 return *result; 6308 } 6309 6310 6311 RUNTIME_FUNCTION(Runtime_TruncateString) { 6312 HandleScope scope(isolate); 6313 ASSERT(args.length() == 2); 6314 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); 6315 CONVERT_SMI_ARG_CHECKED(new_length, 1); 6316 RUNTIME_ASSERT(new_length >= 0); 6317 return *SeqString::Truncate(string, new_length); 6318 } 6319 6320 6321 RUNTIME_FUNCTION(Runtime_URIEscape) { 6322 HandleScope scope(isolate); 6323 ASSERT(args.length() == 1); 6324 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6325 Handle<String> string = String::Flatten(source); 6326 ASSERT(string->IsFlat()); 6327 Handle<String> result; 6328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6329 isolate, result, 6330 string->IsOneByteRepresentationUnderneath() 6331 ? URIEscape::Escape<uint8_t>(isolate, source) 6332 : URIEscape::Escape<uc16>(isolate, source)); 6333 return *result; 6334 } 6335 6336 6337 RUNTIME_FUNCTION(Runtime_URIUnescape) { 6338 HandleScope scope(isolate); 6339 ASSERT(args.length() == 1); 6340 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6341 Handle<String> string = String::Flatten(source); 6342 ASSERT(string->IsFlat()); 6343 Handle<String> result; 6344 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6345 isolate, result, 6346 string->IsOneByteRepresentationUnderneath() 6347 ? URIUnescape::Unescape<uint8_t>(isolate, source) 6348 : URIUnescape::Unescape<uc16>(isolate, source)); 6349 return *result; 6350 } 6351 6352 6353 RUNTIME_FUNCTION(Runtime_QuoteJSONString) { 6354 HandleScope scope(isolate); 6355 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 6356 ASSERT(args.length() == 1); 6357 Handle<Object> result; 6358 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6359 isolate, result, BasicJsonStringifier::StringifyString(isolate, string)); 6360 return *result; 6361 } 6362 6363 6364 RUNTIME_FUNCTION(Runtime_BasicJSONStringify) { 6365 HandleScope scope(isolate); 6366 ASSERT(args.length() == 1); 6367 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 6368 BasicJsonStringifier stringifier(isolate); 6369 Handle<Object> result; 6370 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6371 isolate, result, stringifier.Stringify(object)); 6372 return *result; 6373 } 6374 6375 6376 RUNTIME_FUNCTION(Runtime_StringParseInt) { 6377 HandleScope handle_scope(isolate); 6378 ASSERT(args.length() == 2); 6379 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6380 CONVERT_NUMBER_CHECKED(int, radix, Int32, args[1]); 6381 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 6382 6383 subject = String::Flatten(subject); 6384 double value; 6385 6386 { DisallowHeapAllocation no_gc; 6387 String::FlatContent flat = subject->GetFlatContent(); 6388 6389 // ECMA-262 section 15.1.2.3, empty string is NaN 6390 if (flat.IsAscii()) { 6391 value = StringToInt( 6392 isolate->unicode_cache(), flat.ToOneByteVector(), radix); 6393 } else { 6394 value = StringToInt( 6395 isolate->unicode_cache(), flat.ToUC16Vector(), radix); 6396 } 6397 } 6398 6399 return *isolate->factory()->NewNumber(value); 6400 } 6401 6402 6403 RUNTIME_FUNCTION(Runtime_StringParseFloat) { 6404 HandleScope shs(isolate); 6405 ASSERT(args.length() == 1); 6406 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6407 6408 subject = String::Flatten(subject); 6409 double value = StringToDouble( 6410 isolate->unicode_cache(), *subject, ALLOW_TRAILING_JUNK, OS::nan_value()); 6411 6412 return *isolate->factory()->NewNumber(value); 6413 } 6414 6415 6416 static inline bool ToUpperOverflows(uc32 character) { 6417 // y with umlauts and the micro sign are the only characters that stop 6418 // fitting into one-byte when converting to uppercase. 6419 static const uc32 yuml_code = 0xff; 6420 static const uc32 micro_code = 0xb5; 6421 return (character == yuml_code || character == micro_code); 6422 } 6423 6424 6425 template <class Converter> 6426 MUST_USE_RESULT static Object* ConvertCaseHelper( 6427 Isolate* isolate, 6428 String* string, 6429 SeqString* result, 6430 int result_length, 6431 unibrow::Mapping<Converter, 128>* mapping) { 6432 DisallowHeapAllocation no_gc; 6433 // We try this twice, once with the assumption that the result is no longer 6434 // than the input and, if that assumption breaks, again with the exact 6435 // length. This may not be pretty, but it is nicer than what was here before 6436 // and I hereby claim my vaffel-is. 6437 // 6438 // NOTE: This assumes that the upper/lower case of an ASCII 6439 // character is also ASCII. This is currently the case, but it 6440 // might break in the future if we implement more context and locale 6441 // dependent upper/lower conversions. 6442 bool has_changed_character = false; 6443 6444 // Convert all characters to upper case, assuming that they will fit 6445 // in the buffer 6446 Access<ConsStringIteratorOp> op( 6447 isolate->runtime_state()->string_iterator()); 6448 StringCharacterStream stream(string, op.value()); 6449 unibrow::uchar chars[Converter::kMaxWidth]; 6450 // We can assume that the string is not empty 6451 uc32 current = stream.GetNext(); 6452 bool ignore_overflow = Converter::kIsToLower || result->IsSeqTwoByteString(); 6453 for (int i = 0; i < result_length;) { 6454 bool has_next = stream.HasMore(); 6455 uc32 next = has_next ? stream.GetNext() : 0; 6456 int char_length = mapping->get(current, next, chars); 6457 if (char_length == 0) { 6458 // The case conversion of this character is the character itself. 6459 result->Set(i, current); 6460 i++; 6461 } else if (char_length == 1 && 6462 (ignore_overflow || !ToUpperOverflows(current))) { 6463 // Common case: converting the letter resulted in one character. 6464 ASSERT(static_cast<uc32>(chars[0]) != current); 6465 result->Set(i, chars[0]); 6466 has_changed_character = true; 6467 i++; 6468 } else if (result_length == string->length()) { 6469 bool overflows = ToUpperOverflows(current); 6470 // We've assumed that the result would be as long as the 6471 // input but here is a character that converts to several 6472 // characters. No matter, we calculate the exact length 6473 // of the result and try the whole thing again. 6474 // 6475 // Note that this leaves room for optimization. We could just 6476 // memcpy what we already have to the result string. Also, 6477 // the result string is the last object allocated we could 6478 // "realloc" it and probably, in the vast majority of cases, 6479 // extend the existing string to be able to hold the full 6480 // result. 6481 int next_length = 0; 6482 if (has_next) { 6483 next_length = mapping->get(next, 0, chars); 6484 if (next_length == 0) next_length = 1; 6485 } 6486 int current_length = i + char_length + next_length; 6487 while (stream.HasMore()) { 6488 current = stream.GetNext(); 6489 overflows |= ToUpperOverflows(current); 6490 // NOTE: we use 0 as the next character here because, while 6491 // the next character may affect what a character converts to, 6492 // it does not in any case affect the length of what it convert 6493 // to. 6494 int char_length = mapping->get(current, 0, chars); 6495 if (char_length == 0) char_length = 1; 6496 current_length += char_length; 6497 if (current_length > String::kMaxLength) { 6498 AllowHeapAllocation allocate_error_and_return; 6499 return isolate->ThrowInvalidStringLength(); 6500 } 6501 } 6502 // Try again with the real length. Return signed if we need 6503 // to allocate a two-byte string for to uppercase. 6504 return (overflows && !ignore_overflow) ? Smi::FromInt(-current_length) 6505 : Smi::FromInt(current_length); 6506 } else { 6507 for (int j = 0; j < char_length; j++) { 6508 result->Set(i, chars[j]); 6509 i++; 6510 } 6511 has_changed_character = true; 6512 } 6513 current = next; 6514 } 6515 if (has_changed_character) { 6516 return result; 6517 } else { 6518 // If we didn't actually change anything in doing the conversion 6519 // we simple return the result and let the converted string 6520 // become garbage; there is no reason to keep two identical strings 6521 // alive. 6522 return string; 6523 } 6524 } 6525 6526 6527 namespace { 6528 6529 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; 6530 static const uintptr_t kAsciiMask = kOneInEveryByte << 7; 6531 6532 // Given a word and two range boundaries returns a word with high bit 6533 // set in every byte iff the corresponding input byte was strictly in 6534 // the range (m, n). All the other bits in the result are cleared. 6535 // This function is only useful when it can be inlined and the 6536 // boundaries are statically known. 6537 // Requires: all bytes in the input word and the boundaries must be 6538 // ASCII (less than 0x7F). 6539 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { 6540 // Use strict inequalities since in edge cases the function could be 6541 // further simplified. 6542 ASSERT(0 < m && m < n); 6543 // Has high bit set in every w byte less than n. 6544 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; 6545 // Has high bit set in every w byte greater than m. 6546 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); 6547 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); 6548 } 6549 6550 6551 #ifdef DEBUG 6552 static bool CheckFastAsciiConvert(char* dst, 6553 const char* src, 6554 int length, 6555 bool changed, 6556 bool is_to_lower) { 6557 bool expected_changed = false; 6558 for (int i = 0; i < length; i++) { 6559 if (dst[i] == src[i]) continue; 6560 expected_changed = true; 6561 if (is_to_lower) { 6562 ASSERT('A' <= src[i] && src[i] <= 'Z'); 6563 ASSERT(dst[i] == src[i] + ('a' - 'A')); 6564 } else { 6565 ASSERT('a' <= src[i] && src[i] <= 'z'); 6566 ASSERT(dst[i] == src[i] - ('a' - 'A')); 6567 } 6568 } 6569 return (expected_changed == changed); 6570 } 6571 #endif 6572 6573 6574 template<class Converter> 6575 static bool FastAsciiConvert(char* dst, 6576 const char* src, 6577 int length, 6578 bool* changed_out) { 6579 #ifdef DEBUG 6580 char* saved_dst = dst; 6581 const char* saved_src = src; 6582 #endif 6583 DisallowHeapAllocation no_gc; 6584 // We rely on the distance between upper and lower case letters 6585 // being a known power of 2. 6586 ASSERT('a' - 'A' == (1 << 5)); 6587 // Boundaries for the range of input characters than require conversion. 6588 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; 6589 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; 6590 bool changed = false; 6591 uintptr_t or_acc = 0; 6592 const char* const limit = src + length; 6593 #ifdef V8_HOST_CAN_READ_UNALIGNED 6594 // Process the prefix of the input that requires no conversion one 6595 // (machine) word at a time. 6596 while (src <= limit - sizeof(uintptr_t)) { 6597 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); 6598 or_acc |= w; 6599 if (AsciiRangeMask(w, lo, hi) != 0) { 6600 changed = true; 6601 break; 6602 } 6603 *reinterpret_cast<uintptr_t*>(dst) = w; 6604 src += sizeof(uintptr_t); 6605 dst += sizeof(uintptr_t); 6606 } 6607 // Process the remainder of the input performing conversion when 6608 // required one word at a time. 6609 while (src <= limit - sizeof(uintptr_t)) { 6610 const uintptr_t w = *reinterpret_cast<const uintptr_t*>(src); 6611 or_acc |= w; 6612 uintptr_t m = AsciiRangeMask(w, lo, hi); 6613 // The mask has high (7th) bit set in every byte that needs 6614 // conversion and we know that the distance between cases is 6615 // 1 << 5. 6616 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); 6617 src += sizeof(uintptr_t); 6618 dst += sizeof(uintptr_t); 6619 } 6620 #endif 6621 // Process the last few bytes of the input (or the whole input if 6622 // unaligned access is not supported). 6623 while (src < limit) { 6624 char c = *src; 6625 or_acc |= c; 6626 if (lo < c && c < hi) { 6627 c ^= (1 << 5); 6628 changed = true; 6629 } 6630 *dst = c; 6631 ++src; 6632 ++dst; 6633 } 6634 if ((or_acc & kAsciiMask) != 0) { 6635 return false; 6636 } 6637 6638 ASSERT(CheckFastAsciiConvert( 6639 saved_dst, saved_src, length, changed, Converter::kIsToLower)); 6640 6641 *changed_out = changed; 6642 return true; 6643 } 6644 6645 } // namespace 6646 6647 6648 template <class Converter> 6649 MUST_USE_RESULT static Object* ConvertCase( 6650 Handle<String> s, 6651 Isolate* isolate, 6652 unibrow::Mapping<Converter, 128>* mapping) { 6653 s = String::Flatten(s); 6654 int length = s->length(); 6655 // Assume that the string is not empty; we need this assumption later 6656 if (length == 0) return *s; 6657 6658 // Simpler handling of ASCII strings. 6659 // 6660 // NOTE: This assumes that the upper/lower case of an ASCII 6661 // character is also ASCII. This is currently the case, but it 6662 // might break in the future if we implement more context and locale 6663 // dependent upper/lower conversions. 6664 if (s->IsOneByteRepresentationUnderneath()) { 6665 // Same length as input. 6666 Handle<SeqOneByteString> result = 6667 isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); 6668 DisallowHeapAllocation no_gc; 6669 String::FlatContent flat_content = s->GetFlatContent(); 6670 ASSERT(flat_content.IsFlat()); 6671 bool has_changed_character = false; 6672 bool is_ascii = FastAsciiConvert<Converter>( 6673 reinterpret_cast<char*>(result->GetChars()), 6674 reinterpret_cast<const char*>(flat_content.ToOneByteVector().start()), 6675 length, 6676 &has_changed_character); 6677 // If not ASCII, we discard the result and take the 2 byte path. 6678 if (is_ascii) return has_changed_character ? *result : *s; 6679 } 6680 6681 Handle<SeqString> result; // Same length as input. 6682 if (s->IsOneByteRepresentation()) { 6683 result = isolate->factory()->NewRawOneByteString(length).ToHandleChecked(); 6684 } else { 6685 result = isolate->factory()->NewRawTwoByteString(length).ToHandleChecked(); 6686 } 6687 6688 Object* answer = ConvertCaseHelper(isolate, *s, *result, length, mapping); 6689 if (answer->IsException() || answer->IsString()) return answer; 6690 6691 ASSERT(answer->IsSmi()); 6692 length = Smi::cast(answer)->value(); 6693 if (s->IsOneByteRepresentation() && length > 0) { 6694 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6695 isolate, result, isolate->factory()->NewRawOneByteString(length)); 6696 } else { 6697 if (length < 0) length = -length; 6698 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 6699 isolate, result, isolate->factory()->NewRawTwoByteString(length)); 6700 } 6701 return ConvertCaseHelper(isolate, *s, *result, length, mapping); 6702 } 6703 6704 6705 RUNTIME_FUNCTION(Runtime_StringToLowerCase) { 6706 HandleScope scope(isolate); 6707 ASSERT(args.length() == 1); 6708 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6709 return ConvertCase( 6710 s, isolate, isolate->runtime_state()->to_lower_mapping()); 6711 } 6712 6713 6714 RUNTIME_FUNCTION(Runtime_StringToUpperCase) { 6715 HandleScope scope(isolate); 6716 ASSERT(args.length() == 1); 6717 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6718 return ConvertCase( 6719 s, isolate, isolate->runtime_state()->to_upper_mapping()); 6720 } 6721 6722 6723 RUNTIME_FUNCTION(Runtime_StringTrim) { 6724 HandleScope scope(isolate); 6725 ASSERT(args.length() == 3); 6726 6727 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 6728 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); 6729 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); 6730 6731 string = String::Flatten(string); 6732 int length = string->length(); 6733 6734 int left = 0; 6735 UnicodeCache* unicode_cache = isolate->unicode_cache(); 6736 if (trimLeft) { 6737 while (left < length && 6738 unicode_cache->IsWhiteSpaceOrLineTerminator(string->Get(left))) { 6739 left++; 6740 } 6741 } 6742 6743 int right = length; 6744 if (trimRight) { 6745 while (right > left && 6746 unicode_cache->IsWhiteSpaceOrLineTerminator( 6747 string->Get(right - 1))) { 6748 right--; 6749 } 6750 } 6751 6752 return *isolate->factory()->NewSubString(string, left, right); 6753 } 6754 6755 6756 RUNTIME_FUNCTION(Runtime_StringSplit) { 6757 HandleScope handle_scope(isolate); 6758 ASSERT(args.length() == 3); 6759 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6760 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 6761 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); 6762 RUNTIME_ASSERT(limit > 0); 6763 6764 int subject_length = subject->length(); 6765 int pattern_length = pattern->length(); 6766 RUNTIME_ASSERT(pattern_length > 0); 6767 6768 if (limit == 0xffffffffu) { 6769 Handle<Object> cached_answer( 6770 RegExpResultsCache::Lookup(isolate->heap(), 6771 *subject, 6772 *pattern, 6773 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS), 6774 isolate); 6775 if (*cached_answer != Smi::FromInt(0)) { 6776 // The cache FixedArray is a COW-array and can therefore be reused. 6777 Handle<JSArray> result = 6778 isolate->factory()->NewJSArrayWithElements( 6779 Handle<FixedArray>::cast(cached_answer)); 6780 return *result; 6781 } 6782 } 6783 6784 // The limit can be very large (0xffffffffu), but since the pattern 6785 // isn't empty, we can never create more parts than ~half the length 6786 // of the subject. 6787 6788 subject = String::Flatten(subject); 6789 pattern = String::Flatten(pattern); 6790 6791 static const int kMaxInitialListCapacity = 16; 6792 6793 ZoneScope zone_scope(isolate->runtime_zone()); 6794 6795 // Find (up to limit) indices of separator and end-of-string in subject 6796 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); 6797 ZoneList<int> indices(initial_capacity, zone_scope.zone()); 6798 6799 FindStringIndicesDispatch(isolate, *subject, *pattern, 6800 &indices, limit, zone_scope.zone()); 6801 6802 if (static_cast<uint32_t>(indices.length()) < limit) { 6803 indices.Add(subject_length, zone_scope.zone()); 6804 } 6805 6806 // The list indices now contains the end of each part to create. 6807 6808 // Create JSArray of substrings separated by separator. 6809 int part_count = indices.length(); 6810 6811 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); 6812 JSObject::EnsureCanContainHeapObjectElements(result); 6813 result->set_length(Smi::FromInt(part_count)); 6814 6815 ASSERT(result->HasFastObjectElements()); 6816 6817 if (part_count == 1 && indices.at(0) == subject_length) { 6818 FixedArray::cast(result->elements())->set(0, *subject); 6819 return *result; 6820 } 6821 6822 Handle<FixedArray> elements(FixedArray::cast(result->elements())); 6823 int part_start = 0; 6824 for (int i = 0; i < part_count; i++) { 6825 HandleScope local_loop_handle(isolate); 6826 int part_end = indices.at(i); 6827 Handle<String> substring = 6828 isolate->factory()->NewProperSubString(subject, part_start, part_end); 6829 elements->set(i, *substring); 6830 part_start = part_end + pattern_length; 6831 } 6832 6833 if (limit == 0xffffffffu) { 6834 if (result->HasFastObjectElements()) { 6835 RegExpResultsCache::Enter(isolate, 6836 subject, 6837 pattern, 6838 elements, 6839 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); 6840 } 6841 } 6842 6843 return *result; 6844 } 6845 6846 6847 // Copies ASCII characters to the given fixed array looking up 6848 // one-char strings in the cache. Gives up on the first char that is 6849 // not in the cache and fills the remainder with smi zeros. Returns 6850 // the length of the successfully copied prefix. 6851 static int CopyCachedAsciiCharsToArray(Heap* heap, 6852 const uint8_t* chars, 6853 FixedArray* elements, 6854 int length) { 6855 DisallowHeapAllocation no_gc; 6856 FixedArray* ascii_cache = heap->single_character_string_cache(); 6857 Object* undefined = heap->undefined_value(); 6858 int i; 6859 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 6860 for (i = 0; i < length; ++i) { 6861 Object* value = ascii_cache->get(chars[i]); 6862 if (value == undefined) break; 6863 elements->set(i, value, mode); 6864 } 6865 if (i < length) { 6866 ASSERT(Smi::FromInt(0) == 0); 6867 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 6868 } 6869 #ifdef DEBUG 6870 for (int j = 0; j < length; ++j) { 6871 Object* element = elements->get(j); 6872 ASSERT(element == Smi::FromInt(0) || 6873 (element->IsString() && String::cast(element)->LooksValid())); 6874 } 6875 #endif 6876 return i; 6877 } 6878 6879 6880 // Converts a String to JSArray. 6881 // For example, "foo" => ["f", "o", "o"]. 6882 RUNTIME_FUNCTION(Runtime_StringToArray) { 6883 HandleScope scope(isolate); 6884 ASSERT(args.length() == 2); 6885 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6886 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 6887 6888 s = String::Flatten(s); 6889 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); 6890 6891 Handle<FixedArray> elements; 6892 int position = 0; 6893 if (s->IsFlat() && s->IsOneByteRepresentation()) { 6894 // Try using cached chars where possible. 6895 elements = isolate->factory()->NewUninitializedFixedArray(length); 6896 6897 DisallowHeapAllocation no_gc; 6898 String::FlatContent content = s->GetFlatContent(); 6899 if (content.IsAscii()) { 6900 Vector<const uint8_t> chars = content.ToOneByteVector(); 6901 // Note, this will initialize all elements (not only the prefix) 6902 // to prevent GC from seeing partially initialized array. 6903 position = CopyCachedAsciiCharsToArray(isolate->heap(), 6904 chars.start(), 6905 *elements, 6906 length); 6907 } else { 6908 MemsetPointer(elements->data_start(), 6909 isolate->heap()->undefined_value(), 6910 length); 6911 } 6912 } else { 6913 elements = isolate->factory()->NewFixedArray(length); 6914 } 6915 for (int i = position; i < length; ++i) { 6916 Handle<Object> str = 6917 isolate->factory()->LookupSingleCharacterStringFromCode(s->Get(i)); 6918 elements->set(i, *str); 6919 } 6920 6921 #ifdef DEBUG 6922 for (int i = 0; i < length; ++i) { 6923 ASSERT(String::cast(elements->get(i))->length() == 1); 6924 } 6925 #endif 6926 6927 return *isolate->factory()->NewJSArrayWithElements(elements); 6928 } 6929 6930 6931 RUNTIME_FUNCTION(Runtime_NewStringWrapper) { 6932 HandleScope scope(isolate); 6933 ASSERT(args.length() == 1); 6934 CONVERT_ARG_HANDLE_CHECKED(String, value, 0); 6935 return *Object::ToObject(isolate, value).ToHandleChecked(); 6936 } 6937 6938 6939 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { 6940 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 6941 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); 6942 return char_length == 0; 6943 } 6944 6945 6946 RUNTIME_FUNCTION(RuntimeHidden_NumberToString) { 6947 HandleScope scope(isolate); 6948 ASSERT(args.length() == 1); 6949 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); 6950 6951 return *isolate->factory()->NumberToString(number); 6952 } 6953 6954 6955 RUNTIME_FUNCTION(RuntimeHidden_NumberToStringSkipCache) { 6956 HandleScope scope(isolate); 6957 ASSERT(args.length() == 1); 6958 CONVERT_NUMBER_ARG_HANDLE_CHECKED(number, 0); 6959 6960 return *isolate->factory()->NumberToString(number, false); 6961 } 6962 6963 6964 RUNTIME_FUNCTION(Runtime_NumberToInteger) { 6965 HandleScope scope(isolate); 6966 ASSERT(args.length() == 1); 6967 6968 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6969 return *isolate->factory()->NewNumber(DoubleToInteger(number)); 6970 } 6971 6972 6973 RUNTIME_FUNCTION(Runtime_NumberToIntegerMapMinusZero) { 6974 HandleScope scope(isolate); 6975 ASSERT(args.length() == 1); 6976 6977 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6978 double double_value = DoubleToInteger(number); 6979 // Map both -0 and +0 to +0. 6980 if (double_value == 0) double_value = 0; 6981 6982 return *isolate->factory()->NewNumber(double_value); 6983 } 6984 6985 6986 RUNTIME_FUNCTION(Runtime_NumberToJSUint32) { 6987 HandleScope scope(isolate); 6988 ASSERT(args.length() == 1); 6989 6990 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); 6991 return *isolate->factory()->NewNumberFromUint(number); 6992 } 6993 6994 6995 RUNTIME_FUNCTION(Runtime_NumberToJSInt32) { 6996 HandleScope scope(isolate); 6997 ASSERT(args.length() == 1); 6998 6999 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 7000 return *isolate->factory()->NewNumberFromInt(DoubleToInt32(number)); 7001 } 7002 7003 7004 // Converts a Number to a Smi, if possible. Returns NaN if the number is not 7005 // a small integer. 7006 RUNTIME_FUNCTION(RuntimeHidden_NumberToSmi) { 7007 SealHandleScope shs(isolate); 7008 ASSERT(args.length() == 1); 7009 CONVERT_ARG_CHECKED(Object, obj, 0); 7010 if (obj->IsSmi()) { 7011 return obj; 7012 } 7013 if (obj->IsHeapNumber()) { 7014 double value = HeapNumber::cast(obj)->value(); 7015 int int_value = FastD2I(value); 7016 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 7017 return Smi::FromInt(int_value); 7018 } 7019 } 7020 return isolate->heap()->nan_value(); 7021 } 7022 7023 7024 RUNTIME_FUNCTION(RuntimeHidden_AllocateHeapNumber) { 7025 HandleScope scope(isolate); 7026 ASSERT(args.length() == 0); 7027 return *isolate->factory()->NewHeapNumber(0); 7028 } 7029 7030 7031 RUNTIME_FUNCTION(Runtime_NumberAdd) { 7032 HandleScope scope(isolate); 7033 ASSERT(args.length() == 2); 7034 7035 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7036 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7037 return *isolate->factory()->NewNumber(x + y); 7038 } 7039 7040 7041 RUNTIME_FUNCTION(Runtime_NumberSub) { 7042 HandleScope scope(isolate); 7043 ASSERT(args.length() == 2); 7044 7045 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7046 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7047 return *isolate->factory()->NewNumber(x - y); 7048 } 7049 7050 7051 RUNTIME_FUNCTION(Runtime_NumberMul) { 7052 HandleScope scope(isolate); 7053 ASSERT(args.length() == 2); 7054 7055 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7056 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7057 return *isolate->factory()->NewNumber(x * y); 7058 } 7059 7060 7061 RUNTIME_FUNCTION(Runtime_NumberUnaryMinus) { 7062 HandleScope scope(isolate); 7063 ASSERT(args.length() == 1); 7064 7065 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7066 return *isolate->factory()->NewNumber(-x); 7067 } 7068 7069 7070 RUNTIME_FUNCTION(Runtime_NumberDiv) { 7071 HandleScope scope(isolate); 7072 ASSERT(args.length() == 2); 7073 7074 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7075 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7076 return *isolate->factory()->NewNumber(x / y); 7077 } 7078 7079 7080 RUNTIME_FUNCTION(Runtime_NumberMod) { 7081 HandleScope scope(isolate); 7082 ASSERT(args.length() == 2); 7083 7084 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7085 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7086 return *isolate->factory()->NewNumber(modulo(x, y)); 7087 } 7088 7089 7090 RUNTIME_FUNCTION(Runtime_NumberImul) { 7091 HandleScope scope(isolate); 7092 ASSERT(args.length() == 2); 7093 7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7095 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7096 return *isolate->factory()->NewNumberFromInt(x * y); 7097 } 7098 7099 7100 RUNTIME_FUNCTION(RuntimeHidden_StringAdd) { 7101 HandleScope scope(isolate); 7102 ASSERT(args.length() == 2); 7103 CONVERT_ARG_HANDLE_CHECKED(String, str1, 0); 7104 CONVERT_ARG_HANDLE_CHECKED(String, str2, 1); 7105 isolate->counters()->string_add_runtime()->Increment(); 7106 Handle<String> result; 7107 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 7108 isolate, result, isolate->factory()->NewConsString(str1, str2)); 7109 return *result; 7110 } 7111 7112 7113 template <typename sinkchar> 7114 static inline void StringBuilderConcatHelper(String* special, 7115 sinkchar* sink, 7116 FixedArray* fixed_array, 7117 int array_length) { 7118 DisallowHeapAllocation no_gc; 7119 int position = 0; 7120 for (int i = 0; i < array_length; i++) { 7121 Object* element = fixed_array->get(i); 7122 if (element->IsSmi()) { 7123 // Smi encoding of position and length. 7124 int encoded_slice = Smi::cast(element)->value(); 7125 int pos; 7126 int len; 7127 if (encoded_slice > 0) { 7128 // Position and length encoded in one smi. 7129 pos = StringBuilderSubstringPosition::decode(encoded_slice); 7130 len = StringBuilderSubstringLength::decode(encoded_slice); 7131 } else { 7132 // Position and length encoded in two smis. 7133 Object* obj = fixed_array->get(++i); 7134 ASSERT(obj->IsSmi()); 7135 pos = Smi::cast(obj)->value(); 7136 len = -encoded_slice; 7137 } 7138 String::WriteToFlat(special, 7139 sink + position, 7140 pos, 7141 pos + len); 7142 position += len; 7143 } else { 7144 String* string = String::cast(element); 7145 int element_length = string->length(); 7146 String::WriteToFlat(string, sink + position, 0, element_length); 7147 position += element_length; 7148 } 7149 } 7150 } 7151 7152 7153 // Returns the result length of the concatenation. 7154 // On illegal argument, -1 is returned. 7155 static inline int StringBuilderConcatLength(int special_length, 7156 FixedArray* fixed_array, 7157 int array_length, 7158 bool* one_byte) { 7159 DisallowHeapAllocation no_gc; 7160 int position = 0; 7161 for (int i = 0; i < array_length; i++) { 7162 int increment = 0; 7163 Object* elt = fixed_array->get(i); 7164 if (elt->IsSmi()) { 7165 // Smi encoding of position and length. 7166 int smi_value = Smi::cast(elt)->value(); 7167 int pos; 7168 int len; 7169 if (smi_value > 0) { 7170 // Position and length encoded in one smi. 7171 pos = StringBuilderSubstringPosition::decode(smi_value); 7172 len = StringBuilderSubstringLength::decode(smi_value); 7173 } else { 7174 // Position and length encoded in two smis. 7175 len = -smi_value; 7176 // Get the position and check that it is a positive smi. 7177 i++; 7178 if (i >= array_length) return -1; 7179 Object* next_smi = fixed_array->get(i); 7180 if (!next_smi->IsSmi()) return -1; 7181 pos = Smi::cast(next_smi)->value(); 7182 if (pos < 0) return -1; 7183 } 7184 ASSERT(pos >= 0); 7185 ASSERT(len >= 0); 7186 if (pos > special_length || len > special_length - pos) return -1; 7187 increment = len; 7188 } else if (elt->IsString()) { 7189 String* element = String::cast(elt); 7190 int element_length = element->length(); 7191 increment = element_length; 7192 if (*one_byte && !element->HasOnlyOneByteChars()) { 7193 *one_byte = false; 7194 } 7195 } else { 7196 return -1; 7197 } 7198 if (increment > String::kMaxLength - position) { 7199 return kMaxInt; // Provoke throw on allocation. 7200 } 7201 position += increment; 7202 } 7203 return position; 7204 } 7205 7206 7207 RUNTIME_FUNCTION(Runtime_StringBuilderConcat) { 7208 HandleScope scope(isolate); 7209 ASSERT(args.length() == 3); 7210 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 7211 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); 7212 CONVERT_SMI_ARG_CHECKED(array_length, 1); 7213 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); 7214 7215 size_t actual_array_length = 0; 7216 RUNTIME_ASSERT( 7217 TryNumberToSize(isolate, array->length(), &actual_array_length)); 7218 RUNTIME_ASSERT(array_length >= 0); 7219 RUNTIME_ASSERT(static_cast<size_t>(array_length) <= actual_array_length); 7220 7221 // This assumption is used by the slice encoding in one or two smis. 7222 ASSERT(Smi::kMaxValue >= String::kMaxLength); 7223 7224 RUNTIME_ASSERT(array->HasFastElements()); 7225 JSObject::EnsureCanContainHeapObjectElements(array); 7226 7227 int special_length = special->length(); 7228 if (!array->HasFastObjectElements()) { 7229 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7230 } 7231 7232 int length; 7233 bool one_byte = special->HasOnlyOneByteChars(); 7234 7235 { DisallowHeapAllocation no_gc; 7236 FixedArray* fixed_array = FixedArray::cast(array->elements()); 7237 if (fixed_array->length() < array_length) { 7238 array_length = fixed_array->length(); 7239 } 7240 7241 if (array_length == 0) { 7242 return isolate->heap()->empty_string(); 7243 } else if (array_length == 1) { 7244 Object* first = fixed_array->get(0); 7245 if (first->IsString()) return first; 7246 } 7247 length = StringBuilderConcatLength( 7248 special_length, fixed_array, array_length, &one_byte); 7249 } 7250 7251 if (length == -1) { 7252 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7253 } 7254 7255 if (one_byte) { 7256 Handle<SeqOneByteString> answer; 7257 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 7258 isolate, answer, 7259 isolate->factory()->NewRawOneByteString(length)); 7260 StringBuilderConcatHelper(*special, 7261 answer->GetChars(), 7262 FixedArray::cast(array->elements()), 7263 array_length); 7264 return *answer; 7265 } else { 7266 Handle<SeqTwoByteString> answer; 7267 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 7268 isolate, answer, 7269 isolate->factory()->NewRawTwoByteString(length)); 7270 StringBuilderConcatHelper(*special, 7271 answer->GetChars(), 7272 FixedArray::cast(array->elements()), 7273 array_length); 7274 return *answer; 7275 } 7276 } 7277 7278 7279 RUNTIME_FUNCTION(Runtime_StringBuilderJoin) { 7280 HandleScope scope(isolate); 7281 ASSERT(args.length() == 3); 7282 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 7283 if (!args[1]->IsSmi()) return isolate->ThrowInvalidStringLength(); 7284 CONVERT_SMI_ARG_CHECKED(array_length, 1); 7285 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); 7286 RUNTIME_ASSERT(array->HasFastObjectElements()); 7287 RUNTIME_ASSERT(array_length >= 0); 7288 7289 Handle<FixedArray> fixed_array(FixedArray::cast(array->elements())); 7290 if (fixed_array->length() < array_length) { 7291 array_length = fixed_array->length(); 7292 } 7293 7294 if (array_length == 0) { 7295 return isolate->heap()->empty_string(); 7296 } else if (array_length == 1) { 7297 Object* first = fixed_array->get(0); 7298 RUNTIME_ASSERT(first->IsString()); 7299 return first; 7300 } 7301 7302 int separator_length = separator->length(); 7303 RUNTIME_ASSERT(separator_length > 0); 7304 int max_nof_separators = 7305 (String::kMaxLength + separator_length - 1) / separator_length; 7306 if (max_nof_separators < (array_length - 1)) { 7307 return isolate->ThrowInvalidStringLength(); 7308 } 7309 int length = (array_length - 1) * separator_length; 7310 for (int i = 0; i < array_length; i++) { 7311 Object* element_obj = fixed_array->get(i); 7312 RUNTIME_ASSERT(element_obj->IsString()); 7313 String* element = String::cast(element_obj); 7314 int increment = element->length(); 7315 if (increment > String::kMaxLength - length) { 7316 STATIC_ASSERT(String::kMaxLength < kMaxInt); 7317 length = kMaxInt; // Provoke exception; 7318 break; 7319 } 7320 length += increment; 7321 } 7322 7323 Handle<SeqTwoByteString> answer; 7324 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 7325 isolate, answer, 7326 isolate->factory()->NewRawTwoByteString(length)); 7327 7328 DisallowHeapAllocation no_gc; 7329 7330 uc16* sink = answer->GetChars(); 7331 #ifdef DEBUG 7332 uc16* end = sink + length; 7333 #endif 7334 7335 RUNTIME_ASSERT(fixed_array->get(0)->IsString()); 7336 String* first = String::cast(fixed_array->get(0)); 7337 String* separator_raw = *separator; 7338 int first_length = first->length(); 7339 String::WriteToFlat(first, sink, 0, first_length); 7340 sink += first_length; 7341 7342 for (int i = 1; i < array_length; i++) { 7343 ASSERT(sink + separator_length <= end); 7344 String::WriteToFlat(separator_raw, sink, 0, separator_length); 7345 sink += separator_length; 7346 7347 RUNTIME_ASSERT(fixed_array->get(i)->IsString()); 7348 String* element = String::cast(fixed_array->get(i)); 7349 int element_length = element->length(); 7350 ASSERT(sink + element_length <= end); 7351 String::WriteToFlat(element, sink, 0, element_length); 7352 sink += element_length; 7353 } 7354 ASSERT(sink == end); 7355 7356 // Use %_FastAsciiArrayJoin instead. 7357 ASSERT(!answer->IsOneByteRepresentation()); 7358 return *answer; 7359 } 7360 7361 template <typename Char> 7362 static void JoinSparseArrayWithSeparator(FixedArray* elements, 7363 int elements_length, 7364 uint32_t array_length, 7365 String* separator, 7366 Vector<Char> buffer) { 7367 DisallowHeapAllocation no_gc; 7368 int previous_separator_position = 0; 7369 int separator_length = separator->length(); 7370 int cursor = 0; 7371 for (int i = 0; i < elements_length; i += 2) { 7372 int position = NumberToInt32(elements->get(i)); 7373 String* string = String::cast(elements->get(i + 1)); 7374 int string_length = string->length(); 7375 if (string->length() > 0) { 7376 while (previous_separator_position < position) { 7377 String::WriteToFlat<Char>(separator, &buffer[cursor], 7378 0, separator_length); 7379 cursor += separator_length; 7380 previous_separator_position++; 7381 } 7382 String::WriteToFlat<Char>(string, &buffer[cursor], 7383 0, string_length); 7384 cursor += string->length(); 7385 } 7386 } 7387 if (separator_length > 0) { 7388 // Array length must be representable as a signed 32-bit number, 7389 // otherwise the total string length would have been too large. 7390 ASSERT(array_length <= 0x7fffffff); // Is int32_t. 7391 int last_array_index = static_cast<int>(array_length - 1); 7392 while (previous_separator_position < last_array_index) { 7393 String::WriteToFlat<Char>(separator, &buffer[cursor], 7394 0, separator_length); 7395 cursor += separator_length; 7396 previous_separator_position++; 7397 } 7398 } 7399 ASSERT(cursor <= buffer.length()); 7400 } 7401 7402 7403 RUNTIME_FUNCTION(Runtime_SparseJoinWithSeparator) { 7404 HandleScope scope(isolate); 7405 ASSERT(args.length() == 3); 7406 CONVERT_ARG_HANDLE_CHECKED(JSArray, elements_array, 0); 7407 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); 7408 CONVERT_ARG_HANDLE_CHECKED(String, separator, 2); 7409 // elements_array is fast-mode JSarray of alternating positions 7410 // (increasing order) and strings. 7411 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); 7412 // array_length is length of original array (used to add separators); 7413 // separator is string to put between elements. Assumed to be non-empty. 7414 RUNTIME_ASSERT(array_length > 0); 7415 7416 // Find total length of join result. 7417 int string_length = 0; 7418 bool is_ascii = separator->IsOneByteRepresentation(); 7419 bool overflow = false; 7420 CONVERT_NUMBER_CHECKED(int, elements_length, Int32, elements_array->length()); 7421 RUNTIME_ASSERT(elements_length <= elements_array->elements()->length()); 7422 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. 7423 FixedArray* elements = FixedArray::cast(elements_array->elements()); 7424 for (int i = 0; i < elements_length; i += 2) { 7425 RUNTIME_ASSERT(elements->get(i)->IsNumber()); 7426 CONVERT_NUMBER_CHECKED(uint32_t, position, Uint32, elements->get(i)); 7427 RUNTIME_ASSERT(position < array_length); 7428 RUNTIME_ASSERT(elements->get(i + 1)->IsString()); 7429 } 7430 7431 { DisallowHeapAllocation no_gc; 7432 for (int i = 0; i < elements_length; i += 2) { 7433 String* string = String::cast(elements->get(i + 1)); 7434 int length = string->length(); 7435 if (is_ascii && !string->IsOneByteRepresentation()) { 7436 is_ascii = false; 7437 } 7438 if (length > String::kMaxLength || 7439 String::kMaxLength - length < string_length) { 7440 overflow = true; 7441 break; 7442 } 7443 string_length += length; 7444 } 7445 } 7446 7447 int separator_length = separator->length(); 7448 if (!overflow && separator_length > 0) { 7449 if (array_length <= 0x7fffffffu) { 7450 int separator_count = static_cast<int>(array_length) - 1; 7451 int remaining_length = String::kMaxLength - string_length; 7452 if ((remaining_length / separator_length) >= separator_count) { 7453 string_length += separator_length * (array_length - 1); 7454 } else { 7455 // Not room for the separators within the maximal string length. 7456 overflow = true; 7457 } 7458 } else { 7459 // Nonempty separator and at least 2^31-1 separators necessary 7460 // means that the string is too large to create. 7461 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); 7462 overflow = true; 7463 } 7464 } 7465 if (overflow) { 7466 // Throw an exception if the resulting string is too large. See 7467 // https://code.google.com/p/chromium/issues/detail?id=336820 7468 // for details. 7469 return isolate->ThrowInvalidStringLength(); 7470 } 7471 7472 if (is_ascii) { 7473 Handle<SeqOneByteString> result = isolate->factory()->NewRawOneByteString( 7474 string_length).ToHandleChecked(); 7475 JoinSparseArrayWithSeparator<uint8_t>( 7476 FixedArray::cast(elements_array->elements()), 7477 elements_length, 7478 array_length, 7479 *separator, 7480 Vector<uint8_t>(result->GetChars(), string_length)); 7481 return *result; 7482 } else { 7483 Handle<SeqTwoByteString> result = isolate->factory()->NewRawTwoByteString( 7484 string_length).ToHandleChecked(); 7485 JoinSparseArrayWithSeparator<uc16>( 7486 FixedArray::cast(elements_array->elements()), 7487 elements_length, 7488 array_length, 7489 *separator, 7490 Vector<uc16>(result->GetChars(), string_length)); 7491 return *result; 7492 } 7493 } 7494 7495 7496 RUNTIME_FUNCTION(Runtime_NumberOr) { 7497 HandleScope scope(isolate); 7498 ASSERT(args.length() == 2); 7499 7500 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7501 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7502 return *isolate->factory()->NewNumberFromInt(x | y); 7503 } 7504 7505 7506 RUNTIME_FUNCTION(Runtime_NumberAnd) { 7507 HandleScope scope(isolate); 7508 ASSERT(args.length() == 2); 7509 7510 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7511 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7512 return *isolate->factory()->NewNumberFromInt(x & y); 7513 } 7514 7515 7516 RUNTIME_FUNCTION(Runtime_NumberXor) { 7517 HandleScope scope(isolate); 7518 ASSERT(args.length() == 2); 7519 7520 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7521 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7522 return *isolate->factory()->NewNumberFromInt(x ^ y); 7523 } 7524 7525 7526 RUNTIME_FUNCTION(Runtime_NumberShl) { 7527 HandleScope scope(isolate); 7528 ASSERT(args.length() == 2); 7529 7530 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7531 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7532 return *isolate->factory()->NewNumberFromInt(x << (y & 0x1f)); 7533 } 7534 7535 7536 RUNTIME_FUNCTION(Runtime_NumberShr) { 7537 HandleScope scope(isolate); 7538 ASSERT(args.length() == 2); 7539 7540 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 7541 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7542 return *isolate->factory()->NewNumberFromUint(x >> (y & 0x1f)); 7543 } 7544 7545 7546 RUNTIME_FUNCTION(Runtime_NumberSar) { 7547 HandleScope scope(isolate); 7548 ASSERT(args.length() == 2); 7549 7550 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7551 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7552 return *isolate->factory()->NewNumberFromInt( 7553 ArithmeticShiftRight(x, y & 0x1f)); 7554 } 7555 7556 7557 RUNTIME_FUNCTION(Runtime_NumberEquals) { 7558 SealHandleScope shs(isolate); 7559 ASSERT(args.length() == 2); 7560 7561 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7562 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7563 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL); 7564 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL); 7565 if (x == y) return Smi::FromInt(EQUAL); 7566 Object* result; 7567 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 7568 result = Smi::FromInt(EQUAL); 7569 } else { 7570 result = Smi::FromInt(NOT_EQUAL); 7571 } 7572 return result; 7573 } 7574 7575 7576 RUNTIME_FUNCTION(Runtime_StringEquals) { 7577 HandleScope handle_scope(isolate); 7578 ASSERT(args.length() == 2); 7579 7580 CONVERT_ARG_HANDLE_CHECKED(String, x, 0); 7581 CONVERT_ARG_HANDLE_CHECKED(String, y, 1); 7582 7583 bool not_equal = !String::Equals(x, y); 7584 // This is slightly convoluted because the value that signifies 7585 // equality is 0 and inequality is 1 so we have to negate the result 7586 // from String::Equals. 7587 ASSERT(not_equal == 0 || not_equal == 1); 7588 STATIC_ASSERT(EQUAL == 0); 7589 STATIC_ASSERT(NOT_EQUAL == 1); 7590 return Smi::FromInt(not_equal); 7591 } 7592 7593 7594 RUNTIME_FUNCTION(Runtime_NumberCompare) { 7595 SealHandleScope shs(isolate); 7596 ASSERT(args.length() == 3); 7597 7598 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7599 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7600 CONVERT_ARG_HANDLE_CHECKED(Object, uncomparable_result, 2) 7601 if (std::isnan(x) || std::isnan(y)) return *uncomparable_result; 7602 if (x == y) return Smi::FromInt(EQUAL); 7603 if (isless(x, y)) return Smi::FromInt(LESS); 7604 return Smi::FromInt(GREATER); 7605 } 7606 7607 7608 // Compare two Smis as if they were converted to strings and then 7609 // compared lexicographically. 7610 RUNTIME_FUNCTION(Runtime_SmiLexicographicCompare) { 7611 SealHandleScope shs(isolate); 7612 ASSERT(args.length() == 2); 7613 CONVERT_SMI_ARG_CHECKED(x_value, 0); 7614 CONVERT_SMI_ARG_CHECKED(y_value, 1); 7615 7616 // If the integers are equal so are the string representations. 7617 if (x_value == y_value) return Smi::FromInt(EQUAL); 7618 7619 // If one of the integers is zero the normal integer order is the 7620 // same as the lexicographic order of the string representations. 7621 if (x_value == 0 || y_value == 0) 7622 return Smi::FromInt(x_value < y_value ? LESS : GREATER); 7623 7624 // If only one of the integers is negative the negative number is 7625 // smallest because the char code of '-' is less than the char code 7626 // of any digit. Otherwise, we make both values positive. 7627 7628 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on 7629 // architectures using 32-bit Smis. 7630 uint32_t x_scaled = x_value; 7631 uint32_t y_scaled = y_value; 7632 if (x_value < 0 || y_value < 0) { 7633 if (y_value >= 0) return Smi::FromInt(LESS); 7634 if (x_value >= 0) return Smi::FromInt(GREATER); 7635 x_scaled = -x_value; 7636 y_scaled = -y_value; 7637 } 7638 7639 static const uint32_t kPowersOf10[] = { 7640 1, 10, 100, 1000, 10*1000, 100*1000, 7641 1000*1000, 10*1000*1000, 100*1000*1000, 7642 1000*1000*1000 7643 }; 7644 7645 // If the integers have the same number of decimal digits they can be 7646 // compared directly as the numeric order is the same as the 7647 // lexicographic order. If one integer has fewer digits, it is scaled 7648 // by some power of 10 to have the same number of digits as the longer 7649 // integer. If the scaled integers are equal it means the shorter 7650 // integer comes first in the lexicographic order. 7651 7652 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 7653 int x_log2 = IntegerLog2(x_scaled); 7654 int x_log10 = ((x_log2 + 1) * 1233) >> 12; 7655 x_log10 -= x_scaled < kPowersOf10[x_log10]; 7656 7657 int y_log2 = IntegerLog2(y_scaled); 7658 int y_log10 = ((y_log2 + 1) * 1233) >> 12; 7659 y_log10 -= y_scaled < kPowersOf10[y_log10]; 7660 7661 int tie = EQUAL; 7662 7663 if (x_log10 < y_log10) { 7664 // X has fewer digits. We would like to simply scale up X but that 7665 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would 7666 // be scaled up to 9_000_000_000. So we scale up by the next 7667 // smallest power and scale down Y to drop one digit. It is OK to 7668 // drop one digit from the longer integer since the final digit is 7669 // past the length of the shorter integer. 7670 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; 7671 y_scaled /= 10; 7672 tie = LESS; 7673 } else if (y_log10 < x_log10) { 7674 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; 7675 x_scaled /= 10; 7676 tie = GREATER; 7677 } 7678 7679 if (x_scaled < y_scaled) return Smi::FromInt(LESS); 7680 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); 7681 return Smi::FromInt(tie); 7682 } 7683 7684 7685 RUNTIME_FUNCTION(RuntimeHidden_StringCompare) { 7686 HandleScope handle_scope(isolate); 7687 ASSERT(args.length() == 2); 7688 7689 CONVERT_ARG_HANDLE_CHECKED(String, x, 0); 7690 CONVERT_ARG_HANDLE_CHECKED(String, y, 1); 7691 7692 isolate->counters()->string_compare_runtime()->Increment(); 7693 7694 // A few fast case tests before we flatten. 7695 if (x.is_identical_to(y)) return Smi::FromInt(EQUAL); 7696 if (y->length() == 0) { 7697 if (x->length() == 0) return Smi::FromInt(EQUAL); 7698 return Smi::FromInt(GREATER); 7699 } else if (x->length() == 0) { 7700 return Smi::FromInt(LESS); 7701 } 7702 7703 int d = x->Get(0) - y->Get(0); 7704 if (d < 0) return Smi::FromInt(LESS); 7705 else if (d > 0) return Smi::FromInt(GREATER); 7706 7707 // Slow case. 7708 x = String::Flatten(x); 7709 y = String::Flatten(y); 7710 7711 DisallowHeapAllocation no_gc; 7712 Object* equal_prefix_result = Smi::FromInt(EQUAL); 7713 int prefix_length = x->length(); 7714 if (y->length() < prefix_length) { 7715 prefix_length = y->length(); 7716 equal_prefix_result = Smi::FromInt(GREATER); 7717 } else if (y->length() > prefix_length) { 7718 equal_prefix_result = Smi::FromInt(LESS); 7719 } 7720 int r; 7721 String::FlatContent x_content = x->GetFlatContent(); 7722 String::FlatContent y_content = y->GetFlatContent(); 7723 if (x_content.IsAscii()) { 7724 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 7725 if (y_content.IsAscii()) { 7726 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7727 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7728 } else { 7729 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7730 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7731 } 7732 } else { 7733 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 7734 if (y_content.IsAscii()) { 7735 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7736 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7737 } else { 7738 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7739 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7740 } 7741 } 7742 Object* result; 7743 if (r == 0) { 7744 result = equal_prefix_result; 7745 } else { 7746 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); 7747 } 7748 return result; 7749 } 7750 7751 7752 #define RUNTIME_UNARY_MATH(Name, name) \ 7753 RUNTIME_FUNCTION(Runtime_Math##Name) { \ 7754 HandleScope scope(isolate); \ 7755 ASSERT(args.length() == 1); \ 7756 isolate->counters()->math_##name()->Increment(); \ 7757 CONVERT_DOUBLE_ARG_CHECKED(x, 0); \ 7758 return *isolate->factory()->NewHeapNumber(std::name(x)); \ 7759 } 7760 7761 RUNTIME_UNARY_MATH(Acos, acos) 7762 RUNTIME_UNARY_MATH(Asin, asin) 7763 RUNTIME_UNARY_MATH(Atan, atan) 7764 RUNTIME_UNARY_MATH(LogRT, log) 7765 #undef RUNTIME_UNARY_MATH 7766 7767 7768 RUNTIME_FUNCTION(Runtime_DoubleHi) { 7769 HandleScope scope(isolate); 7770 ASSERT(args.length() == 1); 7771 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7772 uint64_t integer = double_to_uint64(x); 7773 integer = (integer >> 32) & 0xFFFFFFFFu; 7774 return *isolate->factory()->NewNumber(static_cast<int32_t>(integer)); 7775 } 7776 7777 7778 RUNTIME_FUNCTION(Runtime_DoubleLo) { 7779 HandleScope scope(isolate); 7780 ASSERT(args.length() == 1); 7781 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7782 return *isolate->factory()->NewNumber( 7783 static_cast<int32_t>(double_to_uint64(x) & 0xFFFFFFFFu)); 7784 } 7785 7786 7787 RUNTIME_FUNCTION(Runtime_ConstructDouble) { 7788 HandleScope scope(isolate); 7789 ASSERT(args.length() == 2); 7790 CONVERT_NUMBER_CHECKED(uint32_t, hi, Uint32, args[0]); 7791 CONVERT_NUMBER_CHECKED(uint32_t, lo, Uint32, args[1]); 7792 uint64_t result = (static_cast<uint64_t>(hi) << 32) | lo; 7793 return *isolate->factory()->NewNumber(uint64_to_double(result)); 7794 } 7795 7796 7797 static const double kPiDividedBy4 = 0.78539816339744830962; 7798 7799 7800 RUNTIME_FUNCTION(Runtime_MathAtan2) { 7801 HandleScope scope(isolate); 7802 ASSERT(args.length() == 2); 7803 isolate->counters()->math_atan2()->Increment(); 7804 7805 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7806 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7807 double result; 7808 if (std::isinf(x) && std::isinf(y)) { 7809 // Make sure that the result in case of two infinite arguments 7810 // is a multiple of Pi / 4. The sign of the result is determined 7811 // by the first argument (x) and the sign of the second argument 7812 // determines the multiplier: one or three. 7813 int multiplier = (x < 0) ? -1 : 1; 7814 if (y < 0) multiplier *= 3; 7815 result = multiplier * kPiDividedBy4; 7816 } else { 7817 result = std::atan2(x, y); 7818 } 7819 return *isolate->factory()->NewNumber(result); 7820 } 7821 7822 7823 RUNTIME_FUNCTION(Runtime_MathExpRT) { 7824 HandleScope scope(isolate); 7825 ASSERT(args.length() == 1); 7826 isolate->counters()->math_exp()->Increment(); 7827 7828 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7829 lazily_initialize_fast_exp(); 7830 return *isolate->factory()->NewNumber(fast_exp(x)); 7831 } 7832 7833 7834 RUNTIME_FUNCTION(Runtime_MathFloorRT) { 7835 HandleScope scope(isolate); 7836 ASSERT(args.length() == 1); 7837 isolate->counters()->math_floor()->Increment(); 7838 7839 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7840 return *isolate->factory()->NewNumber(std::floor(x)); 7841 } 7842 7843 7844 // Slow version of Math.pow. We check for fast paths for special cases. 7845 // Used if VFP3 is not available. 7846 RUNTIME_FUNCTION(RuntimeHidden_MathPowSlow) { 7847 HandleScope scope(isolate); 7848 ASSERT(args.length() == 2); 7849 isolate->counters()->math_pow()->Increment(); 7850 7851 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7852 7853 // If the second argument is a smi, it is much faster to call the 7854 // custom powi() function than the generic pow(). 7855 if (args[1]->IsSmi()) { 7856 int y = args.smi_at(1); 7857 return *isolate->factory()->NewNumber(power_double_int(x, y)); 7858 } 7859 7860 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7861 double result = power_helper(x, y); 7862 if (std::isnan(result)) return isolate->heap()->nan_value(); 7863 return *isolate->factory()->NewNumber(result); 7864 } 7865 7866 7867 // Fast version of Math.pow if we know that y is not an integer and y is not 7868 // -0.5 or 0.5. Used as slow case from full codegen. 7869 RUNTIME_FUNCTION(RuntimeHidden_MathPow) { 7870 HandleScope scope(isolate); 7871 ASSERT(args.length() == 2); 7872 isolate->counters()->math_pow()->Increment(); 7873 7874 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7875 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7876 if (y == 0) { 7877 return Smi::FromInt(1); 7878 } else { 7879 double result = power_double_double(x, y); 7880 if (std::isnan(result)) return isolate->heap()->nan_value(); 7881 return *isolate->factory()->NewNumber(result); 7882 } 7883 } 7884 7885 7886 RUNTIME_FUNCTION(Runtime_RoundNumber) { 7887 HandleScope scope(isolate); 7888 ASSERT(args.length() == 1); 7889 CONVERT_NUMBER_ARG_HANDLE_CHECKED(input, 0); 7890 isolate->counters()->math_round()->Increment(); 7891 7892 if (!input->IsHeapNumber()) { 7893 ASSERT(input->IsSmi()); 7894 return *input; 7895 } 7896 7897 Handle<HeapNumber> number = Handle<HeapNumber>::cast(input); 7898 7899 double value = number->value(); 7900 int exponent = number->get_exponent(); 7901 int sign = number->get_sign(); 7902 7903 if (exponent < -1) { 7904 // Number in range ]-0.5..0.5[. These always round to +/-zero. 7905 if (sign) return isolate->heap()->minus_zero_value(); 7906 return Smi::FromInt(0); 7907 } 7908 7909 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and 7910 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar 7911 // argument holds for 32-bit smis). 7912 if (!sign && exponent < kSmiValueSize - 2) { 7913 return Smi::FromInt(static_cast<int>(value + 0.5)); 7914 } 7915 7916 // If the magnitude is big enough, there's no place for fraction part. If we 7917 // try to add 0.5 to this number, 1.0 will be added instead. 7918 if (exponent >= 52) { 7919 return *number; 7920 } 7921 7922 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); 7923 7924 // Do not call NumberFromDouble() to avoid extra checks. 7925 return *isolate->factory()->NewNumber(std::floor(value + 0.5)); 7926 } 7927 7928 7929 RUNTIME_FUNCTION(Runtime_MathSqrtRT) { 7930 HandleScope scope(isolate); 7931 ASSERT(args.length() == 1); 7932 isolate->counters()->math_sqrt()->Increment(); 7933 7934 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7935 return *isolate->factory()->NewNumber(fast_sqrt(x)); 7936 } 7937 7938 7939 RUNTIME_FUNCTION(Runtime_MathFround) { 7940 HandleScope scope(isolate); 7941 ASSERT(args.length() == 1); 7942 7943 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7944 float xf = static_cast<float>(x); 7945 return *isolate->factory()->NewNumber(xf); 7946 } 7947 7948 7949 RUNTIME_FUNCTION(Runtime_DateMakeDay) { 7950 SealHandleScope shs(isolate); 7951 ASSERT(args.length() == 2); 7952 7953 CONVERT_SMI_ARG_CHECKED(year, 0); 7954 CONVERT_SMI_ARG_CHECKED(month, 1); 7955 7956 int days = isolate->date_cache()->DaysFromYearMonth(year, month); 7957 RUNTIME_ASSERT(Smi::IsValid(days)); 7958 return Smi::FromInt(days); 7959 } 7960 7961 7962 RUNTIME_FUNCTION(Runtime_DateSetValue) { 7963 HandleScope scope(isolate); 7964 ASSERT(args.length() == 3); 7965 7966 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); 7967 CONVERT_DOUBLE_ARG_CHECKED(time, 1); 7968 CONVERT_SMI_ARG_CHECKED(is_utc, 2); 7969 7970 DateCache* date_cache = isolate->date_cache(); 7971 7972 Handle<Object> value;; 7973 bool is_value_nan = false; 7974 if (std::isnan(time)) { 7975 value = isolate->factory()->nan_value(); 7976 is_value_nan = true; 7977 } else if (!is_utc && 7978 (time < -DateCache::kMaxTimeBeforeUTCInMs || 7979 time > DateCache::kMaxTimeBeforeUTCInMs)) { 7980 value = isolate->factory()->nan_value(); 7981 is_value_nan = true; 7982 } else { 7983 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); 7984 if (time < -DateCache::kMaxTimeInMs || 7985 time > DateCache::kMaxTimeInMs) { 7986 value = isolate->factory()->nan_value(); 7987 is_value_nan = true; 7988 } else { 7989 value = isolate->factory()->NewNumber(DoubleToInteger(time)); 7990 } 7991 } 7992 date->SetValue(*value, is_value_nan); 7993 return *value; 7994 } 7995 7996 7997 RUNTIME_FUNCTION(RuntimeHidden_NewSloppyArguments) { 7998 HandleScope scope(isolate); 7999 ASSERT(args.length() == 3); 8000 8001 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0); 8002 Object** parameters = reinterpret_cast<Object**>(args[1]); 8003 CONVERT_SMI_ARG_CHECKED(argument_count, 2); 8004 8005 Handle<JSObject> result = 8006 isolate->factory()->NewArgumentsObject(callee, argument_count); 8007 // Allocate the elements if needed. 8008 int parameter_count = callee->shared()->formal_parameter_count(); 8009 if (argument_count > 0) { 8010 if (parameter_count > 0) { 8011 int mapped_count = Min(argument_count, parameter_count); 8012 Handle<FixedArray> parameter_map = 8013 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); 8014 parameter_map->set_map( 8015 isolate->heap()->sloppy_arguments_elements_map()); 8016 8017 Handle<Map> map = Map::Copy(handle(result->map())); 8018 map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS); 8019 8020 result->set_map(*map); 8021 result->set_elements(*parameter_map); 8022 8023 // Store the context and the arguments array at the beginning of the 8024 // parameter map. 8025 Handle<Context> context(isolate->context()); 8026 Handle<FixedArray> arguments = 8027 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 8028 parameter_map->set(0, *context); 8029 parameter_map->set(1, *arguments); 8030 8031 // Loop over the actual parameters backwards. 8032 int index = argument_count - 1; 8033 while (index >= mapped_count) { 8034 // These go directly in the arguments array and have no 8035 // corresponding slot in the parameter map. 8036 arguments->set(index, *(parameters - index - 1)); 8037 --index; 8038 } 8039 8040 Handle<ScopeInfo> scope_info(callee->shared()->scope_info()); 8041 while (index >= 0) { 8042 // Detect duplicate names to the right in the parameter list. 8043 Handle<String> name(scope_info->ParameterName(index)); 8044 int context_local_count = scope_info->ContextLocalCount(); 8045 bool duplicate = false; 8046 for (int j = index + 1; j < parameter_count; ++j) { 8047 if (scope_info->ParameterName(j) == *name) { 8048 duplicate = true; 8049 break; 8050 } 8051 } 8052 8053 if (duplicate) { 8054 // This goes directly in the arguments array with a hole in the 8055 // parameter map. 8056 arguments->set(index, *(parameters - index - 1)); 8057 parameter_map->set_the_hole(index + 2); 8058 } else { 8059 // The context index goes in the parameter map with a hole in the 8060 // arguments array. 8061 int context_index = -1; 8062 for (int j = 0; j < context_local_count; ++j) { 8063 if (scope_info->ContextLocalName(j) == *name) { 8064 context_index = j; 8065 break; 8066 } 8067 } 8068 ASSERT(context_index >= 0); 8069 arguments->set_the_hole(index); 8070 parameter_map->set(index + 2, Smi::FromInt( 8071 Context::MIN_CONTEXT_SLOTS + context_index)); 8072 } 8073 8074 --index; 8075 } 8076 } else { 8077 // If there is no aliasing, the arguments object elements are not 8078 // special in any way. 8079 Handle<FixedArray> elements = 8080 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 8081 result->set_elements(*elements); 8082 for (int i = 0; i < argument_count; ++i) { 8083 elements->set(i, *(parameters - i - 1)); 8084 } 8085 } 8086 } 8087 return *result; 8088 } 8089 8090 8091 RUNTIME_FUNCTION(RuntimeHidden_NewStrictArguments) { 8092 HandleScope scope(isolate); 8093 ASSERT(args.length() == 3); 8094 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0) 8095 Object** parameters = reinterpret_cast<Object**>(args[1]); 8096 CONVERT_SMI_ARG_CHECKED(length, 2); 8097 8098 Handle<JSObject> result = 8099 isolate->factory()->NewArgumentsObject(callee, length); 8100 8101 if (length > 0) { 8102 Handle<FixedArray> array = 8103 isolate->factory()->NewUninitializedFixedArray(length); 8104 DisallowHeapAllocation no_gc; 8105 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 8106 for (int i = 0; i < length; i++) { 8107 array->set(i, *--parameters, mode); 8108 } 8109 result->set_elements(*array); 8110 } 8111 return *result; 8112 } 8113 8114 8115 RUNTIME_FUNCTION(RuntimeHidden_NewClosureFromStubFailure) { 8116 HandleScope scope(isolate); 8117 ASSERT(args.length() == 1); 8118 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0); 8119 Handle<Context> context(isolate->context()); 8120 PretenureFlag pretenure_flag = NOT_TENURED; 8121 return *isolate->factory()->NewFunctionFromSharedFunctionInfo( 8122 shared, context, pretenure_flag); 8123 } 8124 8125 8126 RUNTIME_FUNCTION(RuntimeHidden_NewClosure) { 8127 HandleScope scope(isolate); 8128 ASSERT(args.length() == 3); 8129 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 8130 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1); 8131 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2); 8132 8133 // The caller ensures that we pretenure closures that are assigned 8134 // directly to properties. 8135 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 8136 return *isolate->factory()->NewFunctionFromSharedFunctionInfo( 8137 shared, context, pretenure_flag); 8138 } 8139 8140 8141 // Find the arguments of the JavaScript function invocation that called 8142 // into C++ code. Collect these in a newly allocated array of handles (possibly 8143 // prefixed by a number of empty handles). 8144 static SmartArrayPointer<Handle<Object> > GetCallerArguments( 8145 Isolate* isolate, 8146 int prefix_argc, 8147 int* total_argc) { 8148 // Find frame containing arguments passed to the caller. 8149 JavaScriptFrameIterator it(isolate); 8150 JavaScriptFrame* frame = it.frame(); 8151 List<JSFunction*> functions(2); 8152 frame->GetFunctions(&functions); 8153 if (functions.length() > 1) { 8154 int inlined_jsframe_index = functions.length() - 1; 8155 JSFunction* inlined_function = functions[inlined_jsframe_index]; 8156 SlotRefValueBuilder slot_refs( 8157 frame, 8158 inlined_jsframe_index, 8159 inlined_function->shared()->formal_parameter_count()); 8160 8161 int args_count = slot_refs.args_length(); 8162 8163 *total_argc = prefix_argc + args_count; 8164 SmartArrayPointer<Handle<Object> > param_data( 8165 NewArray<Handle<Object> >(*total_argc)); 8166 slot_refs.Prepare(isolate); 8167 for (int i = 0; i < args_count; i++) { 8168 Handle<Object> val = slot_refs.GetNext(isolate, 0); 8169 param_data[prefix_argc + i] = val; 8170 } 8171 slot_refs.Finish(isolate); 8172 8173 return param_data; 8174 } else { 8175 it.AdvanceToArgumentsFrame(); 8176 frame = it.frame(); 8177 int args_count = frame->ComputeParametersCount(); 8178 8179 *total_argc = prefix_argc + args_count; 8180 SmartArrayPointer<Handle<Object> > param_data( 8181 NewArray<Handle<Object> >(*total_argc)); 8182 for (int i = 0; i < args_count; i++) { 8183 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate); 8184 param_data[prefix_argc + i] = val; 8185 } 8186 return param_data; 8187 } 8188 } 8189 8190 8191 RUNTIME_FUNCTION(Runtime_FunctionBindArguments) { 8192 HandleScope scope(isolate); 8193 ASSERT(args.length() == 4); 8194 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); 8195 CONVERT_ARG_HANDLE_CHECKED(Object, bindee, 1); 8196 CONVERT_ARG_HANDLE_CHECKED(Object, this_object, 2); 8197 CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3); 8198 8199 // TODO(lrn): Create bound function in C++ code from premade shared info. 8200 bound_function->shared()->set_bound(true); 8201 // Get all arguments of calling function (Function.prototype.bind). 8202 int argc = 0; 8203 SmartArrayPointer<Handle<Object> > arguments = 8204 GetCallerArguments(isolate, 0, &argc); 8205 // Don't count the this-arg. 8206 if (argc > 0) { 8207 RUNTIME_ASSERT(arguments[0].is_identical_to(this_object)); 8208 argc--; 8209 } else { 8210 RUNTIME_ASSERT(this_object->IsUndefined()); 8211 } 8212 // Initialize array of bindings (function, this, and any existing arguments 8213 // if the function was already bound). 8214 Handle<FixedArray> new_bindings; 8215 int i; 8216 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { 8217 Handle<FixedArray> old_bindings( 8218 JSFunction::cast(*bindee)->function_bindings()); 8219 RUNTIME_ASSERT(old_bindings->length() > JSFunction::kBoundFunctionIndex); 8220 new_bindings = 8221 isolate->factory()->NewFixedArray(old_bindings->length() + argc); 8222 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex), 8223 isolate); 8224 i = 0; 8225 for (int n = old_bindings->length(); i < n; i++) { 8226 new_bindings->set(i, old_bindings->get(i)); 8227 } 8228 } else { 8229 int array_size = JSFunction::kBoundArgumentsStartIndex + argc; 8230 new_bindings = isolate->factory()->NewFixedArray(array_size); 8231 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); 8232 new_bindings->set(JSFunction::kBoundThisIndex, *this_object); 8233 i = 2; 8234 } 8235 // Copy arguments, skipping the first which is "this_arg". 8236 for (int j = 0; j < argc; j++, i++) { 8237 new_bindings->set(i, *arguments[j + 1]); 8238 } 8239 new_bindings->set_map_no_write_barrier( 8240 isolate->heap()->fixed_cow_array_map()); 8241 bound_function->set_function_bindings(*new_bindings); 8242 8243 // Update length. Have to remove the prototype first so that map migration 8244 // is happy about the number of fields. 8245 RUNTIME_ASSERT(bound_function->RemovePrototype()); 8246 Handle<Map> bound_function_map( 8247 isolate->native_context()->bound_function_map()); 8248 JSObject::MigrateToMap(bound_function, bound_function_map); 8249 Handle<String> length_string = isolate->factory()->length_string(); 8250 PropertyAttributes attr = 8251 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); 8252 RETURN_FAILURE_ON_EXCEPTION( 8253 isolate, 8254 JSObject::SetOwnPropertyIgnoreAttributes(bound_function, length_string, 8255 new_length, attr)); 8256 return *bound_function; 8257 } 8258 8259 8260 RUNTIME_FUNCTION(Runtime_BoundFunctionGetBindings) { 8261 HandleScope handles(isolate); 8262 ASSERT(args.length() == 1); 8263 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); 8264 if (callable->IsJSFunction()) { 8265 Handle<JSFunction> function = Handle<JSFunction>::cast(callable); 8266 if (function->shared()->bound()) { 8267 Handle<FixedArray> bindings(function->function_bindings()); 8268 RUNTIME_ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); 8269 return *isolate->factory()->NewJSArrayWithElements(bindings); 8270 } 8271 } 8272 return isolate->heap()->undefined_value(); 8273 } 8274 8275 8276 RUNTIME_FUNCTION(Runtime_NewObjectFromBound) { 8277 HandleScope scope(isolate); 8278 ASSERT(args.length() == 1); 8279 // First argument is a function to use as a constructor. 8280 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8281 RUNTIME_ASSERT(function->shared()->bound()); 8282 8283 // The argument is a bound function. Extract its bound arguments 8284 // and callable. 8285 Handle<FixedArray> bound_args = 8286 Handle<FixedArray>(FixedArray::cast(function->function_bindings())); 8287 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; 8288 Handle<Object> bound_function( 8289 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)), 8290 isolate); 8291 ASSERT(!bound_function->IsJSFunction() || 8292 !Handle<JSFunction>::cast(bound_function)->shared()->bound()); 8293 8294 int total_argc = 0; 8295 SmartArrayPointer<Handle<Object> > param_data = 8296 GetCallerArguments(isolate, bound_argc, &total_argc); 8297 for (int i = 0; i < bound_argc; i++) { 8298 param_data[i] = Handle<Object>(bound_args->get( 8299 JSFunction::kBoundArgumentsStartIndex + i), isolate); 8300 } 8301 8302 if (!bound_function->IsJSFunction()) { 8303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 8304 isolate, bound_function, 8305 Execution::TryGetConstructorDelegate(isolate, bound_function)); 8306 } 8307 ASSERT(bound_function->IsJSFunction()); 8308 8309 Handle<Object> result; 8310 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 8311 isolate, result, 8312 Execution::New(Handle<JSFunction>::cast(bound_function), 8313 total_argc, param_data.get())); 8314 return *result; 8315 } 8316 8317 8318 static Object* Runtime_NewObjectHelper(Isolate* isolate, 8319 Handle<Object> constructor, 8320 Handle<AllocationSite> site) { 8321 // If the constructor isn't a proper function we throw a type error. 8322 if (!constructor->IsJSFunction()) { 8323 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8324 Handle<Object> type_error = 8325 isolate->factory()->NewTypeError("not_constructor", arguments); 8326 return isolate->Throw(*type_error); 8327 } 8328 8329 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 8330 8331 // If function should not have prototype, construction is not allowed. In this 8332 // case generated code bailouts here, since function has no initial_map. 8333 if (!function->should_have_prototype() && !function->shared()->bound()) { 8334 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8335 Handle<Object> type_error = 8336 isolate->factory()->NewTypeError("not_constructor", arguments); 8337 return isolate->Throw(*type_error); 8338 } 8339 8340 Debug* debug = isolate->debug(); 8341 // Handle stepping into constructors if step into is active. 8342 if (debug->StepInActive()) { 8343 debug->HandleStepIn(function, Handle<Object>::null(), 0, true); 8344 } 8345 8346 if (function->has_initial_map()) { 8347 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 8348 // The 'Function' function ignores the receiver object when 8349 // called using 'new' and creates a new JSFunction object that 8350 // is returned. The receiver object is only used for error 8351 // reporting if an error occurs when constructing the new 8352 // JSFunction. Factory::NewJSObject() should not be used to 8353 // allocate JSFunctions since it does not properly initialize 8354 // the shared part of the function. Since the receiver is 8355 // ignored anyway, we use the global object as the receiver 8356 // instead of a new JSFunction object. This way, errors are 8357 // reported the same way whether or not 'Function' is called 8358 // using 'new'. 8359 return isolate->context()->global_object(); 8360 } 8361 } 8362 8363 // The function should be compiled for the optimization hints to be 8364 // available. 8365 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION); 8366 8367 Handle<JSObject> result; 8368 if (site.is_null()) { 8369 result = isolate->factory()->NewJSObject(function); 8370 } else { 8371 result = isolate->factory()->NewJSObjectWithMemento(function, site); 8372 } 8373 8374 isolate->counters()->constructed_objects()->Increment(); 8375 isolate->counters()->constructed_objects_runtime()->Increment(); 8376 8377 return *result; 8378 } 8379 8380 8381 RUNTIME_FUNCTION(RuntimeHidden_NewObject) { 8382 HandleScope scope(isolate); 8383 ASSERT(args.length() == 1); 8384 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0); 8385 return Runtime_NewObjectHelper(isolate, 8386 constructor, 8387 Handle<AllocationSite>::null()); 8388 } 8389 8390 8391 RUNTIME_FUNCTION(RuntimeHidden_NewObjectWithAllocationSite) { 8392 HandleScope scope(isolate); 8393 ASSERT(args.length() == 2); 8394 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1); 8395 CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0); 8396 Handle<AllocationSite> site; 8397 if (feedback->IsAllocationSite()) { 8398 // The feedback can be an AllocationSite or undefined. 8399 site = Handle<AllocationSite>::cast(feedback); 8400 } 8401 return Runtime_NewObjectHelper(isolate, constructor, site); 8402 } 8403 8404 8405 RUNTIME_FUNCTION(RuntimeHidden_FinalizeInstanceSize) { 8406 HandleScope scope(isolate); 8407 ASSERT(args.length() == 1); 8408 8409 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8410 function->CompleteInobjectSlackTracking(); 8411 8412 return isolate->heap()->undefined_value(); 8413 } 8414 8415 8416 RUNTIME_FUNCTION(RuntimeHidden_CompileUnoptimized) { 8417 HandleScope scope(isolate); 8418 ASSERT(args.length() == 1); 8419 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8420 #ifdef DEBUG 8421 if (FLAG_trace_lazy && !function->shared()->is_compiled()) { 8422 PrintF("[unoptimized: "); 8423 function->PrintName(); 8424 PrintF("]\n"); 8425 } 8426 #endif 8427 8428 // Compile the target function. 8429 ASSERT(function->shared()->allows_lazy_compilation()); 8430 8431 Handle<Code> code; 8432 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code, 8433 Compiler::GetUnoptimizedCode(function)); 8434 function->ReplaceCode(*code); 8435 8436 // All done. Return the compiled code. 8437 ASSERT(function->is_compiled()); 8438 ASSERT(function->code()->kind() == Code::FUNCTION || 8439 (FLAG_always_opt && 8440 function->code()->kind() == Code::OPTIMIZED_FUNCTION)); 8441 return *code; 8442 } 8443 8444 8445 RUNTIME_FUNCTION(RuntimeHidden_CompileOptimized) { 8446 HandleScope scope(isolate); 8447 ASSERT(args.length() == 2); 8448 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8449 CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1); 8450 8451 Handle<Code> unoptimized(function->shared()->code()); 8452 if (!function->shared()->is_compiled()) { 8453 // If the function is not compiled, do not optimize. 8454 // This can happen if the debugger is activated and 8455 // the function is returned to the not compiled state. 8456 // TODO(yangguo): reconsider this. 8457 function->ReplaceCode(function->shared()->code()); 8458 } else if (!isolate->use_crankshaft() || 8459 function->shared()->optimization_disabled() || 8460 isolate->DebuggerHasBreakPoints()) { 8461 // If the function is not optimizable or debugger is active continue 8462 // using the code from the full compiler. 8463 if (FLAG_trace_opt) { 8464 PrintF("[failed to optimize "); 8465 function->PrintName(); 8466 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", 8467 function->shared()->optimization_disabled() ? "F" : "T", 8468 isolate->DebuggerHasBreakPoints() ? "T" : "F"); 8469 } 8470 function->ReplaceCode(*unoptimized); 8471 } else { 8472 Compiler::ConcurrencyMode mode = concurrent ? Compiler::CONCURRENT 8473 : Compiler::NOT_CONCURRENT; 8474 Handle<Code> code; 8475 if (Compiler::GetOptimizedCode( 8476 function, unoptimized, mode).ToHandle(&code)) { 8477 function->ReplaceCode(*code); 8478 } else { 8479 function->ReplaceCode(*unoptimized); 8480 } 8481 } 8482 8483 ASSERT(function->code()->kind() == Code::FUNCTION || 8484 function->code()->kind() == Code::OPTIMIZED_FUNCTION || 8485 function->IsInOptimizationQueue()); 8486 return function->code(); 8487 } 8488 8489 8490 class ActivationsFinder : public ThreadVisitor { 8491 public: 8492 Code* code_; 8493 bool has_code_activations_; 8494 8495 explicit ActivationsFinder(Code* code) 8496 : code_(code), 8497 has_code_activations_(false) { } 8498 8499 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 8500 JavaScriptFrameIterator it(isolate, top); 8501 VisitFrames(&it); 8502 } 8503 8504 void VisitFrames(JavaScriptFrameIterator* it) { 8505 for (; !it->done(); it->Advance()) { 8506 JavaScriptFrame* frame = it->frame(); 8507 if (code_->contains(frame->pc())) has_code_activations_ = true; 8508 } 8509 } 8510 }; 8511 8512 8513 RUNTIME_FUNCTION(RuntimeHidden_NotifyStubFailure) { 8514 HandleScope scope(isolate); 8515 ASSERT(args.length() == 0); 8516 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8517 ASSERT(AllowHeapAllocation::IsAllowed()); 8518 delete deoptimizer; 8519 return isolate->heap()->undefined_value(); 8520 } 8521 8522 8523 RUNTIME_FUNCTION(RuntimeHidden_NotifyDeoptimized) { 8524 HandleScope scope(isolate); 8525 ASSERT(args.length() == 1); 8526 CONVERT_SMI_ARG_CHECKED(type_arg, 0); 8527 Deoptimizer::BailoutType type = 8528 static_cast<Deoptimizer::BailoutType>(type_arg); 8529 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8530 ASSERT(AllowHeapAllocation::IsAllowed()); 8531 8532 Handle<JSFunction> function = deoptimizer->function(); 8533 Handle<Code> optimized_code = deoptimizer->compiled_code(); 8534 8535 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION); 8536 ASSERT(type == deoptimizer->bailout_type()); 8537 8538 // Make sure to materialize objects before causing any allocation. 8539 JavaScriptFrameIterator it(isolate); 8540 deoptimizer->MaterializeHeapObjects(&it); 8541 delete deoptimizer; 8542 8543 JavaScriptFrame* frame = it.frame(); 8544 RUNTIME_ASSERT(frame->function()->IsJSFunction()); 8545 ASSERT(frame->function() == *function); 8546 8547 // Avoid doing too much work when running with --always-opt and keep 8548 // the optimized code around. 8549 if (FLAG_always_opt || type == Deoptimizer::LAZY) { 8550 return isolate->heap()->undefined_value(); 8551 } 8552 8553 // Search for other activations of the same function and code. 8554 ActivationsFinder activations_finder(*optimized_code); 8555 activations_finder.VisitFrames(&it); 8556 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); 8557 8558 if (!activations_finder.has_code_activations_) { 8559 if (function->code() == *optimized_code) { 8560 if (FLAG_trace_deopt) { 8561 PrintF("[removing optimized code for: "); 8562 function->PrintName(); 8563 PrintF("]\n"); 8564 } 8565 function->ReplaceCode(function->shared()->code()); 8566 // Evict optimized code for this function from the cache so that it 8567 // doesn't get used for new closures. 8568 function->shared()->EvictFromOptimizedCodeMap(*optimized_code, 8569 "notify deoptimized"); 8570 } 8571 } else { 8572 // TODO(titzer): we should probably do DeoptimizeCodeList(code) 8573 // unconditionally if the code is not already marked for deoptimization. 8574 // If there is an index by shared function info, all the better. 8575 Deoptimizer::DeoptimizeFunction(*function); 8576 } 8577 8578 return isolate->heap()->undefined_value(); 8579 } 8580 8581 8582 RUNTIME_FUNCTION(Runtime_DeoptimizeFunction) { 8583 HandleScope scope(isolate); 8584 ASSERT(args.length() == 1); 8585 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8586 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 8587 8588 Deoptimizer::DeoptimizeFunction(*function); 8589 8590 return isolate->heap()->undefined_value(); 8591 } 8592 8593 8594 RUNTIME_FUNCTION(Runtime_ClearFunctionTypeFeedback) { 8595 HandleScope scope(isolate); 8596 ASSERT(args.length() == 1); 8597 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8598 function->shared()->ClearTypeFeedbackInfo(); 8599 Code* unoptimized = function->shared()->code(); 8600 if (unoptimized->kind() == Code::FUNCTION) { 8601 unoptimized->ClearInlineCaches(); 8602 } 8603 return isolate->heap()->undefined_value(); 8604 } 8605 8606 8607 RUNTIME_FUNCTION(Runtime_RunningInSimulator) { 8608 SealHandleScope shs(isolate); 8609 ASSERT(args.length() == 0); 8610 #if defined(USE_SIMULATOR) 8611 return isolate->heap()->true_value(); 8612 #else 8613 return isolate->heap()->false_value(); 8614 #endif 8615 } 8616 8617 8618 RUNTIME_FUNCTION(Runtime_IsConcurrentRecompilationSupported) { 8619 SealHandleScope shs(isolate); 8620 ASSERT(args.length() == 0); 8621 return isolate->heap()->ToBoolean( 8622 isolate->concurrent_recompilation_enabled()); 8623 } 8624 8625 8626 RUNTIME_FUNCTION(Runtime_OptimizeFunctionOnNextCall) { 8627 HandleScope scope(isolate); 8628 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8629 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8630 8631 if (!function->IsOptimizable() && 8632 !function->IsMarkedForConcurrentOptimization() && 8633 !function->IsInOptimizationQueue()) { 8634 return isolate->heap()->undefined_value(); 8635 } 8636 8637 function->MarkForOptimization(); 8638 8639 Code* unoptimized = function->shared()->code(); 8640 if (args.length() == 2 && 8641 unoptimized->kind() == Code::FUNCTION) { 8642 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 8643 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) { 8644 // Start patching from the currently patched loop nesting level. 8645 int current_level = unoptimized->allow_osr_at_loop_nesting_level(); 8646 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level)); 8647 if (FLAG_use_osr) { 8648 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) { 8649 unoptimized->set_allow_osr_at_loop_nesting_level(i); 8650 isolate->runtime_profiler()->AttemptOnStackReplacement(*function); 8651 } 8652 } 8653 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent")) && 8654 isolate->concurrent_recompilation_enabled()) { 8655 function->MarkForConcurrentOptimization(); 8656 } 8657 } 8658 8659 return isolate->heap()->undefined_value(); 8660 } 8661 8662 8663 RUNTIME_FUNCTION(Runtime_NeverOptimizeFunction) { 8664 HandleScope scope(isolate); 8665 ASSERT(args.length() == 1); 8666 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8667 function->shared()->set_optimization_disabled(true); 8668 return isolate->heap()->undefined_value(); 8669 } 8670 8671 8672 RUNTIME_FUNCTION(Runtime_GetOptimizationStatus) { 8673 HandleScope scope(isolate); 8674 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8675 if (!isolate->use_crankshaft()) { 8676 return Smi::FromInt(4); // 4 == "never". 8677 } 8678 bool sync_with_compiler_thread = true; 8679 if (args.length() == 2) { 8680 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1); 8681 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) { 8682 sync_with_compiler_thread = false; 8683 } 8684 } 8685 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8686 if (isolate->concurrent_recompilation_enabled() && 8687 sync_with_compiler_thread) { 8688 while (function->IsInOptimizationQueue()) { 8689 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 8690 OS::Sleep(50); 8691 } 8692 } 8693 if (FLAG_always_opt) { 8694 // We may have always opt, but that is more best-effort than a real 8695 // promise, so we still say "no" if it is not optimized. 8696 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always". 8697 : Smi::FromInt(2); // 2 == "no". 8698 } 8699 if (FLAG_deopt_every_n_times) { 8700 return Smi::FromInt(6); // 6 == "maybe deopted". 8701 } 8702 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". 8703 : Smi::FromInt(2); // 2 == "no". 8704 } 8705 8706 8707 RUNTIME_FUNCTION(Runtime_UnblockConcurrentRecompilation) { 8708 ASSERT(args.length() == 0); 8709 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); 8710 RUNTIME_ASSERT(isolate->concurrent_recompilation_enabled()); 8711 isolate->optimizing_compiler_thread()->Unblock(); 8712 return isolate->heap()->undefined_value(); 8713 } 8714 8715 8716 RUNTIME_FUNCTION(Runtime_GetOptimizationCount) { 8717 HandleScope scope(isolate); 8718 ASSERT(args.length() == 1); 8719 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8720 return Smi::FromInt(function->shared()->opt_count()); 8721 } 8722 8723 8724 static bool IsSuitableForOnStackReplacement(Isolate* isolate, 8725 Handle<JSFunction> function, 8726 Handle<Code> current_code) { 8727 // Keep track of whether we've succeeded in optimizing. 8728 if (!isolate->use_crankshaft() || !current_code->optimizable()) return false; 8729 // If we are trying to do OSR when there are already optimized 8730 // activations of the function, it means (a) the function is directly or 8731 // indirectly recursive and (b) an optimized invocation has been 8732 // deoptimized so that we are currently in an unoptimized activation. 8733 // Check for optimized activations of this function. 8734 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 8735 JavaScriptFrame* frame = it.frame(); 8736 if (frame->is_optimized() && frame->function() == *function) return false; 8737 } 8738 8739 return true; 8740 } 8741 8742 8743 RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) { 8744 HandleScope scope(isolate); 8745 ASSERT(args.length() == 1); 8746 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8747 Handle<Code> caller_code(function->shared()->code()); 8748 8749 // We're not prepared to handle a function with arguments object. 8750 ASSERT(!function->shared()->uses_arguments()); 8751 8752 RUNTIME_ASSERT(FLAG_use_osr); 8753 8754 // Passing the PC in the javascript frame from the caller directly is 8755 // not GC safe, so we walk the stack to get it. 8756 JavaScriptFrameIterator it(isolate); 8757 JavaScriptFrame* frame = it.frame(); 8758 if (!caller_code->contains(frame->pc())) { 8759 // Code on the stack may not be the code object referenced by the shared 8760 // function info. It may have been replaced to include deoptimization data. 8761 caller_code = Handle<Code>(frame->LookupCode()); 8762 } 8763 8764 uint32_t pc_offset = static_cast<uint32_t>( 8765 frame->pc() - caller_code->instruction_start()); 8766 8767 #ifdef DEBUG 8768 ASSERT_EQ(frame->function(), *function); 8769 ASSERT_EQ(frame->LookupCode(), *caller_code); 8770 ASSERT(caller_code->contains(frame->pc())); 8771 #endif // DEBUG 8772 8773 8774 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset); 8775 ASSERT(!ast_id.IsNone()); 8776 8777 Compiler::ConcurrencyMode mode = 8778 isolate->concurrent_osr_enabled() && 8779 (function->shared()->ast_node_count() > 512) ? Compiler::CONCURRENT 8780 : Compiler::NOT_CONCURRENT; 8781 Handle<Code> result = Handle<Code>::null(); 8782 8783 OptimizedCompileJob* job = NULL; 8784 if (mode == Compiler::CONCURRENT) { 8785 // Gate the OSR entry with a stack check. 8786 BackEdgeTable::AddStackCheck(caller_code, pc_offset); 8787 // Poll already queued compilation jobs. 8788 OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread(); 8789 if (thread->IsQueuedForOSR(function, ast_id)) { 8790 if (FLAG_trace_osr) { 8791 PrintF("[OSR - Still waiting for queued: "); 8792 function->PrintName(); 8793 PrintF(" at AST id %d]\n", ast_id.ToInt()); 8794 } 8795 return NULL; 8796 } 8797 8798 job = thread->FindReadyOSRCandidate(function, ast_id); 8799 } 8800 8801 if (job != NULL) { 8802 if (FLAG_trace_osr) { 8803 PrintF("[OSR - Found ready: "); 8804 function->PrintName(); 8805 PrintF(" at AST id %d]\n", ast_id.ToInt()); 8806 } 8807 result = Compiler::GetConcurrentlyOptimizedCode(job); 8808 } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) { 8809 if (FLAG_trace_osr) { 8810 PrintF("[OSR - Compiling: "); 8811 function->PrintName(); 8812 PrintF(" at AST id %d]\n", ast_id.ToInt()); 8813 } 8814 MaybeHandle<Code> maybe_result = Compiler::GetOptimizedCode( 8815 function, caller_code, mode, ast_id); 8816 if (maybe_result.ToHandle(&result) && 8817 result.is_identical_to(isolate->builtins()->InOptimizationQueue())) { 8818 // Optimization is queued. Return to check later. 8819 return NULL; 8820 } 8821 } 8822 8823 // Revert the patched back edge table, regardless of whether OSR succeeds. 8824 BackEdgeTable::Revert(isolate, *caller_code); 8825 8826 // Check whether we ended up with usable optimized code. 8827 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) { 8828 DeoptimizationInputData* data = 8829 DeoptimizationInputData::cast(result->deoptimization_data()); 8830 8831 if (data->OsrPcOffset()->value() >= 0) { 8832 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id); 8833 if (FLAG_trace_osr) { 8834 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n", 8835 ast_id.ToInt(), data->OsrPcOffset()->value()); 8836 } 8837 // TODO(titzer): this is a massive hack to make the deopt counts 8838 // match. Fix heuristics for reenabling optimizations! 8839 function->shared()->increment_deopt_count(); 8840 8841 // TODO(titzer): Do not install code into the function. 8842 function->ReplaceCode(*result); 8843 return *result; 8844 } 8845 } 8846 8847 // Failed. 8848 if (FLAG_trace_osr) { 8849 PrintF("[OSR - Failed: "); 8850 function->PrintName(); 8851 PrintF(" at AST id %d]\n", ast_id.ToInt()); 8852 } 8853 8854 if (!function->IsOptimized()) { 8855 function->ReplaceCode(function->shared()->code()); 8856 } 8857 return NULL; 8858 } 8859 8860 8861 RUNTIME_FUNCTION(Runtime_SetAllocationTimeout) { 8862 SealHandleScope shs(isolate); 8863 ASSERT(args.length() == 2 || args.length() == 3); 8864 #ifdef DEBUG 8865 CONVERT_SMI_ARG_CHECKED(interval, 0); 8866 CONVERT_SMI_ARG_CHECKED(timeout, 1); 8867 isolate->heap()->set_allocation_timeout(timeout); 8868 FLAG_gc_interval = interval; 8869 if (args.length() == 3) { 8870 // Enable/disable inline allocation if requested. 8871 CONVERT_BOOLEAN_ARG_CHECKED(inline_allocation, 2); 8872 if (inline_allocation) { 8873 isolate->heap()->EnableInlineAllocation(); 8874 } else { 8875 isolate->heap()->DisableInlineAllocation(); 8876 } 8877 } 8878 #endif 8879 return isolate->heap()->undefined_value(); 8880 } 8881 8882 8883 RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) { 8884 SealHandleScope shs(isolate); 8885 ASSERT(args.length() == 0); 8886 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8887 return isolate->heap()->undefined_value(); 8888 } 8889 8890 8891 RUNTIME_FUNCTION(Runtime_GetRootNaN) { 8892 SealHandleScope shs(isolate); 8893 ASSERT(args.length() == 0); 8894 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8895 return isolate->heap()->nan_value(); 8896 } 8897 8898 8899 RUNTIME_FUNCTION(Runtime_Call) { 8900 HandleScope scope(isolate); 8901 ASSERT(args.length() >= 2); 8902 int argc = args.length() - 2; 8903 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1); 8904 Object* receiver = args[0]; 8905 8906 // If there are too many arguments, allocate argv via malloc. 8907 const int argv_small_size = 10; 8908 Handle<Object> argv_small_buffer[argv_small_size]; 8909 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8910 Handle<Object>* argv = argv_small_buffer; 8911 if (argc > argv_small_size) { 8912 argv = new Handle<Object>[argc]; 8913 if (argv == NULL) return isolate->StackOverflow(); 8914 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8915 } 8916 8917 for (int i = 0; i < argc; ++i) { 8918 argv[i] = Handle<Object>(args[1 + i], isolate); 8919 } 8920 8921 Handle<JSReceiver> hfun(fun); 8922 Handle<Object> hreceiver(receiver, isolate); 8923 Handle<Object> result; 8924 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 8925 isolate, result, 8926 Execution::Call(isolate, hfun, hreceiver, argc, argv, true)); 8927 return *result; 8928 } 8929 8930 8931 RUNTIME_FUNCTION(Runtime_Apply) { 8932 HandleScope scope(isolate); 8933 ASSERT(args.length() == 5); 8934 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); 8935 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); 8936 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); 8937 CONVERT_SMI_ARG_CHECKED(offset, 3); 8938 CONVERT_SMI_ARG_CHECKED(argc, 4); 8939 RUNTIME_ASSERT(offset >= 0); 8940 // Loose upper bound to allow fuzzing. We'll most likely run out of 8941 // stack space before hitting this limit. 8942 static int kMaxArgc = 1000000; 8943 RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc); 8944 8945 // If there are too many arguments, allocate argv via malloc. 8946 const int argv_small_size = 10; 8947 Handle<Object> argv_small_buffer[argv_small_size]; 8948 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8949 Handle<Object>* argv = argv_small_buffer; 8950 if (argc > argv_small_size) { 8951 argv = new Handle<Object>[argc]; 8952 if (argv == NULL) return isolate->StackOverflow(); 8953 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8954 } 8955 8956 for (int i = 0; i < argc; ++i) { 8957 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 8958 isolate, argv[i], 8959 Object::GetElement(isolate, arguments, offset + i)); 8960 } 8961 8962 Handle<Object> result; 8963 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 8964 isolate, result, 8965 Execution::Call(isolate, fun, receiver, argc, argv, true)); 8966 return *result; 8967 } 8968 8969 8970 RUNTIME_FUNCTION(Runtime_GetFunctionDelegate) { 8971 HandleScope scope(isolate); 8972 ASSERT(args.length() == 1); 8973 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 8974 RUNTIME_ASSERT(!object->IsJSFunction()); 8975 return *Execution::GetFunctionDelegate(isolate, object); 8976 } 8977 8978 8979 RUNTIME_FUNCTION(Runtime_GetConstructorDelegate) { 8980 HandleScope scope(isolate); 8981 ASSERT(args.length() == 1); 8982 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 8983 RUNTIME_ASSERT(!object->IsJSFunction()); 8984 return *Execution::GetConstructorDelegate(isolate, object); 8985 } 8986 8987 8988 RUNTIME_FUNCTION(RuntimeHidden_NewGlobalContext) { 8989 HandleScope scope(isolate); 8990 ASSERT(args.length() == 2); 8991 8992 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8993 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); 8994 Handle<Context> result = 8995 isolate->factory()->NewGlobalContext(function, scope_info); 8996 8997 ASSERT(function->context() == isolate->context()); 8998 ASSERT(function->context()->global_object() == result->global_object()); 8999 result->global_object()->set_global_context(*result); 9000 return *result; 9001 } 9002 9003 9004 RUNTIME_FUNCTION(RuntimeHidden_NewFunctionContext) { 9005 HandleScope scope(isolate); 9006 ASSERT(args.length() == 1); 9007 9008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 9009 int length = function->shared()->scope_info()->ContextLength(); 9010 return *isolate->factory()->NewFunctionContext(length, function); 9011 } 9012 9013 9014 RUNTIME_FUNCTION(RuntimeHidden_PushWithContext) { 9015 HandleScope scope(isolate); 9016 ASSERT(args.length() == 2); 9017 Handle<JSReceiver> extension_object; 9018 if (args[0]->IsJSReceiver()) { 9019 extension_object = args.at<JSReceiver>(0); 9020 } else { 9021 // Try to convert the object to a proper JavaScript object. 9022 MaybeHandle<JSReceiver> maybe_object = 9023 Object::ToObject(isolate, args.at<Object>(0)); 9024 if (!maybe_object.ToHandle(&extension_object)) { 9025 Handle<Object> handle = args.at<Object>(0); 9026 Handle<Object> result = 9027 isolate->factory()->NewTypeError("with_expression", 9028 HandleVector(&handle, 1)); 9029 return isolate->Throw(*result); 9030 } 9031 } 9032 9033 Handle<JSFunction> function; 9034 if (args[1]->IsSmi()) { 9035 // A smi sentinel indicates a context nested inside global code rather 9036 // than some function. There is a canonical empty function that can be 9037 // gotten from the native context. 9038 function = handle(isolate->context()->native_context()->closure()); 9039 } else { 9040 function = args.at<JSFunction>(1); 9041 } 9042 9043 Handle<Context> current(isolate->context()); 9044 Handle<Context> context = isolate->factory()->NewWithContext( 9045 function, current, extension_object); 9046 isolate->set_context(*context); 9047 return *context; 9048 } 9049 9050 9051 RUNTIME_FUNCTION(RuntimeHidden_PushCatchContext) { 9052 HandleScope scope(isolate); 9053 ASSERT(args.length() == 3); 9054 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 9055 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1); 9056 Handle<JSFunction> function; 9057 if (args[2]->IsSmi()) { 9058 // A smi sentinel indicates a context nested inside global code rather 9059 // than some function. There is a canonical empty function that can be 9060 // gotten from the native context. 9061 function = handle(isolate->context()->native_context()->closure()); 9062 } else { 9063 function = args.at<JSFunction>(2); 9064 } 9065 Handle<Context> current(isolate->context()); 9066 Handle<Context> context = isolate->factory()->NewCatchContext( 9067 function, current, name, thrown_object); 9068 isolate->set_context(*context); 9069 return *context; 9070 } 9071 9072 9073 RUNTIME_FUNCTION(RuntimeHidden_PushBlockContext) { 9074 HandleScope scope(isolate); 9075 ASSERT(args.length() == 2); 9076 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0); 9077 Handle<JSFunction> function; 9078 if (args[1]->IsSmi()) { 9079 // A smi sentinel indicates a context nested inside global code rather 9080 // than some function. There is a canonical empty function that can be 9081 // gotten from the native context. 9082 function = handle(isolate->context()->native_context()->closure()); 9083 } else { 9084 function = args.at<JSFunction>(1); 9085 } 9086 Handle<Context> current(isolate->context()); 9087 Handle<Context> context = isolate->factory()->NewBlockContext( 9088 function, current, scope_info); 9089 isolate->set_context(*context); 9090 return *context; 9091 } 9092 9093 9094 RUNTIME_FUNCTION(Runtime_IsJSModule) { 9095 SealHandleScope shs(isolate); 9096 ASSERT(args.length() == 1); 9097 CONVERT_ARG_CHECKED(Object, obj, 0); 9098 return isolate->heap()->ToBoolean(obj->IsJSModule()); 9099 } 9100 9101 9102 RUNTIME_FUNCTION(RuntimeHidden_PushModuleContext) { 9103 SealHandleScope shs(isolate); 9104 ASSERT(args.length() == 2); 9105 CONVERT_SMI_ARG_CHECKED(index, 0); 9106 9107 if (!args[1]->IsScopeInfo()) { 9108 // Module already initialized. Find hosting context and retrieve context. 9109 Context* host = Context::cast(isolate->context())->global_context(); 9110 Context* context = Context::cast(host->get(index)); 9111 ASSERT(context->previous() == isolate->context()); 9112 isolate->set_context(context); 9113 return context; 9114 } 9115 9116 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); 9117 9118 // Allocate module context. 9119 HandleScope scope(isolate); 9120 Factory* factory = isolate->factory(); 9121 Handle<Context> context = factory->NewModuleContext(scope_info); 9122 Handle<JSModule> module = factory->NewJSModule(context, scope_info); 9123 context->set_module(*module); 9124 Context* previous = isolate->context(); 9125 context->set_previous(previous); 9126 context->set_closure(previous->closure()); 9127 context->set_global_object(previous->global_object()); 9128 isolate->set_context(*context); 9129 9130 // Find hosting scope and initialize internal variable holding module there. 9131 previous->global_context()->set(index, *context); 9132 9133 return *context; 9134 } 9135 9136 9137 RUNTIME_FUNCTION(RuntimeHidden_DeclareModules) { 9138 HandleScope scope(isolate); 9139 ASSERT(args.length() == 1); 9140 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); 9141 Context* host_context = isolate->context(); 9142 9143 for (int i = 0; i < descriptions->length(); ++i) { 9144 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i))); 9145 int host_index = description->host_index(); 9146 Handle<Context> context(Context::cast(host_context->get(host_index))); 9147 Handle<JSModule> module(context->module()); 9148 9149 for (int j = 0; j < description->length(); ++j) { 9150 Handle<String> name(description->name(j)); 9151 VariableMode mode = description->mode(j); 9152 int index = description->index(j); 9153 switch (mode) { 9154 case VAR: 9155 case LET: 9156 case CONST: 9157 case CONST_LEGACY: { 9158 PropertyAttributes attr = 9159 IsImmutableVariableMode(mode) ? FROZEN : SEALED; 9160 Handle<AccessorInfo> info = 9161 Accessors::MakeModuleExport(name, index, attr); 9162 Handle<Object> result = 9163 JSObject::SetAccessor(module, info).ToHandleChecked(); 9164 ASSERT(!result->IsUndefined()); 9165 USE(result); 9166 break; 9167 } 9168 case MODULE: { 9169 Object* referenced_context = Context::cast(host_context)->get(index); 9170 Handle<JSModule> value(Context::cast(referenced_context)->module()); 9171 JSReceiver::SetProperty(module, name, value, FROZEN, STRICT).Assert(); 9172 break; 9173 } 9174 case INTERNAL: 9175 case TEMPORARY: 9176 case DYNAMIC: 9177 case DYNAMIC_GLOBAL: 9178 case DYNAMIC_LOCAL: 9179 UNREACHABLE(); 9180 } 9181 } 9182 9183 JSObject::PreventExtensions(module).Assert(); 9184 } 9185 9186 ASSERT(!isolate->has_pending_exception()); 9187 return isolate->heap()->undefined_value(); 9188 } 9189 9190 9191 RUNTIME_FUNCTION(RuntimeHidden_DeleteContextSlot) { 9192 HandleScope scope(isolate); 9193 ASSERT(args.length() == 2); 9194 9195 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 9196 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 9197 9198 int index; 9199 PropertyAttributes attributes; 9200 ContextLookupFlags flags = FOLLOW_CHAINS; 9201 BindingFlags binding_flags; 9202 Handle<Object> holder = context->Lookup(name, 9203 flags, 9204 &index, 9205 &attributes, 9206 &binding_flags); 9207 9208 // If the slot was not found the result is true. 9209 if (holder.is_null()) { 9210 return isolate->heap()->true_value(); 9211 } 9212 9213 // If the slot was found in a context, it should be DONT_DELETE. 9214 if (holder->IsContext()) { 9215 return isolate->heap()->false_value(); 9216 } 9217 9218 // The slot was found in a JSObject, either a context extension object, 9219 // the global object, or the subject of a with. Try to delete it 9220 // (respecting DONT_DELETE). 9221 Handle<JSObject> object = Handle<JSObject>::cast(holder); 9222 Handle<Object> result; 9223 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 9224 isolate, result, 9225 JSReceiver::DeleteProperty(object, name)); 9226 return *result; 9227 } 9228 9229 9230 // A mechanism to return a pair of Object pointers in registers (if possible). 9231 // How this is achieved is calling convention-dependent. 9232 // All currently supported x86 compiles uses calling conventions that are cdecl 9233 // variants where a 64-bit value is returned in two 32-bit registers 9234 // (edx:eax on ia32, r1:r0 on ARM). 9235 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 9236 // In Win64 calling convention, a struct of two pointers is returned in memory, 9237 // allocated by the caller, and passed as a pointer in a hidden first parameter. 9238 #ifdef V8_HOST_ARCH_64_BIT 9239 struct ObjectPair { 9240 Object* x; 9241 Object* y; 9242 }; 9243 9244 9245 static inline ObjectPair MakePair(Object* x, Object* y) { 9246 ObjectPair result = {x, y}; 9247 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 9248 // In Win64 they are assigned to a hidden first argument. 9249 return result; 9250 } 9251 #else 9252 typedef uint64_t ObjectPair; 9253 static inline ObjectPair MakePair(Object* x, Object* y) { 9254 #if defined(V8_TARGET_LITTLE_ENDIAN) 9255 return reinterpret_cast<uint32_t>(x) | 9256 (reinterpret_cast<ObjectPair>(y) << 32); 9257 #elif defined(V8_TARGET_BIG_ENDIAN) 9258 return reinterpret_cast<uint32_t>(y) | 9259 (reinterpret_cast<ObjectPair>(x) << 32); 9260 #else 9261 #error Unknown endianness 9262 #endif 9263 } 9264 #endif 9265 9266 9267 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, 9268 JSObject* holder) { 9269 ASSERT(!holder->IsGlobalObject()); 9270 Context* top = isolate->context(); 9271 // Get the context extension function. 9272 JSFunction* context_extension_function = 9273 top->native_context()->context_extension_function(); 9274 // If the holder isn't a context extension object, we just return it 9275 // as the receiver. This allows arguments objects to be used as 9276 // receivers, but only if they are put in the context scope chain 9277 // explicitly via a with-statement. 9278 Object* constructor = holder->map()->constructor(); 9279 if (constructor != context_extension_function) return holder; 9280 // Fall back to using the global object as the implicit receiver if 9281 // the property turns out to be a local variable allocated in a 9282 // context extension object - introduced via eval. 9283 return isolate->heap()->undefined_value(); 9284 } 9285 9286 9287 static ObjectPair LoadContextSlotHelper(Arguments args, 9288 Isolate* isolate, 9289 bool throw_error) { 9290 HandleScope scope(isolate); 9291 ASSERT_EQ(2, args.length()); 9292 9293 if (!args[0]->IsContext() || !args[1]->IsString()) { 9294 return MakePair(isolate->ThrowIllegalOperation(), NULL); 9295 } 9296 Handle<Context> context = args.at<Context>(0); 9297 Handle<String> name = args.at<String>(1); 9298 9299 int index; 9300 PropertyAttributes attributes; 9301 ContextLookupFlags flags = FOLLOW_CHAINS; 9302 BindingFlags binding_flags; 9303 Handle<Object> holder = context->Lookup(name, 9304 flags, 9305 &index, 9306 &attributes, 9307 &binding_flags); 9308 if (isolate->has_pending_exception()) { 9309 return MakePair(isolate->heap()->exception(), NULL); 9310 } 9311 9312 // If the index is non-negative, the slot has been found in a context. 9313 if (index >= 0) { 9314 ASSERT(holder->IsContext()); 9315 // If the "property" we were looking for is a local variable, the 9316 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. 9317 Handle<Object> receiver = isolate->factory()->undefined_value(); 9318 Object* value = Context::cast(*holder)->get(index); 9319 // Check for uninitialized bindings. 9320 switch (binding_flags) { 9321 case MUTABLE_CHECK_INITIALIZED: 9322 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: 9323 if (value->IsTheHole()) { 9324 Handle<Object> reference_error = 9325 isolate->factory()->NewReferenceError("not_defined", 9326 HandleVector(&name, 1)); 9327 return MakePair(isolate->Throw(*reference_error), NULL); 9328 } 9329 // FALLTHROUGH 9330 case MUTABLE_IS_INITIALIZED: 9331 case IMMUTABLE_IS_INITIALIZED: 9332 case IMMUTABLE_IS_INITIALIZED_HARMONY: 9333 ASSERT(!value->IsTheHole()); 9334 return MakePair(value, *receiver); 9335 case IMMUTABLE_CHECK_INITIALIZED: 9336 if (value->IsTheHole()) { 9337 ASSERT((attributes & READ_ONLY) != 0); 9338 value = isolate->heap()->undefined_value(); 9339 } 9340 return MakePair(value, *receiver); 9341 case MISSING_BINDING: 9342 UNREACHABLE(); 9343 return MakePair(NULL, NULL); 9344 } 9345 } 9346 9347 // Otherwise, if the slot was found the holder is a context extension 9348 // object, subject of a with, or a global object. We read the named 9349 // property from it. 9350 if (!holder.is_null()) { 9351 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); 9352 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name)); 9353 // GetProperty below can cause GC. 9354 Handle<Object> receiver_handle( 9355 object->IsGlobalObject() 9356 ? Object::cast(isolate->heap()->undefined_value()) 9357 : object->IsJSProxy() ? static_cast<Object*>(*object) 9358 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)), 9359 isolate); 9360 9361 // No need to unhole the value here. This is taken care of by the 9362 // GetProperty function. 9363 Handle<Object> value; 9364 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9365 isolate, value, 9366 Object::GetProperty(object, name), 9367 MakePair(isolate->heap()->exception(), NULL)); 9368 return MakePair(*value, *receiver_handle); 9369 } 9370 9371 if (throw_error) { 9372 // The property doesn't exist - throw exception. 9373 Handle<Object> reference_error = 9374 isolate->factory()->NewReferenceError("not_defined", 9375 HandleVector(&name, 1)); 9376 return MakePair(isolate->Throw(*reference_error), NULL); 9377 } else { 9378 // The property doesn't exist - return undefined. 9379 return MakePair(isolate->heap()->undefined_value(), 9380 isolate->heap()->undefined_value()); 9381 } 9382 } 9383 9384 9385 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlot) { 9386 return LoadContextSlotHelper(args, isolate, true); 9387 } 9388 9389 9390 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_LoadContextSlotNoReferenceError) { 9391 return LoadContextSlotHelper(args, isolate, false); 9392 } 9393 9394 9395 RUNTIME_FUNCTION(RuntimeHidden_StoreContextSlot) { 9396 HandleScope scope(isolate); 9397 ASSERT(args.length() == 4); 9398 9399 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0); 9400 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); 9401 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); 9402 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3); 9403 9404 int index; 9405 PropertyAttributes attributes; 9406 ContextLookupFlags flags = FOLLOW_CHAINS; 9407 BindingFlags binding_flags; 9408 Handle<Object> holder = context->Lookup(name, 9409 flags, 9410 &index, 9411 &attributes, 9412 &binding_flags); 9413 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 9414 9415 if (index >= 0) { 9416 // The property was found in a context slot. 9417 Handle<Context> context = Handle<Context>::cast(holder); 9418 if (binding_flags == MUTABLE_CHECK_INITIALIZED && 9419 context->get(index)->IsTheHole()) { 9420 Handle<Object> error = 9421 isolate->factory()->NewReferenceError("not_defined", 9422 HandleVector(&name, 1)); 9423 return isolate->Throw(*error); 9424 } 9425 // Ignore if read_only variable. 9426 if ((attributes & READ_ONLY) == 0) { 9427 // Context is a fixed array and set cannot fail. 9428 context->set(index, *value); 9429 } else if (strict_mode == STRICT) { 9430 // Setting read only property in strict mode. 9431 Handle<Object> error = 9432 isolate->factory()->NewTypeError("strict_cannot_assign", 9433 HandleVector(&name, 1)); 9434 return isolate->Throw(*error); 9435 } 9436 return *value; 9437 } 9438 9439 // Slow case: The property is not in a context slot. It is either in a 9440 // context extension object, a property of the subject of a with, or a 9441 // property of the global object. 9442 Handle<JSReceiver> object; 9443 9444 if (!holder.is_null()) { 9445 // The property exists on the holder. 9446 object = Handle<JSReceiver>::cast(holder); 9447 } else { 9448 // The property was not found. 9449 ASSERT(attributes == ABSENT); 9450 9451 if (strict_mode == STRICT) { 9452 // Throw in strict mode (assignment to undefined variable). 9453 Handle<Object> error = 9454 isolate->factory()->NewReferenceError( 9455 "not_defined", HandleVector(&name, 1)); 9456 return isolate->Throw(*error); 9457 } 9458 // In sloppy mode, the property is added to the global object. 9459 attributes = NONE; 9460 object = Handle<JSReceiver>(isolate->context()->global_object()); 9461 } 9462 9463 // Set the property if it's not read only or doesn't yet exist. 9464 if ((attributes & READ_ONLY) == 0 || 9465 (JSReceiver::GetOwnPropertyAttributes(object, name) == ABSENT)) { 9466 RETURN_FAILURE_ON_EXCEPTION( 9467 isolate, 9468 JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); 9469 } else if (strict_mode == STRICT && (attributes & READ_ONLY) != 0) { 9470 // Setting read only property in strict mode. 9471 Handle<Object> error = 9472 isolate->factory()->NewTypeError( 9473 "strict_cannot_assign", HandleVector(&name, 1)); 9474 return isolate->Throw(*error); 9475 } 9476 return *value; 9477 } 9478 9479 9480 RUNTIME_FUNCTION(RuntimeHidden_Throw) { 9481 HandleScope scope(isolate); 9482 ASSERT(args.length() == 1); 9483 9484 return isolate->Throw(args[0]); 9485 } 9486 9487 9488 RUNTIME_FUNCTION(RuntimeHidden_ReThrow) { 9489 HandleScope scope(isolate); 9490 ASSERT(args.length() == 1); 9491 9492 return isolate->ReThrow(args[0]); 9493 } 9494 9495 9496 RUNTIME_FUNCTION(RuntimeHidden_PromoteScheduledException) { 9497 SealHandleScope shs(isolate); 9498 ASSERT(args.length() == 0); 9499 return isolate->PromoteScheduledException(); 9500 } 9501 9502 9503 RUNTIME_FUNCTION(RuntimeHidden_ThrowReferenceError) { 9504 HandleScope scope(isolate); 9505 ASSERT(args.length() == 1); 9506 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0); 9507 Handle<Object> reference_error = 9508 isolate->factory()->NewReferenceError("not_defined", 9509 HandleVector(&name, 1)); 9510 return isolate->Throw(*reference_error); 9511 } 9512 9513 9514 RUNTIME_FUNCTION(RuntimeHidden_ThrowNotDateError) { 9515 HandleScope scope(isolate); 9516 ASSERT(args.length() == 0); 9517 return isolate->Throw(*isolate->factory()->NewTypeError( 9518 "not_date_object", HandleVector<Object>(NULL, 0))); 9519 } 9520 9521 9522 RUNTIME_FUNCTION(RuntimeHidden_StackGuard) { 9523 SealHandleScope shs(isolate); 9524 ASSERT(args.length() == 0); 9525 9526 // First check if this is a real stack overflow. 9527 StackLimitCheck check(isolate); 9528 if (check.JsHasOverflowed()) { 9529 return isolate->StackOverflow(); 9530 } 9531 9532 return isolate->stack_guard()->HandleInterrupts(); 9533 } 9534 9535 9536 RUNTIME_FUNCTION(RuntimeHidden_TryInstallOptimizedCode) { 9537 HandleScope scope(isolate); 9538 ASSERT(args.length() == 1); 9539 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 9540 9541 // First check if this is a real stack overflow. 9542 StackLimitCheck check(isolate); 9543 if (check.JsHasOverflowed()) { 9544 SealHandleScope shs(isolate); 9545 return isolate->StackOverflow(); 9546 } 9547 9548 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 9549 return (function->IsOptimized()) ? function->code() 9550 : function->shared()->code(); 9551 } 9552 9553 9554 RUNTIME_FUNCTION(RuntimeHidden_Interrupt) { 9555 SealHandleScope shs(isolate); 9556 ASSERT(args.length() == 0); 9557 return isolate->stack_guard()->HandleInterrupts(); 9558 } 9559 9560 9561 static int StackSize(Isolate* isolate) { 9562 int n = 0; 9563 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; 9564 return n; 9565 } 9566 9567 9568 static void PrintTransition(Isolate* isolate, Object* result) { 9569 // indentation 9570 { const int nmax = 80; 9571 int n = StackSize(isolate); 9572 if (n <= nmax) 9573 PrintF("%4d:%*s", n, n, ""); 9574 else 9575 PrintF("%4d:%*s", n, nmax, "..."); 9576 } 9577 9578 if (result == NULL) { 9579 JavaScriptFrame::PrintTop(isolate, stdout, true, false); 9580 PrintF(" {\n"); 9581 } else { 9582 // function result 9583 PrintF("} -> "); 9584 result->ShortPrint(); 9585 PrintF("\n"); 9586 } 9587 } 9588 9589 9590 RUNTIME_FUNCTION(Runtime_TraceEnter) { 9591 SealHandleScope shs(isolate); 9592 ASSERT(args.length() == 0); 9593 PrintTransition(isolate, NULL); 9594 return isolate->heap()->undefined_value(); 9595 } 9596 9597 9598 RUNTIME_FUNCTION(Runtime_TraceExit) { 9599 SealHandleScope shs(isolate); 9600 ASSERT(args.length() == 1); 9601 CONVERT_ARG_CHECKED(Object, obj, 0); 9602 PrintTransition(isolate, obj); 9603 return obj; // return TOS 9604 } 9605 9606 9607 RUNTIME_FUNCTION(Runtime_DebugPrint) { 9608 SealHandleScope shs(isolate); 9609 ASSERT(args.length() == 1); 9610 9611 #ifdef DEBUG 9612 if (args[0]->IsString()) { 9613 // If we have a string, assume it's a code "marker" 9614 // and print some interesting cpu debugging info. 9615 JavaScriptFrameIterator it(isolate); 9616 JavaScriptFrame* frame = it.frame(); 9617 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 9618 frame->fp(), frame->sp(), frame->caller_sp()); 9619 } else { 9620 PrintF("DebugPrint: "); 9621 } 9622 args[0]->Print(); 9623 if (args[0]->IsHeapObject()) { 9624 PrintF("\n"); 9625 HeapObject::cast(args[0])->map()->Print(); 9626 } 9627 #else 9628 // ShortPrint is available in release mode. Print is not. 9629 args[0]->ShortPrint(); 9630 #endif 9631 PrintF("\n"); 9632 Flush(); 9633 9634 return args[0]; // return TOS 9635 } 9636 9637 9638 RUNTIME_FUNCTION(Runtime_DebugTrace) { 9639 SealHandleScope shs(isolate); 9640 ASSERT(args.length() == 0); 9641 isolate->PrintStack(stdout); 9642 return isolate->heap()->undefined_value(); 9643 } 9644 9645 9646 RUNTIME_FUNCTION(Runtime_DateCurrentTime) { 9647 HandleScope scope(isolate); 9648 ASSERT(args.length() == 0); 9649 if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent()); 9650 9651 // According to ECMA-262, section 15.9.1, page 117, the precision of 9652 // the number in a Date object representing a particular instant in 9653 // time is milliseconds. Therefore, we floor the result of getting 9654 // the OS time. 9655 double millis = std::floor(OS::TimeCurrentMillis()); 9656 return *isolate->factory()->NewNumber(millis); 9657 } 9658 9659 9660 RUNTIME_FUNCTION(Runtime_DateParseString) { 9661 HandleScope scope(isolate); 9662 ASSERT(args.length() == 2); 9663 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 9664 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); 9665 9666 RUNTIME_ASSERT(output->HasFastElements()); 9667 JSObject::EnsureCanContainHeapObjectElements(output); 9668 RUNTIME_ASSERT(output->HasFastObjectElements()); 9669 Handle<FixedArray> output_array(FixedArray::cast(output->elements())); 9670 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 9671 9672 str = String::Flatten(str); 9673 DisallowHeapAllocation no_gc; 9674 9675 bool result; 9676 String::FlatContent str_content = str->GetFlatContent(); 9677 if (str_content.IsAscii()) { 9678 result = DateParser::Parse(str_content.ToOneByteVector(), 9679 *output_array, 9680 isolate->unicode_cache()); 9681 } else { 9682 ASSERT(str_content.IsTwoByte()); 9683 result = DateParser::Parse(str_content.ToUC16Vector(), 9684 *output_array, 9685 isolate->unicode_cache()); 9686 } 9687 9688 if (result) { 9689 return *output; 9690 } else { 9691 return isolate->heap()->null_value(); 9692 } 9693 } 9694 9695 9696 RUNTIME_FUNCTION(Runtime_DateLocalTimezone) { 9697 HandleScope scope(isolate); 9698 ASSERT(args.length() == 1); 9699 9700 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9701 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && 9702 x <= DateCache::kMaxTimeBeforeUTCInMs); 9703 const char* zone = 9704 isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x)); 9705 Handle<String> result = isolate->factory()->NewStringFromUtf8( 9706 CStrVector(zone)).ToHandleChecked(); 9707 return *result; 9708 } 9709 9710 9711 RUNTIME_FUNCTION(Runtime_DateToUTC) { 9712 HandleScope scope(isolate); 9713 ASSERT(args.length() == 1); 9714 9715 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9716 RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs && 9717 x <= DateCache::kMaxTimeBeforeUTCInMs); 9718 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); 9719 9720 return *isolate->factory()->NewNumber(static_cast<double>(time)); 9721 } 9722 9723 9724 RUNTIME_FUNCTION(Runtime_DateCacheVersion) { 9725 HandleScope hs(isolate); 9726 ASSERT(args.length() == 0); 9727 if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) { 9728 Handle<FixedArray> date_cache_version = 9729 isolate->factory()->NewFixedArray(1, TENURED); 9730 date_cache_version->set(0, Smi::FromInt(0)); 9731 isolate->eternal_handles()->CreateSingleton( 9732 isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION); 9733 } 9734 Handle<FixedArray> date_cache_version = 9735 Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton( 9736 EternalHandles::DATE_CACHE_VERSION)); 9737 // Return result as a JS array. 9738 Handle<JSObject> result = 9739 isolate->factory()->NewJSObject(isolate->array_function()); 9740 JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version); 9741 return *result; 9742 } 9743 9744 9745 RUNTIME_FUNCTION(Runtime_GlobalReceiver) { 9746 SealHandleScope shs(isolate); 9747 ASSERT(args.length() == 1); 9748 CONVERT_ARG_CHECKED(Object, global, 0); 9749 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); 9750 return JSGlobalObject::cast(global)->global_receiver(); 9751 } 9752 9753 9754 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) { 9755 SealHandleScope shs(isolate); 9756 ASSERT(args.length() == 1); 9757 CONVERT_ARG_CHECKED(Object, global, 0); 9758 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); 9759 return isolate->heap()->ToBoolean( 9760 !JSGlobalObject::cast(global)->IsDetached()); 9761 } 9762 9763 9764 RUNTIME_FUNCTION(Runtime_ParseJson) { 9765 HandleScope scope(isolate); 9766 ASSERT(args.length() == 1); 9767 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9768 9769 source = String::Flatten(source); 9770 // Optimized fast case where we only have ASCII characters. 9771 Handle<Object> result; 9772 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 9773 isolate, result, 9774 source->IsSeqOneByteString() ? JsonParser<true>::Parse(source) 9775 : JsonParser<false>::Parse(source)); 9776 return *result; 9777 } 9778 9779 9780 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 9781 Handle<Context> context) { 9782 ASSERT(context->allow_code_gen_from_strings()->IsFalse()); 9783 // Check with callback if set. 9784 AllowCodeGenerationFromStringsCallback callback = 9785 isolate->allow_code_gen_callback(); 9786 if (callback == NULL) { 9787 // No callback set and code generation disallowed. 9788 return false; 9789 } else { 9790 // Callback set. Let it decide if code generation is allowed. 9791 VMState<EXTERNAL> state(isolate); 9792 return callback(v8::Utils::ToLocal(context)); 9793 } 9794 } 9795 9796 9797 // Walk up the stack expecting: 9798 // - Runtime_CompileString 9799 // - JSFunction callee (eval, Function constructor, etc) 9800 // - call() (maybe) 9801 // - apply() (maybe) 9802 // - bind() (maybe) 9803 // - JSFunction caller (maybe) 9804 // 9805 // return true if the caller has the same security token as the callee 9806 // or if an exit frame was hit, in which case allow it through, as it could 9807 // have come through the api. 9808 static bool TokensMatchForCompileString(Isolate* isolate) { 9809 MaybeHandle<JSFunction> callee; 9810 bool exit_handled = true; 9811 bool tokens_match = true; 9812 bool done = false; 9813 for (StackFrameIterator it(isolate); !it.done() && !done; it.Advance()) { 9814 StackFrame* raw_frame = it.frame(); 9815 if (!raw_frame->is_java_script()) { 9816 if (raw_frame->is_exit()) exit_handled = false; 9817 continue; 9818 } 9819 JavaScriptFrame* outer_frame = JavaScriptFrame::cast(raw_frame); 9820 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); 9821 outer_frame->Summarize(&frames); 9822 for (int i = frames.length() - 1; i >= 0 && !done; --i) { 9823 FrameSummary& frame = frames[i]; 9824 Handle<JSFunction> fun = frame.function(); 9825 // Capture the callee function. 9826 if (callee.is_null()) { 9827 callee = fun; 9828 exit_handled = true; 9829 continue; 9830 } 9831 // Exit condition. 9832 Handle<Context> context(callee.ToHandleChecked()->context()); 9833 if (!fun->context()->HasSameSecurityTokenAs(*context)) { 9834 tokens_match = false; 9835 done = true; 9836 continue; 9837 } 9838 // Skip bound functions in correct origin. 9839 if (fun->shared()->bound()) { 9840 exit_handled = true; 9841 continue; 9842 } 9843 done = true; 9844 } 9845 } 9846 return !exit_handled || tokens_match; 9847 } 9848 9849 9850 RUNTIME_FUNCTION(Runtime_CompileString) { 9851 HandleScope scope(isolate); 9852 ASSERT(args.length() == 2); 9853 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9854 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); 9855 9856 // Extract native context. 9857 Handle<Context> context(isolate->context()->native_context()); 9858 9859 // Filter cross security context calls. 9860 if (!TokensMatchForCompileString(isolate)) { 9861 return isolate->heap()->undefined_value(); 9862 } 9863 9864 // Check if native context allows code generation from 9865 // strings. Throw an exception if it doesn't. 9866 if (context->allow_code_gen_from_strings()->IsFalse() && 9867 !CodeGenerationFromStringsAllowed(isolate, context)) { 9868 Handle<Object> error_message = 9869 context->ErrorMessageForCodeGenerationFromStrings(); 9870 return isolate->Throw(*isolate->factory()->NewEvalError( 9871 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9872 } 9873 9874 // Compile source string in the native context. 9875 ParseRestriction restriction = function_literal_only 9876 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; 9877 Handle<JSFunction> fun; 9878 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 9879 isolate, fun, 9880 Compiler::GetFunctionFromEval( 9881 source, context, SLOPPY, restriction, RelocInfo::kNoPosition)); 9882 return *fun; 9883 } 9884 9885 9886 static ObjectPair CompileGlobalEval(Isolate* isolate, 9887 Handle<String> source, 9888 Handle<Object> receiver, 9889 StrictMode strict_mode, 9890 int scope_position) { 9891 Handle<Context> context = Handle<Context>(isolate->context()); 9892 Handle<Context> native_context = Handle<Context>(context->native_context()); 9893 9894 // Check if native context allows code generation from 9895 // strings. Throw an exception if it doesn't. 9896 if (native_context->allow_code_gen_from_strings()->IsFalse() && 9897 !CodeGenerationFromStringsAllowed(isolate, native_context)) { 9898 Handle<Object> error_message = 9899 native_context->ErrorMessageForCodeGenerationFromStrings(); 9900 isolate->Throw(*isolate->factory()->NewEvalError( 9901 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9902 return MakePair(isolate->heap()->exception(), NULL); 9903 } 9904 9905 // Deal with a normal eval call with a string argument. Compile it 9906 // and return the compiled function bound in the local context. 9907 static const ParseRestriction restriction = NO_PARSE_RESTRICTION; 9908 Handle<JSFunction> compiled; 9909 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 9910 isolate, compiled, 9911 Compiler::GetFunctionFromEval( 9912 source, context, strict_mode, restriction, scope_position), 9913 MakePair(isolate->heap()->exception(), NULL)); 9914 return MakePair(*compiled, *receiver); 9915 } 9916 9917 9918 RUNTIME_FUNCTION_RETURN_PAIR(RuntimeHidden_ResolvePossiblyDirectEval) { 9919 HandleScope scope(isolate); 9920 ASSERT(args.length() == 5); 9921 9922 Handle<Object> callee = args.at<Object>(0); 9923 9924 // If "eval" didn't refer to the original GlobalEval, it's not a 9925 // direct call to eval. 9926 // (And even if it is, but the first argument isn't a string, just let 9927 // execution default to an indirect call to eval, which will also return 9928 // the first argument without doing anything). 9929 if (*callee != isolate->native_context()->global_eval_fun() || 9930 !args[1]->IsString()) { 9931 return MakePair(*callee, isolate->heap()->undefined_value()); 9932 } 9933 9934 ASSERT(args[3]->IsSmi()); 9935 ASSERT(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT); 9936 StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3)); 9937 ASSERT(args[4]->IsSmi()); 9938 return CompileGlobalEval(isolate, 9939 args.at<String>(1), 9940 args.at<Object>(2), 9941 strict_mode, 9942 args.smi_at(4)); 9943 } 9944 9945 9946 RUNTIME_FUNCTION(RuntimeHidden_AllocateInNewSpace) { 9947 HandleScope scope(isolate); 9948 ASSERT(args.length() == 1); 9949 CONVERT_SMI_ARG_CHECKED(size, 0); 9950 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); 9951 RUNTIME_ASSERT(size > 0); 9952 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); 9953 return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE); 9954 } 9955 9956 9957 RUNTIME_FUNCTION(RuntimeHidden_AllocateInTargetSpace) { 9958 HandleScope scope(isolate); 9959 ASSERT(args.length() == 2); 9960 CONVERT_SMI_ARG_CHECKED(size, 0); 9961 CONVERT_SMI_ARG_CHECKED(flags, 1); 9962 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); 9963 RUNTIME_ASSERT(size > 0); 9964 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize); 9965 bool double_align = AllocateDoubleAlignFlag::decode(flags); 9966 AllocationSpace space = AllocateTargetSpace::decode(flags); 9967 return *isolate->factory()->NewFillerObject(size, double_align, space); 9968 } 9969 9970 9971 // Push an object unto an array of objects if it is not already in the 9972 // array. Returns true if the element was pushed on the stack and 9973 // false otherwise. 9974 RUNTIME_FUNCTION(Runtime_PushIfAbsent) { 9975 HandleScope scope(isolate); 9976 ASSERT(args.length() == 2); 9977 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 9978 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1); 9979 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements()); 9980 int length = Smi::cast(array->length())->value(); 9981 FixedArray* elements = FixedArray::cast(array->elements()); 9982 for (int i = 0; i < length; i++) { 9983 if (elements->get(i) == *element) return isolate->heap()->false_value(); 9984 } 9985 9986 // Strict not needed. Used for cycle detection in Array join implementation. 9987 RETURN_FAILURE_ON_EXCEPTION( 9988 isolate, 9989 JSObject::SetFastElement(array, length, element, SLOPPY, true)); 9990 return isolate->heap()->true_value(); 9991 } 9992 9993 9994 /** 9995 * A simple visitor visits every element of Array's. 9996 * The backend storage can be a fixed array for fast elements case, 9997 * or a dictionary for sparse array. Since Dictionary is a subtype 9998 * of FixedArray, the class can be used by both fast and slow cases. 9999 * The second parameter of the constructor, fast_elements, specifies 10000 * whether the storage is a FixedArray or Dictionary. 10001 * 10002 * An index limit is used to deal with the situation that a result array 10003 * length overflows 32-bit non-negative integer. 10004 */ 10005 class ArrayConcatVisitor { 10006 public: 10007 ArrayConcatVisitor(Isolate* isolate, 10008 Handle<FixedArray> storage, 10009 bool fast_elements) : 10010 isolate_(isolate), 10011 storage_(Handle<FixedArray>::cast( 10012 isolate->global_handles()->Create(*storage))), 10013 index_offset_(0u), 10014 fast_elements_(fast_elements), 10015 exceeds_array_limit_(false) { } 10016 10017 ~ArrayConcatVisitor() { 10018 clear_storage(); 10019 } 10020 10021 void visit(uint32_t i, Handle<Object> elm) { 10022 if (i > JSObject::kMaxElementCount - index_offset_) { 10023 exceeds_array_limit_ = true; 10024 return; 10025 } 10026 uint32_t index = index_offset_ + i; 10027 10028 if (fast_elements_) { 10029 if (index < static_cast<uint32_t>(storage_->length())) { 10030 storage_->set(index, *elm); 10031 return; 10032 } 10033 // Our initial estimate of length was foiled, possibly by 10034 // getters on the arrays increasing the length of later arrays 10035 // during iteration. 10036 // This shouldn't happen in anything but pathological cases. 10037 SetDictionaryMode(); 10038 // Fall-through to dictionary mode. 10039 } 10040 ASSERT(!fast_elements_); 10041 Handle<SeededNumberDictionary> dict( 10042 SeededNumberDictionary::cast(*storage_)); 10043 Handle<SeededNumberDictionary> result = 10044 SeededNumberDictionary::AtNumberPut(dict, index, elm); 10045 if (!result.is_identical_to(dict)) { 10046 // Dictionary needed to grow. 10047 clear_storage(); 10048 set_storage(*result); 10049 } 10050 } 10051 10052 void increase_index_offset(uint32_t delta) { 10053 if (JSObject::kMaxElementCount - index_offset_ < delta) { 10054 index_offset_ = JSObject::kMaxElementCount; 10055 } else { 10056 index_offset_ += delta; 10057 } 10058 // If the initial length estimate was off (see special case in visit()), 10059 // but the array blowing the limit didn't contain elements beyond the 10060 // provided-for index range, go to dictionary mode now. 10061 if (fast_elements_ && 10062 index_offset_ > 10063 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { 10064 SetDictionaryMode(); 10065 } 10066 } 10067 10068 bool exceeds_array_limit() { 10069 return exceeds_array_limit_; 10070 } 10071 10072 Handle<JSArray> ToArray() { 10073 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 10074 Handle<Object> length = 10075 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 10076 Handle<Map> map = JSObject::GetElementsTransitionMap( 10077 array, 10078 fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); 10079 array->set_map(*map); 10080 array->set_length(*length); 10081 array->set_elements(*storage_); 10082 return array; 10083 } 10084 10085 private: 10086 // Convert storage to dictionary mode. 10087 void SetDictionaryMode() { 10088 ASSERT(fast_elements_); 10089 Handle<FixedArray> current_storage(*storage_); 10090 Handle<SeededNumberDictionary> slow_storage( 10091 SeededNumberDictionary::New(isolate_, current_storage->length())); 10092 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 10093 for (uint32_t i = 0; i < current_length; i++) { 10094 HandleScope loop_scope(isolate_); 10095 Handle<Object> element(current_storage->get(i), isolate_); 10096 if (!element->IsTheHole()) { 10097 Handle<SeededNumberDictionary> new_storage = 10098 SeededNumberDictionary::AtNumberPut(slow_storage, i, element); 10099 if (!new_storage.is_identical_to(slow_storage)) { 10100 slow_storage = loop_scope.CloseAndEscape(new_storage); 10101 } 10102 } 10103 } 10104 clear_storage(); 10105 set_storage(*slow_storage); 10106 fast_elements_ = false; 10107 } 10108 10109 inline void clear_storage() { 10110 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); 10111 } 10112 10113 inline void set_storage(FixedArray* storage) { 10114 storage_ = Handle<FixedArray>::cast( 10115 isolate_->global_handles()->Create(storage)); 10116 } 10117 10118 Isolate* isolate_; 10119 Handle<FixedArray> storage_; // Always a global handle. 10120 // Index after last seen index. Always less than or equal to 10121 // JSObject::kMaxElementCount. 10122 uint32_t index_offset_; 10123 bool fast_elements_ : 1; 10124 bool exceeds_array_limit_ : 1; 10125 }; 10126 10127 10128 static uint32_t EstimateElementCount(Handle<JSArray> array) { 10129 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 10130 int element_count = 0; 10131 switch (array->GetElementsKind()) { 10132 case FAST_SMI_ELEMENTS: 10133 case FAST_HOLEY_SMI_ELEMENTS: 10134 case FAST_ELEMENTS: 10135 case FAST_HOLEY_ELEMENTS: { 10136 // Fast elements can't have lengths that are not representable by 10137 // a 32-bit signed integer. 10138 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); 10139 int fast_length = static_cast<int>(length); 10140 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 10141 for (int i = 0; i < fast_length; i++) { 10142 if (!elements->get(i)->IsTheHole()) element_count++; 10143 } 10144 break; 10145 } 10146 case FAST_DOUBLE_ELEMENTS: 10147 case FAST_HOLEY_DOUBLE_ELEMENTS: { 10148 // Fast elements can't have lengths that are not representable by 10149 // a 32-bit signed integer. 10150 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); 10151 int fast_length = static_cast<int>(length); 10152 if (array->elements()->IsFixedArray()) { 10153 ASSERT(FixedArray::cast(array->elements())->length() == 0); 10154 break; 10155 } 10156 Handle<FixedDoubleArray> elements( 10157 FixedDoubleArray::cast(array->elements())); 10158 for (int i = 0; i < fast_length; i++) { 10159 if (!elements->is_the_hole(i)) element_count++; 10160 } 10161 break; 10162 } 10163 case DICTIONARY_ELEMENTS: { 10164 Handle<SeededNumberDictionary> dictionary( 10165 SeededNumberDictionary::cast(array->elements())); 10166 int capacity = dictionary->Capacity(); 10167 for (int i = 0; i < capacity; i++) { 10168 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate()); 10169 if (dictionary->IsKey(*key)) { 10170 element_count++; 10171 } 10172 } 10173 break; 10174 } 10175 case SLOPPY_ARGUMENTS_ELEMENTS: 10176 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 10177 case EXTERNAL_##TYPE##_ELEMENTS: \ 10178 case TYPE##_ELEMENTS: \ 10179 10180 TYPED_ARRAYS(TYPED_ARRAY_CASE) 10181 #undef TYPED_ARRAY_CASE 10182 // External arrays are always dense. 10183 return length; 10184 } 10185 // As an estimate, we assume that the prototype doesn't contain any 10186 // inherited elements. 10187 return element_count; 10188 } 10189 10190 10191 10192 template<class ExternalArrayClass, class ElementType> 10193 static void IterateExternalArrayElements(Isolate* isolate, 10194 Handle<JSObject> receiver, 10195 bool elements_are_ints, 10196 bool elements_are_guaranteed_smis, 10197 ArrayConcatVisitor* visitor) { 10198 Handle<ExternalArrayClass> array( 10199 ExternalArrayClass::cast(receiver->elements())); 10200 uint32_t len = static_cast<uint32_t>(array->length()); 10201 10202 ASSERT(visitor != NULL); 10203 if (elements_are_ints) { 10204 if (elements_are_guaranteed_smis) { 10205 for (uint32_t j = 0; j < len; j++) { 10206 HandleScope loop_scope(isolate); 10207 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), 10208 isolate); 10209 visitor->visit(j, e); 10210 } 10211 } else { 10212 for (uint32_t j = 0; j < len; j++) { 10213 HandleScope loop_scope(isolate); 10214 int64_t val = static_cast<int64_t>(array->get_scalar(j)); 10215 if (Smi::IsValid(static_cast<intptr_t>(val))) { 10216 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); 10217 visitor->visit(j, e); 10218 } else { 10219 Handle<Object> e = 10220 isolate->factory()->NewNumber(static_cast<ElementType>(val)); 10221 visitor->visit(j, e); 10222 } 10223 } 10224 } 10225 } else { 10226 for (uint32_t j = 0; j < len; j++) { 10227 HandleScope loop_scope(isolate); 10228 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); 10229 visitor->visit(j, e); 10230 } 10231 } 10232 } 10233 10234 10235 // Used for sorting indices in a List<uint32_t>. 10236 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 10237 uint32_t a = *ap; 10238 uint32_t b = *bp; 10239 return (a == b) ? 0 : (a < b) ? -1 : 1; 10240 } 10241 10242 10243 static void CollectElementIndices(Handle<JSObject> object, 10244 uint32_t range, 10245 List<uint32_t>* indices) { 10246 Isolate* isolate = object->GetIsolate(); 10247 ElementsKind kind = object->GetElementsKind(); 10248 switch (kind) { 10249 case FAST_SMI_ELEMENTS: 10250 case FAST_ELEMENTS: 10251 case FAST_HOLEY_SMI_ELEMENTS: 10252 case FAST_HOLEY_ELEMENTS: { 10253 Handle<FixedArray> elements(FixedArray::cast(object->elements())); 10254 uint32_t length = static_cast<uint32_t>(elements->length()); 10255 if (range < length) length = range; 10256 for (uint32_t i = 0; i < length; i++) { 10257 if (!elements->get(i)->IsTheHole()) { 10258 indices->Add(i); 10259 } 10260 } 10261 break; 10262 } 10263 case FAST_HOLEY_DOUBLE_ELEMENTS: 10264 case FAST_DOUBLE_ELEMENTS: { 10265 // TODO(1810): Decide if it's worthwhile to implement this. 10266 UNREACHABLE(); 10267 break; 10268 } 10269 case DICTIONARY_ELEMENTS: { 10270 Handle<SeededNumberDictionary> dict( 10271 SeededNumberDictionary::cast(object->elements())); 10272 uint32_t capacity = dict->Capacity(); 10273 for (uint32_t j = 0; j < capacity; j++) { 10274 HandleScope loop_scope(isolate); 10275 Handle<Object> k(dict->KeyAt(j), isolate); 10276 if (dict->IsKey(*k)) { 10277 ASSERT(k->IsNumber()); 10278 uint32_t index = static_cast<uint32_t>(k->Number()); 10279 if (index < range) { 10280 indices->Add(index); 10281 } 10282 } 10283 } 10284 break; 10285 } 10286 default: { 10287 int dense_elements_length; 10288 switch (kind) { 10289 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 10290 case EXTERNAL_##TYPE##_ELEMENTS: { \ 10291 dense_elements_length = \ 10292 External##Type##Array::cast(object->elements())->length(); \ 10293 break; \ 10294 } 10295 10296 TYPED_ARRAYS(TYPED_ARRAY_CASE) 10297 #undef TYPED_ARRAY_CASE 10298 10299 default: 10300 UNREACHABLE(); 10301 dense_elements_length = 0; 10302 break; 10303 } 10304 uint32_t length = static_cast<uint32_t>(dense_elements_length); 10305 if (range <= length) { 10306 length = range; 10307 // We will add all indices, so we might as well clear it first 10308 // and avoid duplicates. 10309 indices->Clear(); 10310 } 10311 for (uint32_t i = 0; i < length; i++) { 10312 indices->Add(i); 10313 } 10314 if (length == range) return; // All indices accounted for already. 10315 break; 10316 } 10317 } 10318 10319 Handle<Object> prototype(object->GetPrototype(), isolate); 10320 if (prototype->IsJSObject()) { 10321 // The prototype will usually have no inherited element indices, 10322 // but we have to check. 10323 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); 10324 } 10325 } 10326 10327 10328 /** 10329 * A helper function that visits elements of a JSArray in numerical 10330 * order. 10331 * 10332 * The visitor argument called for each existing element in the array 10333 * with the element index and the element's value. 10334 * Afterwards it increments the base-index of the visitor by the array 10335 * length. 10336 * Returns false if any access threw an exception, otherwise true. 10337 */ 10338 static bool IterateElements(Isolate* isolate, 10339 Handle<JSArray> receiver, 10340 ArrayConcatVisitor* visitor) { 10341 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); 10342 switch (receiver->GetElementsKind()) { 10343 case FAST_SMI_ELEMENTS: 10344 case FAST_ELEMENTS: 10345 case FAST_HOLEY_SMI_ELEMENTS: 10346 case FAST_HOLEY_ELEMENTS: { 10347 // Run through the elements FixedArray and use HasElement and GetElement 10348 // to check the prototype for missing elements. 10349 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 10350 int fast_length = static_cast<int>(length); 10351 ASSERT(fast_length <= elements->length()); 10352 for (int j = 0; j < fast_length; j++) { 10353 HandleScope loop_scope(isolate); 10354 Handle<Object> element_value(elements->get(j), isolate); 10355 if (!element_value->IsTheHole()) { 10356 visitor->visit(j, element_value); 10357 } else if (JSReceiver::HasElement(receiver, j)) { 10358 // Call GetElement on receiver, not its prototype, or getters won't 10359 // have the correct receiver. 10360 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 10361 isolate, element_value, 10362 Object::GetElement(isolate, receiver, j), 10363 false); 10364 visitor->visit(j, element_value); 10365 } 10366 } 10367 break; 10368 } 10369 case FAST_HOLEY_DOUBLE_ELEMENTS: 10370 case FAST_DOUBLE_ELEMENTS: { 10371 // Empty array is FixedArray but not FixedDoubleArray. 10372 if (length == 0) break; 10373 // Run through the elements FixedArray and use HasElement and GetElement 10374 // to check the prototype for missing elements. 10375 if (receiver->elements()->IsFixedArray()) { 10376 ASSERT(receiver->elements()->length() == 0); 10377 break; 10378 } 10379 Handle<FixedDoubleArray> elements( 10380 FixedDoubleArray::cast(receiver->elements())); 10381 int fast_length = static_cast<int>(length); 10382 ASSERT(fast_length <= elements->length()); 10383 for (int j = 0; j < fast_length; j++) { 10384 HandleScope loop_scope(isolate); 10385 if (!elements->is_the_hole(j)) { 10386 double double_value = elements->get_scalar(j); 10387 Handle<Object> element_value = 10388 isolate->factory()->NewNumber(double_value); 10389 visitor->visit(j, element_value); 10390 } else if (JSReceiver::HasElement(receiver, j)) { 10391 // Call GetElement on receiver, not its prototype, or getters won't 10392 // have the correct receiver. 10393 Handle<Object> element_value; 10394 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 10395 isolate, element_value, 10396 Object::GetElement(isolate, receiver, j), 10397 false); 10398 visitor->visit(j, element_value); 10399 } 10400 } 10401 break; 10402 } 10403 case DICTIONARY_ELEMENTS: { 10404 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); 10405 List<uint32_t> indices(dict->Capacity() / 2); 10406 // Collect all indices in the object and the prototypes less 10407 // than length. This might introduce duplicates in the indices list. 10408 CollectElementIndices(receiver, length, &indices); 10409 indices.Sort(&compareUInt32); 10410 int j = 0; 10411 int n = indices.length(); 10412 while (j < n) { 10413 HandleScope loop_scope(isolate); 10414 uint32_t index = indices[j]; 10415 Handle<Object> element; 10416 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 10417 isolate, element, 10418 Object::GetElement(isolate, receiver, index), 10419 false); 10420 visitor->visit(index, element); 10421 // Skip to next different index (i.e., omit duplicates). 10422 do { 10423 j++; 10424 } while (j < n && indices[j] == index); 10425 } 10426 break; 10427 } 10428 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { 10429 Handle<ExternalUint8ClampedArray> pixels(ExternalUint8ClampedArray::cast( 10430 receiver->elements())); 10431 for (uint32_t j = 0; j < length; j++) { 10432 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); 10433 visitor->visit(j, e); 10434 } 10435 break; 10436 } 10437 case EXTERNAL_INT8_ELEMENTS: { 10438 IterateExternalArrayElements<ExternalInt8Array, int8_t>( 10439 isolate, receiver, true, true, visitor); 10440 break; 10441 } 10442 case EXTERNAL_UINT8_ELEMENTS: { 10443 IterateExternalArrayElements<ExternalUint8Array, uint8_t>( 10444 isolate, receiver, true, true, visitor); 10445 break; 10446 } 10447 case EXTERNAL_INT16_ELEMENTS: { 10448 IterateExternalArrayElements<ExternalInt16Array, int16_t>( 10449 isolate, receiver, true, true, visitor); 10450 break; 10451 } 10452 case EXTERNAL_UINT16_ELEMENTS: { 10453 IterateExternalArrayElements<ExternalUint16Array, uint16_t>( 10454 isolate, receiver, true, true, visitor); 10455 break; 10456 } 10457 case EXTERNAL_INT32_ELEMENTS: { 10458 IterateExternalArrayElements<ExternalInt32Array, int32_t>( 10459 isolate, receiver, true, false, visitor); 10460 break; 10461 } 10462 case EXTERNAL_UINT32_ELEMENTS: { 10463 IterateExternalArrayElements<ExternalUint32Array, uint32_t>( 10464 isolate, receiver, true, false, visitor); 10465 break; 10466 } 10467 case EXTERNAL_FLOAT32_ELEMENTS: { 10468 IterateExternalArrayElements<ExternalFloat32Array, float>( 10469 isolate, receiver, false, false, visitor); 10470 break; 10471 } 10472 case EXTERNAL_FLOAT64_ELEMENTS: { 10473 IterateExternalArrayElements<ExternalFloat64Array, double>( 10474 isolate, receiver, false, false, visitor); 10475 break; 10476 } 10477 default: 10478 UNREACHABLE(); 10479 break; 10480 } 10481 visitor->increase_index_offset(length); 10482 return true; 10483 } 10484 10485 10486 /** 10487 * Array::concat implementation. 10488 * See ECMAScript 262, 15.4.4.4. 10489 * TODO(581): Fix non-compliance for very large concatenations and update to 10490 * following the ECMAScript 5 specification. 10491 */ 10492 RUNTIME_FUNCTION(Runtime_ArrayConcat) { 10493 HandleScope handle_scope(isolate); 10494 ASSERT(args.length() == 1); 10495 10496 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); 10497 int argument_count = static_cast<int>(arguments->length()->Number()); 10498 RUNTIME_ASSERT(arguments->HasFastObjectElements()); 10499 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); 10500 10501 // Pass 1: estimate the length and number of elements of the result. 10502 // The actual length can be larger if any of the arguments have getters 10503 // that mutate other arguments (but will otherwise be precise). 10504 // The number of elements is precise if there are no inherited elements. 10505 10506 ElementsKind kind = FAST_SMI_ELEMENTS; 10507 10508 uint32_t estimate_result_length = 0; 10509 uint32_t estimate_nof_elements = 0; 10510 for (int i = 0; i < argument_count; i++) { 10511 HandleScope loop_scope(isolate); 10512 Handle<Object> obj(elements->get(i), isolate); 10513 uint32_t length_estimate; 10514 uint32_t element_estimate; 10515 if (obj->IsJSArray()) { 10516 Handle<JSArray> array(Handle<JSArray>::cast(obj)); 10517 length_estimate = static_cast<uint32_t>(array->length()->Number()); 10518 if (length_estimate != 0) { 10519 ElementsKind array_kind = 10520 GetPackedElementsKind(array->map()->elements_kind()); 10521 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { 10522 kind = array_kind; 10523 } 10524 } 10525 element_estimate = EstimateElementCount(array); 10526 } else { 10527 if (obj->IsHeapObject()) { 10528 if (obj->IsNumber()) { 10529 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { 10530 kind = FAST_DOUBLE_ELEMENTS; 10531 } 10532 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { 10533 kind = FAST_ELEMENTS; 10534 } 10535 } 10536 length_estimate = 1; 10537 element_estimate = 1; 10538 } 10539 // Avoid overflows by capping at kMaxElementCount. 10540 if (JSObject::kMaxElementCount - estimate_result_length < 10541 length_estimate) { 10542 estimate_result_length = JSObject::kMaxElementCount; 10543 } else { 10544 estimate_result_length += length_estimate; 10545 } 10546 if (JSObject::kMaxElementCount - estimate_nof_elements < 10547 element_estimate) { 10548 estimate_nof_elements = JSObject::kMaxElementCount; 10549 } else { 10550 estimate_nof_elements += element_estimate; 10551 } 10552 } 10553 10554 // If estimated number of elements is more than half of length, a 10555 // fixed array (fast case) is more time and space-efficient than a 10556 // dictionary. 10557 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; 10558 10559 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { 10560 Handle<FixedArrayBase> storage = 10561 isolate->factory()->NewFixedDoubleArray(estimate_result_length); 10562 int j = 0; 10563 if (estimate_result_length > 0) { 10564 Handle<FixedDoubleArray> double_storage = 10565 Handle<FixedDoubleArray>::cast(storage); 10566 bool failure = false; 10567 for (int i = 0; i < argument_count; i++) { 10568 Handle<Object> obj(elements->get(i), isolate); 10569 if (obj->IsSmi()) { 10570 double_storage->set(j, Smi::cast(*obj)->value()); 10571 j++; 10572 } else if (obj->IsNumber()) { 10573 double_storage->set(j, obj->Number()); 10574 j++; 10575 } else { 10576 JSArray* array = JSArray::cast(*obj); 10577 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 10578 switch (array->map()->elements_kind()) { 10579 case FAST_HOLEY_DOUBLE_ELEMENTS: 10580 case FAST_DOUBLE_ELEMENTS: { 10581 // Empty array is FixedArray but not FixedDoubleArray. 10582 if (length == 0) break; 10583 FixedDoubleArray* elements = 10584 FixedDoubleArray::cast(array->elements()); 10585 for (uint32_t i = 0; i < length; i++) { 10586 if (elements->is_the_hole(i)) { 10587 failure = true; 10588 break; 10589 } 10590 double double_value = elements->get_scalar(i); 10591 double_storage->set(j, double_value); 10592 j++; 10593 } 10594 break; 10595 } 10596 case FAST_HOLEY_SMI_ELEMENTS: 10597 case FAST_SMI_ELEMENTS: { 10598 FixedArray* elements( 10599 FixedArray::cast(array->elements())); 10600 for (uint32_t i = 0; i < length; i++) { 10601 Object* element = elements->get(i); 10602 if (element->IsTheHole()) { 10603 failure = true; 10604 break; 10605 } 10606 int32_t int_value = Smi::cast(element)->value(); 10607 double_storage->set(j, int_value); 10608 j++; 10609 } 10610 break; 10611 } 10612 case FAST_HOLEY_ELEMENTS: 10613 ASSERT_EQ(0, length); 10614 break; 10615 default: 10616 UNREACHABLE(); 10617 } 10618 } 10619 if (failure) break; 10620 } 10621 } 10622 Handle<JSArray> array = isolate->factory()->NewJSArray(0); 10623 Smi* length = Smi::FromInt(j); 10624 Handle<Map> map; 10625 map = JSObject::GetElementsTransitionMap(array, kind); 10626 array->set_map(*map); 10627 array->set_length(length); 10628 array->set_elements(*storage); 10629 return *array; 10630 } 10631 10632 Handle<FixedArray> storage; 10633 if (fast_case) { 10634 // The backing storage array must have non-existing elements to preserve 10635 // holes across concat operations. 10636 storage = isolate->factory()->NewFixedArrayWithHoles( 10637 estimate_result_length); 10638 } else { 10639 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 10640 uint32_t at_least_space_for = estimate_nof_elements + 10641 (estimate_nof_elements >> 2); 10642 storage = Handle<FixedArray>::cast( 10643 SeededNumberDictionary::New(isolate, at_least_space_for)); 10644 } 10645 10646 ArrayConcatVisitor visitor(isolate, storage, fast_case); 10647 10648 for (int i = 0; i < argument_count; i++) { 10649 Handle<Object> obj(elements->get(i), isolate); 10650 if (obj->IsJSArray()) { 10651 Handle<JSArray> array = Handle<JSArray>::cast(obj); 10652 if (!IterateElements(isolate, array, &visitor)) { 10653 return isolate->heap()->exception(); 10654 } 10655 } else { 10656 visitor.visit(0, obj); 10657 visitor.increase_index_offset(1); 10658 } 10659 } 10660 10661 if (visitor.exceeds_array_limit()) { 10662 return isolate->Throw( 10663 *isolate->factory()->NewRangeError("invalid_array_length", 10664 HandleVector<Object>(NULL, 0))); 10665 } 10666 return *visitor.ToArray(); 10667 } 10668 10669 10670 // This will not allocate (flatten the string), but it may run 10671 // very slowly for very deeply nested ConsStrings. For debugging use only. 10672 RUNTIME_FUNCTION(Runtime_GlobalPrint) { 10673 SealHandleScope shs(isolate); 10674 ASSERT(args.length() == 1); 10675 10676 CONVERT_ARG_CHECKED(String, string, 0); 10677 ConsStringIteratorOp op; 10678 StringCharacterStream stream(string, &op); 10679 while (stream.HasMore()) { 10680 uint16_t character = stream.GetNext(); 10681 PrintF("%c", character); 10682 } 10683 return string; 10684 } 10685 10686 10687 // Moves all own elements of an object, that are below a limit, to positions 10688 // starting at zero. All undefined values are placed after non-undefined values, 10689 // and are followed by non-existing element. Does not change the length 10690 // property. 10691 // Returns the number of non-undefined elements collected. 10692 // Returns -1 if hole removal is not supported by this method. 10693 RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) { 10694 HandleScope scope(isolate); 10695 ASSERT(args.length() == 2); 10696 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 10697 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 10698 return *JSObject::PrepareElementsForSort(object, limit); 10699 } 10700 10701 10702 // Move contents of argument 0 (an array) to argument 1 (an array) 10703 RUNTIME_FUNCTION(Runtime_MoveArrayContents) { 10704 HandleScope scope(isolate); 10705 ASSERT(args.length() == 2); 10706 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0); 10707 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1); 10708 JSObject::ValidateElements(from); 10709 JSObject::ValidateElements(to); 10710 10711 Handle<FixedArrayBase> new_elements(from->elements()); 10712 ElementsKind from_kind = from->GetElementsKind(); 10713 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind); 10714 JSObject::SetMapAndElements(to, new_map, new_elements); 10715 to->set_length(from->length()); 10716 10717 JSObject::ResetElements(from); 10718 from->set_length(Smi::FromInt(0)); 10719 10720 JSObject::ValidateElements(to); 10721 return *to; 10722 } 10723 10724 10725 // How many elements does this object/array have? 10726 RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) { 10727 SealHandleScope shs(isolate); 10728 ASSERT(args.length() == 1); 10729 CONVERT_ARG_CHECKED(JSArray, object, 0); 10730 HeapObject* elements = object->elements(); 10731 if (elements->IsDictionary()) { 10732 int result = SeededNumberDictionary::cast(elements)->NumberOfElements(); 10733 return Smi::FromInt(result); 10734 } else { 10735 return object->length(); 10736 } 10737 } 10738 10739 10740 // Returns an array that tells you where in the [0, length) interval an array 10741 // might have elements. Can either return an array of keys (positive integers 10742 // or undefined) or a number representing the positive length of an interval 10743 // starting at index 0. 10744 // Intervals can span over some keys that are not in the object. 10745 RUNTIME_FUNCTION(Runtime_GetArrayKeys) { 10746 HandleScope scope(isolate); 10747 ASSERT(args.length() == 2); 10748 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); 10749 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 10750 if (array->elements()->IsDictionary()) { 10751 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); 10752 for (Handle<Object> p = array; 10753 !p->IsNull(); 10754 p = Handle<Object>(p->GetPrototype(isolate), isolate)) { 10755 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) { 10756 // Bail out if we find a proxy or interceptor, likely not worth 10757 // collecting keys in that case. 10758 return *isolate->factory()->NewNumberFromUint(length); 10759 } 10760 Handle<JSObject> current = Handle<JSObject>::cast(p); 10761 Handle<FixedArray> current_keys = 10762 isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE)); 10763 current->GetOwnElementKeys(*current_keys, NONE); 10764 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 10765 isolate, keys, FixedArray::UnionOfKeys(keys, current_keys)); 10766 } 10767 // Erase any keys >= length. 10768 // TODO(adamk): Remove this step when the contract of %GetArrayKeys 10769 // is changed to let this happen on the JS side. 10770 for (int i = 0; i < keys->length(); i++) { 10771 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); 10772 } 10773 return *isolate->factory()->NewJSArrayWithElements(keys); 10774 } else { 10775 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() || 10776 array->HasFastDoubleElements()); 10777 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); 10778 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); 10779 } 10780 } 10781 10782 10783 RUNTIME_FUNCTION(Runtime_LookupAccessor) { 10784 HandleScope scope(isolate); 10785 ASSERT(args.length() == 3); 10786 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 10787 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10788 CONVERT_SMI_ARG_CHECKED(flag, 2); 10789 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; 10790 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); 10791 Handle<Object> result; 10792 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 10793 isolate, result, 10794 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component)); 10795 return *result; 10796 } 10797 10798 10799 RUNTIME_FUNCTION(Runtime_DebugBreak) { 10800 SealHandleScope shs(isolate); 10801 ASSERT(args.length() == 0); 10802 isolate->debug()->HandleDebugBreak(); 10803 return isolate->heap()->undefined_value(); 10804 } 10805 10806 10807 // Helper functions for wrapping and unwrapping stack frame ids. 10808 static Smi* WrapFrameId(StackFrame::Id id) { 10809 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 10810 return Smi::FromInt(id >> 2); 10811 } 10812 10813 10814 static StackFrame::Id UnwrapFrameId(int wrapped) { 10815 return static_cast<StackFrame::Id>(wrapped << 2); 10816 } 10817 10818 10819 // Adds a JavaScript function as a debug event listener. 10820 // args[0]: debug event listener function to set or null or undefined for 10821 // clearing the event listener function 10822 // args[1]: object supplied during callback 10823 RUNTIME_FUNCTION(Runtime_SetDebugEventListener) { 10824 SealHandleScope shs(isolate); 10825 ASSERT(args.length() == 2); 10826 RUNTIME_ASSERT(args[0]->IsJSFunction() || 10827 args[0]->IsUndefined() || 10828 args[0]->IsNull()); 10829 CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0); 10830 CONVERT_ARG_HANDLE_CHECKED(Object, data, 1); 10831 isolate->debug()->SetEventListener(callback, data); 10832 10833 return isolate->heap()->undefined_value(); 10834 } 10835 10836 10837 RUNTIME_FUNCTION(Runtime_Break) { 10838 SealHandleScope shs(isolate); 10839 ASSERT(args.length() == 0); 10840 isolate->stack_guard()->RequestDebugBreak(); 10841 return isolate->heap()->undefined_value(); 10842 } 10843 10844 10845 static Handle<Object> DebugLookupResultValue(Isolate* isolate, 10846 Handle<Object> receiver, 10847 Handle<Name> name, 10848 LookupResult* result, 10849 bool* has_caught = NULL) { 10850 Handle<Object> value = isolate->factory()->undefined_value(); 10851 if (!result->IsFound()) return value; 10852 switch (result->type()) { 10853 case NORMAL: 10854 value = JSObject::GetNormalizedProperty( 10855 handle(result->holder(), isolate), result); 10856 break; 10857 case FIELD: 10858 value = JSObject::FastPropertyAt(handle(result->holder(), isolate), 10859 result->representation(), 10860 result->GetFieldIndex()); 10861 break; 10862 case CONSTANT: 10863 return handle(result->GetConstant(), isolate); 10864 case CALLBACKS: { 10865 Handle<Object> structure(result->GetCallbackObject(), isolate); 10866 ASSERT(!structure->IsForeign()); 10867 if (structure->IsAccessorInfo()) { 10868 MaybeHandle<Object> obj = JSObject::GetPropertyWithAccessor( 10869 receiver, name, handle(result->holder(), isolate), structure); 10870 if (!obj.ToHandle(&value)) { 10871 value = handle(isolate->pending_exception(), isolate); 10872 isolate->clear_pending_exception(); 10873 if (has_caught != NULL) *has_caught = true; 10874 return value; 10875 } 10876 } 10877 break; 10878 } 10879 case INTERCEPTOR: 10880 case HANDLER: 10881 break; 10882 case NONEXISTENT: 10883 UNREACHABLE(); 10884 break; 10885 } 10886 ASSERT(!value->IsTheHole() || result->IsReadOnly()); 10887 return value->IsTheHole() 10888 ? Handle<Object>::cast(isolate->factory()->undefined_value()) : value; 10889 } 10890 10891 10892 // Get debugger related details for an object property. 10893 // args[0]: object holding property 10894 // args[1]: name of the property 10895 // 10896 // The array returned contains the following information: 10897 // 0: Property value 10898 // 1: Property details 10899 // 2: Property value is exception 10900 // 3: Getter function if defined 10901 // 4: Setter function if defined 10902 // Items 2-4 are only filled if the property has either a getter or a setter 10903 // defined through __defineGetter__ and/or __defineSetter__. 10904 RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) { 10905 HandleScope scope(isolate); 10906 10907 ASSERT(args.length() == 2); 10908 10909 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10910 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10911 10912 // Make sure to set the current context to the context before the debugger was 10913 // entered (if the debugger is entered). The reason for switching context here 10914 // is that for some property lookups (accessors and interceptors) callbacks 10915 // into the embedding application can occour, and the embedding application 10916 // could have the assumption that its own native context is the current 10917 // context and not some internal debugger context. 10918 SaveContext save(isolate); 10919 if (isolate->debug()->in_debug_scope()) { 10920 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 10921 } 10922 10923 // Skip the global proxy as it has no properties and always delegates to the 10924 // real global object. 10925 if (obj->IsJSGlobalProxy()) { 10926 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 10927 } 10928 10929 10930 // Check if the name is trivially convertible to an index and get the element 10931 // if so. 10932 uint32_t index; 10933 if (name->AsArrayIndex(&index)) { 10934 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 10935 Handle<Object> element_or_char; 10936 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 10937 isolate, element_or_char, 10938 Runtime::GetElementOrCharAt(isolate, obj, index)); 10939 details->set(0, *element_or_char); 10940 details->set( 10941 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); 10942 return *isolate->factory()->NewJSArrayWithElements(details); 10943 } 10944 10945 // Find the number of objects making up this. 10946 int length = OwnPrototypeChainLength(*obj); 10947 10948 // Try own lookup on each of the objects. 10949 Handle<JSObject> jsproto = obj; 10950 for (int i = 0; i < length; i++) { 10951 LookupResult result(isolate); 10952 jsproto->LookupOwn(name, &result); 10953 if (result.IsFound()) { 10954 // LookupResult is not GC safe as it holds raw object pointers. 10955 // GC can happen later in this code so put the required fields into 10956 // local variables using handles when required for later use. 10957 Handle<Object> result_callback_obj; 10958 if (result.IsPropertyCallbacks()) { 10959 result_callback_obj = Handle<Object>(result.GetCallbackObject(), 10960 isolate); 10961 } 10962 10963 10964 bool has_caught = false; 10965 Handle<Object> value = DebugLookupResultValue( 10966 isolate, obj, name, &result, &has_caught); 10967 10968 // If the callback object is a fixed array then it contains JavaScript 10969 // getter and/or setter. 10970 bool has_js_accessors = result.IsPropertyCallbacks() && 10971 result_callback_obj->IsAccessorPair(); 10972 Handle<FixedArray> details = 10973 isolate->factory()->NewFixedArray(has_js_accessors ? 5 : 2); 10974 details->set(0, *value); 10975 details->set(1, result.GetPropertyDetails().AsSmi()); 10976 if (has_js_accessors) { 10977 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj); 10978 details->set(2, isolate->heap()->ToBoolean(has_caught)); 10979 details->set(3, accessors->GetComponent(ACCESSOR_GETTER)); 10980 details->set(4, accessors->GetComponent(ACCESSOR_SETTER)); 10981 } 10982 10983 return *isolate->factory()->NewJSArrayWithElements(details); 10984 } 10985 if (i < length - 1) { 10986 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 10987 } 10988 } 10989 10990 return isolate->heap()->undefined_value(); 10991 } 10992 10993 10994 RUNTIME_FUNCTION(Runtime_DebugGetProperty) { 10995 HandleScope scope(isolate); 10996 10997 ASSERT(args.length() == 2); 10998 10999 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 11000 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 11001 11002 LookupResult result(isolate); 11003 obj->Lookup(name, &result); 11004 return *DebugLookupResultValue(isolate, obj, name, &result); 11005 } 11006 11007 11008 // Return the property type calculated from the property details. 11009 // args[0]: smi with property details. 11010 RUNTIME_FUNCTION(Runtime_DebugPropertyTypeFromDetails) { 11011 SealHandleScope shs(isolate); 11012 ASSERT(args.length() == 1); 11013 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 11014 return Smi::FromInt(static_cast<int>(details.type())); 11015 } 11016 11017 11018 // Return the property attribute calculated from the property details. 11019 // args[0]: smi with property details. 11020 RUNTIME_FUNCTION(Runtime_DebugPropertyAttributesFromDetails) { 11021 SealHandleScope shs(isolate); 11022 ASSERT(args.length() == 1); 11023 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 11024 return Smi::FromInt(static_cast<int>(details.attributes())); 11025 } 11026 11027 11028 // Return the property insertion index calculated from the property details. 11029 // args[0]: smi with property details. 11030 RUNTIME_FUNCTION(Runtime_DebugPropertyIndexFromDetails) { 11031 SealHandleScope shs(isolate); 11032 ASSERT(args.length() == 1); 11033 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 11034 // TODO(verwaest): Depends on the type of details. 11035 return Smi::FromInt(details.dictionary_index()); 11036 } 11037 11038 11039 // Return property value from named interceptor. 11040 // args[0]: object 11041 // args[1]: property name 11042 RUNTIME_FUNCTION(Runtime_DebugNamedInterceptorPropertyValue) { 11043 HandleScope scope(isolate); 11044 ASSERT(args.length() == 2); 11045 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 11046 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 11047 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 11048 11049 Handle<Object> result; 11050 LookupIterator it(obj, name, obj); 11051 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 11052 isolate, result, JSObject::GetProperty(&it)); 11053 return *result; 11054 } 11055 11056 11057 // Return element value from indexed interceptor. 11058 // args[0]: object 11059 // args[1]: index 11060 RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) { 11061 HandleScope scope(isolate); 11062 ASSERT(args.length() == 2); 11063 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 11064 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 11065 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 11066 Handle<Object> result; 11067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 11068 isolate, result, JSObject::GetElementWithInterceptor(obj, obj, index)); 11069 return *result; 11070 } 11071 11072 11073 static bool CheckExecutionState(Isolate* isolate, int break_id) { 11074 return !isolate->debug()->debug_context().is_null() && 11075 isolate->debug()->break_id() != 0 && 11076 isolate->debug()->break_id() == break_id; 11077 } 11078 11079 11080 RUNTIME_FUNCTION(Runtime_CheckExecutionState) { 11081 SealHandleScope shs(isolate); 11082 ASSERT(args.length() == 1); 11083 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 11084 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 11085 return isolate->heap()->true_value(); 11086 } 11087 11088 11089 RUNTIME_FUNCTION(Runtime_GetFrameCount) { 11090 HandleScope scope(isolate); 11091 ASSERT(args.length() == 1); 11092 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 11093 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 11094 11095 // Count all frames which are relevant to debugging stack trace. 11096 int n = 0; 11097 StackFrame::Id id = isolate->debug()->break_frame_id(); 11098 if (id == StackFrame::NO_ID) { 11099 // If there is no JavaScript stack frame count is 0. 11100 return Smi::FromInt(0); 11101 } 11102 11103 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { 11104 n += it.frame()->GetInlineCount(); 11105 } 11106 return Smi::FromInt(n); 11107 } 11108 11109 11110 class FrameInspector { 11111 public: 11112 FrameInspector(JavaScriptFrame* frame, 11113 int inlined_jsframe_index, 11114 Isolate* isolate) 11115 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { 11116 // Calculate the deoptimized frame. 11117 if (frame->is_optimized()) { 11118 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( 11119 frame, inlined_jsframe_index, isolate); 11120 } 11121 has_adapted_arguments_ = frame_->has_adapted_arguments(); 11122 is_bottommost_ = inlined_jsframe_index == 0; 11123 is_optimized_ = frame_->is_optimized(); 11124 } 11125 11126 ~FrameInspector() { 11127 // Get rid of the calculated deoptimized frame if any. 11128 if (deoptimized_frame_ != NULL) { 11129 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, 11130 isolate_); 11131 } 11132 } 11133 11134 int GetParametersCount() { 11135 return is_optimized_ 11136 ? deoptimized_frame_->parameters_count() 11137 : frame_->ComputeParametersCount(); 11138 } 11139 int expression_count() { return deoptimized_frame_->expression_count(); } 11140 Object* GetFunction() { 11141 return is_optimized_ 11142 ? deoptimized_frame_->GetFunction() 11143 : frame_->function(); 11144 } 11145 Object* GetParameter(int index) { 11146 return is_optimized_ 11147 ? deoptimized_frame_->GetParameter(index) 11148 : frame_->GetParameter(index); 11149 } 11150 Object* GetExpression(int index) { 11151 return is_optimized_ 11152 ? deoptimized_frame_->GetExpression(index) 11153 : frame_->GetExpression(index); 11154 } 11155 int GetSourcePosition() { 11156 return is_optimized_ 11157 ? deoptimized_frame_->GetSourcePosition() 11158 : frame_->LookupCode()->SourcePosition(frame_->pc()); 11159 } 11160 bool IsConstructor() { 11161 return is_optimized_ && !is_bottommost_ 11162 ? deoptimized_frame_->HasConstructStub() 11163 : frame_->IsConstructor(); 11164 } 11165 11166 // To inspect all the provided arguments the frame might need to be 11167 // replaced with the arguments frame. 11168 void SetArgumentsFrame(JavaScriptFrame* frame) { 11169 ASSERT(has_adapted_arguments_); 11170 frame_ = frame; 11171 is_optimized_ = frame_->is_optimized(); 11172 ASSERT(!is_optimized_); 11173 } 11174 11175 private: 11176 JavaScriptFrame* frame_; 11177 DeoptimizedFrameInfo* deoptimized_frame_; 11178 Isolate* isolate_; 11179 bool is_optimized_; 11180 bool is_bottommost_; 11181 bool has_adapted_arguments_; 11182 11183 DISALLOW_COPY_AND_ASSIGN(FrameInspector); 11184 }; 11185 11186 11187 static const int kFrameDetailsFrameIdIndex = 0; 11188 static const int kFrameDetailsReceiverIndex = 1; 11189 static const int kFrameDetailsFunctionIndex = 2; 11190 static const int kFrameDetailsArgumentCountIndex = 3; 11191 static const int kFrameDetailsLocalCountIndex = 4; 11192 static const int kFrameDetailsSourcePositionIndex = 5; 11193 static const int kFrameDetailsConstructCallIndex = 6; 11194 static const int kFrameDetailsAtReturnIndex = 7; 11195 static const int kFrameDetailsFlagsIndex = 8; 11196 static const int kFrameDetailsFirstDynamicIndex = 9; 11197 11198 11199 static SaveContext* FindSavedContextForFrame(Isolate* isolate, 11200 JavaScriptFrame* frame) { 11201 SaveContext* save = isolate->save_context(); 11202 while (save != NULL && !save->IsBelowFrame(frame)) { 11203 save = save->prev(); 11204 } 11205 ASSERT(save != NULL); 11206 return save; 11207 } 11208 11209 11210 // Return an array with frame details 11211 // args[0]: number: break id 11212 // args[1]: number: frame index 11213 // 11214 // The array returned contains the following information: 11215 // 0: Frame id 11216 // 1: Receiver 11217 // 2: Function 11218 // 3: Argument count 11219 // 4: Local count 11220 // 5: Source position 11221 // 6: Constructor call 11222 // 7: Is at return 11223 // 8: Flags 11224 // Arguments name, value 11225 // Locals name, value 11226 // Return value if any 11227 RUNTIME_FUNCTION(Runtime_GetFrameDetails) { 11228 HandleScope scope(isolate); 11229 ASSERT(args.length() == 2); 11230 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 11231 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 11232 11233 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 11234 Heap* heap = isolate->heap(); 11235 11236 // Find the relevant frame with the requested index. 11237 StackFrame::Id id = isolate->debug()->break_frame_id(); 11238 if (id == StackFrame::NO_ID) { 11239 // If there are no JavaScript stack frames return undefined. 11240 return heap->undefined_value(); 11241 } 11242 11243 int count = 0; 11244 JavaScriptFrameIterator it(isolate, id); 11245 for (; !it.done(); it.Advance()) { 11246 if (index < count + it.frame()->GetInlineCount()) break; 11247 count += it.frame()->GetInlineCount(); 11248 } 11249 if (it.done()) return heap->undefined_value(); 11250 11251 bool is_optimized = it.frame()->is_optimized(); 11252 11253 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame. 11254 if (is_optimized) { 11255 inlined_jsframe_index = 11256 it.frame()->GetInlineCount() - (index - count) - 1; 11257 } 11258 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); 11259 11260 // Traverse the saved contexts chain to find the active context for the 11261 // selected frame. 11262 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); 11263 11264 // Get the frame id. 11265 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); 11266 11267 // Find source position in unoptimized code. 11268 int position = frame_inspector.GetSourcePosition(); 11269 11270 // Check for constructor frame. 11271 bool constructor = frame_inspector.IsConstructor(); 11272 11273 // Get scope info and read from it for local variable information. 11274 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11275 Handle<SharedFunctionInfo> shared(function->shared()); 11276 Handle<ScopeInfo> scope_info(shared->scope_info()); 11277 ASSERT(*scope_info != ScopeInfo::Empty(isolate)); 11278 11279 // Get the locals names and values into a temporary array. 11280 int local_count = scope_info->LocalCount(); 11281 for (int slot = 0; slot < scope_info->LocalCount(); ++slot) { 11282 // Hide compiler-introduced temporary variables, whether on the stack or on 11283 // the context. 11284 if (scope_info->LocalIsSynthetic(slot)) 11285 local_count--; 11286 } 11287 11288 Handle<FixedArray> locals = 11289 isolate->factory()->NewFixedArray(local_count * 2); 11290 11291 // Fill in the values of the locals. 11292 int local = 0; 11293 int i = 0; 11294 for (; i < scope_info->StackLocalCount(); ++i) { 11295 // Use the value from the stack. 11296 if (scope_info->LocalIsSynthetic(i)) 11297 continue; 11298 locals->set(local * 2, scope_info->LocalName(i)); 11299 locals->set(local * 2 + 1, frame_inspector.GetExpression(i)); 11300 local++; 11301 } 11302 if (local < local_count) { 11303 // Get the context containing declarations. 11304 Handle<Context> context( 11305 Context::cast(it.frame()->context())->declaration_context()); 11306 for (; i < scope_info->LocalCount(); ++i) { 11307 if (scope_info->LocalIsSynthetic(i)) 11308 continue; 11309 Handle<String> name(scope_info->LocalName(i)); 11310 VariableMode mode; 11311 InitializationFlag init_flag; 11312 locals->set(local * 2, *name); 11313 int context_slot_index = 11314 ScopeInfo::ContextSlotIndex(scope_info, name, &mode, &init_flag); 11315 Object* value = context->get(context_slot_index); 11316 locals->set(local * 2 + 1, value); 11317 local++; 11318 } 11319 } 11320 11321 // Check whether this frame is positioned at return. If not top 11322 // frame or if the frame is optimized it cannot be at a return. 11323 bool at_return = false; 11324 if (!is_optimized && index == 0) { 11325 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); 11326 } 11327 11328 // If positioned just before return find the value to be returned and add it 11329 // to the frame information. 11330 Handle<Object> return_value = isolate->factory()->undefined_value(); 11331 if (at_return) { 11332 StackFrameIterator it2(isolate); 11333 Address internal_frame_sp = NULL; 11334 while (!it2.done()) { 11335 if (it2.frame()->is_internal()) { 11336 internal_frame_sp = it2.frame()->sp(); 11337 } else { 11338 if (it2.frame()->is_java_script()) { 11339 if (it2.frame()->id() == it.frame()->id()) { 11340 // The internal frame just before the JavaScript frame contains the 11341 // value to return on top. A debug break at return will create an 11342 // internal frame to store the return value (eax/rax/r0) before 11343 // entering the debug break exit frame. 11344 if (internal_frame_sp != NULL) { 11345 return_value = 11346 Handle<Object>(Memory::Object_at(internal_frame_sp), 11347 isolate); 11348 break; 11349 } 11350 } 11351 } 11352 11353 // Indicate that the previous frame was not an internal frame. 11354 internal_frame_sp = NULL; 11355 } 11356 it2.Advance(); 11357 } 11358 } 11359 11360 // Now advance to the arguments adapter frame (if any). It contains all 11361 // the provided parameters whereas the function frame always have the number 11362 // of arguments matching the functions parameters. The rest of the 11363 // information (except for what is collected above) is the same. 11364 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { 11365 it.AdvanceToArgumentsFrame(); 11366 frame_inspector.SetArgumentsFrame(it.frame()); 11367 } 11368 11369 // Find the number of arguments to fill. At least fill the number of 11370 // parameters for the function and fill more if more parameters are provided. 11371 int argument_count = scope_info->ParameterCount(); 11372 if (argument_count < frame_inspector.GetParametersCount()) { 11373 argument_count = frame_inspector.GetParametersCount(); 11374 } 11375 11376 // Calculate the size of the result. 11377 int details_size = kFrameDetailsFirstDynamicIndex + 11378 2 * (argument_count + local_count) + 11379 (at_return ? 1 : 0); 11380 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 11381 11382 // Add the frame id. 11383 details->set(kFrameDetailsFrameIdIndex, *frame_id); 11384 11385 // Add the function (same as in function frame). 11386 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); 11387 11388 // Add the arguments count. 11389 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 11390 11391 // Add the locals count 11392 details->set(kFrameDetailsLocalCountIndex, 11393 Smi::FromInt(local_count)); 11394 11395 // Add the source position. 11396 if (position != RelocInfo::kNoPosition) { 11397 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 11398 } else { 11399 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 11400 } 11401 11402 // Add the constructor information. 11403 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 11404 11405 // Add the at return information. 11406 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 11407 11408 // Add flags to indicate information on whether this frame is 11409 // bit 0: invoked in the debugger context. 11410 // bit 1: optimized frame. 11411 // bit 2: inlined in optimized frame 11412 int flags = 0; 11413 if (*save->context() == *isolate->debug()->debug_context()) { 11414 flags |= 1 << 0; 11415 } 11416 if (is_optimized) { 11417 flags |= 1 << 1; 11418 flags |= inlined_jsframe_index << 2; 11419 } 11420 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 11421 11422 // Fill the dynamic part. 11423 int details_index = kFrameDetailsFirstDynamicIndex; 11424 11425 // Add arguments name and value. 11426 for (int i = 0; i < argument_count; i++) { 11427 // Name of the argument. 11428 if (i < scope_info->ParameterCount()) { 11429 details->set(details_index++, scope_info->ParameterName(i)); 11430 } else { 11431 details->set(details_index++, heap->undefined_value()); 11432 } 11433 11434 // Parameter value. 11435 if (i < frame_inspector.GetParametersCount()) { 11436 // Get the value from the stack. 11437 details->set(details_index++, frame_inspector.GetParameter(i)); 11438 } else { 11439 details->set(details_index++, heap->undefined_value()); 11440 } 11441 } 11442 11443 // Add locals name and value from the temporary copy from the function frame. 11444 for (int i = 0; i < local_count * 2; i++) { 11445 details->set(details_index++, locals->get(i)); 11446 } 11447 11448 // Add the value being returned. 11449 if (at_return) { 11450 details->set(details_index++, *return_value); 11451 } 11452 11453 // Add the receiver (same as in function frame). 11454 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 11455 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 11456 Handle<Object> receiver(it.frame()->receiver(), isolate); 11457 if (!receiver->IsJSObject() && 11458 shared->strict_mode() == SLOPPY && 11459 !function->IsBuiltin()) { 11460 // If the receiver is not a JSObject and the function is not a 11461 // builtin or strict-mode we have hit an optimization where a 11462 // value object is not converted into a wrapped JS objects. To 11463 // hide this optimization from the debugger, we wrap the receiver 11464 // by creating correct wrapper object based on the calling frame's 11465 // native context. 11466 it.Advance(); 11467 if (receiver->IsUndefined()) { 11468 Context* context = function->context(); 11469 receiver = handle(context->global_object()->global_receiver()); 11470 } else { 11471 ASSERT(!receiver->IsNull()); 11472 Context* context = Context::cast(it.frame()->context()); 11473 Handle<Context> native_context(Context::cast(context->native_context())); 11474 receiver = Object::ToObject( 11475 isolate, receiver, native_context).ToHandleChecked(); 11476 } 11477 } 11478 details->set(kFrameDetailsReceiverIndex, *receiver); 11479 11480 ASSERT_EQ(details_size, details_index); 11481 return *isolate->factory()->NewJSArrayWithElements(details); 11482 } 11483 11484 11485 static bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info, 11486 Handle<String> parameter_name) { 11487 VariableMode mode; 11488 InitializationFlag flag; 11489 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &flag) != -1; 11490 } 11491 11492 11493 // Create a plain JSObject which materializes the local scope for the specified 11494 // frame. 11495 MUST_USE_RESULT 11496 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( 11497 Isolate* isolate, 11498 Handle<JSObject> target, 11499 Handle<JSFunction> function, 11500 FrameInspector* frame_inspector) { 11501 Handle<SharedFunctionInfo> shared(function->shared()); 11502 Handle<ScopeInfo> scope_info(shared->scope_info()); 11503 11504 // First fill all parameters. 11505 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11506 // Do not materialize the parameter if it is shadowed by a context local. 11507 Handle<String> name(scope_info->ParameterName(i)); 11508 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; 11509 11510 HandleScope scope(isolate); 11511 Handle<Object> value(i < frame_inspector->GetParametersCount() 11512 ? frame_inspector->GetParameter(i) 11513 : isolate->heap()->undefined_value(), 11514 isolate); 11515 ASSERT(!value->IsTheHole()); 11516 11517 RETURN_ON_EXCEPTION( 11518 isolate, 11519 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY), 11520 JSObject); 11521 } 11522 11523 // Second fill all stack locals. 11524 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11525 if (scope_info->LocalIsSynthetic(i)) continue; 11526 Handle<String> name(scope_info->StackLocalName(i)); 11527 Handle<Object> value(frame_inspector->GetExpression(i), isolate); 11528 if (value->IsTheHole()) continue; 11529 11530 RETURN_ON_EXCEPTION( 11531 isolate, 11532 Runtime::SetObjectProperty(isolate, target, name, value, NONE, SLOPPY), 11533 JSObject); 11534 } 11535 11536 return target; 11537 } 11538 11539 11540 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, 11541 Handle<JSObject> target, 11542 Handle<JSFunction> function, 11543 JavaScriptFrame* frame, 11544 int inlined_jsframe_index) { 11545 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11546 // Optimized frames are not supported. 11547 // TODO(yangguo): make sure all code deoptimized when debugger is active 11548 // and assert that this cannot happen. 11549 return; 11550 } 11551 11552 Handle<SharedFunctionInfo> shared(function->shared()); 11553 Handle<ScopeInfo> scope_info(shared->scope_info()); 11554 11555 // Parameters. 11556 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11557 // Shadowed parameters were not materialized. 11558 Handle<String> name(scope_info->ParameterName(i)); 11559 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; 11560 11561 ASSERT(!frame->GetParameter(i)->IsTheHole()); 11562 HandleScope scope(isolate); 11563 Handle<Object> value = 11564 Object::GetPropertyOrElement(target, name).ToHandleChecked(); 11565 frame->SetParameterValue(i, *value); 11566 } 11567 11568 // Stack locals. 11569 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11570 if (scope_info->LocalIsSynthetic(i)) continue; 11571 if (frame->GetExpression(i)->IsTheHole()) continue; 11572 HandleScope scope(isolate); 11573 Handle<Object> value = Object::GetPropertyOrElement( 11574 target, 11575 handle(scope_info->StackLocalName(i), isolate)).ToHandleChecked(); 11576 frame->SetExpression(i, *value); 11577 } 11578 } 11579 11580 11581 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( 11582 Isolate* isolate, 11583 Handle<JSObject> target, 11584 Handle<JSFunction> function, 11585 JavaScriptFrame* frame) { 11586 HandleScope scope(isolate); 11587 Handle<SharedFunctionInfo> shared(function->shared()); 11588 Handle<ScopeInfo> scope_info(shared->scope_info()); 11589 11590 if (!scope_info->HasContext()) return target; 11591 11592 // Third fill all context locals. 11593 Handle<Context> frame_context(Context::cast(frame->context())); 11594 Handle<Context> function_context(frame_context->declaration_context()); 11595 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11596 scope_info, function_context, target)) { 11597 return MaybeHandle<JSObject>(); 11598 } 11599 11600 // Finally copy any properties from the function context extension. 11601 // These will be variables introduced by eval. 11602 if (function_context->closure() == *function) { 11603 if (function_context->has_extension() && 11604 !function_context->IsNativeContext()) { 11605 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11606 Handle<FixedArray> keys; 11607 ASSIGN_RETURN_ON_EXCEPTION( 11608 isolate, keys, 11609 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), 11610 JSObject); 11611 11612 for (int i = 0; i < keys->length(); i++) { 11613 // Names of variables introduced by eval are strings. 11614 ASSERT(keys->get(i)->IsString()); 11615 Handle<String> key(String::cast(keys->get(i))); 11616 Handle<Object> value; 11617 ASSIGN_RETURN_ON_EXCEPTION( 11618 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); 11619 RETURN_ON_EXCEPTION( 11620 isolate, 11621 Runtime::SetObjectProperty( 11622 isolate, target, key, value, NONE, SLOPPY), 11623 JSObject); 11624 } 11625 } 11626 } 11627 11628 return target; 11629 } 11630 11631 11632 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope( 11633 Isolate* isolate, 11634 JavaScriptFrame* frame, 11635 int inlined_jsframe_index) { 11636 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 11637 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11638 11639 Handle<JSObject> local_scope = 11640 isolate->factory()->NewJSObject(isolate->object_function()); 11641 ASSIGN_RETURN_ON_EXCEPTION( 11642 isolate, local_scope, 11643 MaterializeStackLocalsWithFrameInspector( 11644 isolate, local_scope, function, &frame_inspector), 11645 JSObject); 11646 11647 return MaterializeLocalContext(isolate, local_scope, function, frame); 11648 } 11649 11650 11651 // Set the context local variable value. 11652 static bool SetContextLocalValue(Isolate* isolate, 11653 Handle<ScopeInfo> scope_info, 11654 Handle<Context> context, 11655 Handle<String> variable_name, 11656 Handle<Object> new_value) { 11657 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { 11658 Handle<String> next_name(scope_info->ContextLocalName(i)); 11659 if (String::Equals(variable_name, next_name)) { 11660 VariableMode mode; 11661 InitializationFlag init_flag; 11662 int context_index = 11663 ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &init_flag); 11664 context->set(context_index, *new_value); 11665 return true; 11666 } 11667 } 11668 11669 return false; 11670 } 11671 11672 11673 static bool SetLocalVariableValue(Isolate* isolate, 11674 JavaScriptFrame* frame, 11675 int inlined_jsframe_index, 11676 Handle<String> variable_name, 11677 Handle<Object> new_value) { 11678 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11679 // Optimized frames are not supported. 11680 return false; 11681 } 11682 11683 Handle<JSFunction> function(frame->function()); 11684 Handle<SharedFunctionInfo> shared(function->shared()); 11685 Handle<ScopeInfo> scope_info(shared->scope_info()); 11686 11687 bool default_result = false; 11688 11689 // Parameters. 11690 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11691 HandleScope scope(isolate); 11692 if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) { 11693 frame->SetParameterValue(i, *new_value); 11694 // Argument might be shadowed in heap context, don't stop here. 11695 default_result = true; 11696 } 11697 } 11698 11699 // Stack locals. 11700 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11701 HandleScope scope(isolate); 11702 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { 11703 frame->SetExpression(i, *new_value); 11704 return true; 11705 } 11706 } 11707 11708 if (scope_info->HasContext()) { 11709 // Context locals. 11710 Handle<Context> frame_context(Context::cast(frame->context())); 11711 Handle<Context> function_context(frame_context->declaration_context()); 11712 if (SetContextLocalValue( 11713 isolate, scope_info, function_context, variable_name, new_value)) { 11714 return true; 11715 } 11716 11717 // Function context extension. These are variables introduced by eval. 11718 if (function_context->closure() == *function) { 11719 if (function_context->has_extension() && 11720 !function_context->IsNativeContext()) { 11721 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11722 11723 if (JSReceiver::HasProperty(ext, variable_name)) { 11724 // We don't expect this to do anything except replacing 11725 // property value. 11726 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, 11727 NONE, SLOPPY).Assert(); 11728 return true; 11729 } 11730 } 11731 } 11732 } 11733 11734 return default_result; 11735 } 11736 11737 11738 // Create a plain JSObject which materializes the closure content for the 11739 // context. 11740 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( 11741 Isolate* isolate, 11742 Handle<Context> context) { 11743 ASSERT(context->IsFunctionContext()); 11744 11745 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11746 Handle<ScopeInfo> scope_info(shared->scope_info()); 11747 11748 // Allocate and initialize a JSObject with all the content of this function 11749 // closure. 11750 Handle<JSObject> closure_scope = 11751 isolate->factory()->NewJSObject(isolate->object_function()); 11752 11753 // Fill all context locals to the context extension. 11754 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11755 scope_info, context, closure_scope)) { 11756 return MaybeHandle<JSObject>(); 11757 } 11758 11759 // Finally copy any properties from the function context extension. This will 11760 // be variables introduced by eval. 11761 if (context->has_extension()) { 11762 Handle<JSObject> ext(JSObject::cast(context->extension())); 11763 Handle<FixedArray> keys; 11764 ASSIGN_RETURN_ON_EXCEPTION( 11765 isolate, keys, 11766 JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS), JSObject); 11767 11768 for (int i = 0; i < keys->length(); i++) { 11769 HandleScope scope(isolate); 11770 // Names of variables introduced by eval are strings. 11771 ASSERT(keys->get(i)->IsString()); 11772 Handle<String> key(String::cast(keys->get(i))); 11773 Handle<Object> value; 11774 ASSIGN_RETURN_ON_EXCEPTION( 11775 isolate, value, Object::GetPropertyOrElement(ext, key), JSObject); 11776 RETURN_ON_EXCEPTION( 11777 isolate, 11778 Runtime::SetObjectProperty( 11779 isolate, closure_scope, key, value, NONE, SLOPPY), 11780 JSObject); 11781 } 11782 } 11783 11784 return closure_scope; 11785 } 11786 11787 11788 // This method copies structure of MaterializeClosure method above. 11789 static bool SetClosureVariableValue(Isolate* isolate, 11790 Handle<Context> context, 11791 Handle<String> variable_name, 11792 Handle<Object> new_value) { 11793 ASSERT(context->IsFunctionContext()); 11794 11795 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11796 Handle<ScopeInfo> scope_info(shared->scope_info()); 11797 11798 // Context locals to the context extension. 11799 if (SetContextLocalValue( 11800 isolate, scope_info, context, variable_name, new_value)) { 11801 return true; 11802 } 11803 11804 // Properties from the function context extension. This will 11805 // be variables introduced by eval. 11806 if (context->has_extension()) { 11807 Handle<JSObject> ext(JSObject::cast(context->extension())); 11808 if (JSReceiver::HasProperty(ext, variable_name)) { 11809 // We don't expect this to do anything except replacing property value. 11810 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, 11811 NONE, SLOPPY).Assert(); 11812 return true; 11813 } 11814 } 11815 11816 return false; 11817 } 11818 11819 11820 // Create a plain JSObject which materializes the scope for the specified 11821 // catch context. 11822 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeCatchScope( 11823 Isolate* isolate, 11824 Handle<Context> context) { 11825 ASSERT(context->IsCatchContext()); 11826 Handle<String> name(String::cast(context->extension())); 11827 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), 11828 isolate); 11829 Handle<JSObject> catch_scope = 11830 isolate->factory()->NewJSObject(isolate->object_function()); 11831 RETURN_ON_EXCEPTION( 11832 isolate, 11833 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object, 11834 NONE, SLOPPY), 11835 JSObject); 11836 return catch_scope; 11837 } 11838 11839 11840 static bool SetCatchVariableValue(Isolate* isolate, 11841 Handle<Context> context, 11842 Handle<String> variable_name, 11843 Handle<Object> new_value) { 11844 ASSERT(context->IsCatchContext()); 11845 Handle<String> name(String::cast(context->extension())); 11846 if (!String::Equals(name, variable_name)) { 11847 return false; 11848 } 11849 context->set(Context::THROWN_OBJECT_INDEX, *new_value); 11850 return true; 11851 } 11852 11853 11854 // Create a plain JSObject which materializes the block scope for the specified 11855 // block context. 11856 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( 11857 Isolate* isolate, 11858 Handle<Context> context) { 11859 ASSERT(context->IsBlockContext()); 11860 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11861 11862 // Allocate and initialize a JSObject with all the arguments, stack locals 11863 // heap locals and extension properties of the debugged function. 11864 Handle<JSObject> block_scope = 11865 isolate->factory()->NewJSObject(isolate->object_function()); 11866 11867 // Fill all context locals. 11868 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11869 scope_info, context, block_scope)) { 11870 return MaybeHandle<JSObject>(); 11871 } 11872 11873 return block_scope; 11874 } 11875 11876 11877 // Create a plain JSObject which materializes the module scope for the specified 11878 // module context. 11879 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( 11880 Isolate* isolate, 11881 Handle<Context> context) { 11882 ASSERT(context->IsModuleContext()); 11883 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11884 11885 // Allocate and initialize a JSObject with all the members of the debugged 11886 // module. 11887 Handle<JSObject> module_scope = 11888 isolate->factory()->NewJSObject(isolate->object_function()); 11889 11890 // Fill all context locals. 11891 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11892 scope_info, context, module_scope)) { 11893 return MaybeHandle<JSObject>(); 11894 } 11895 11896 return module_scope; 11897 } 11898 11899 11900 // Iterate over the actual scopes visible from a stack frame or from a closure. 11901 // The iteration proceeds from the innermost visible nested scope outwards. 11902 // All scopes are backed by an actual context except the local scope, 11903 // which is inserted "artificially" in the context chain. 11904 class ScopeIterator { 11905 public: 11906 enum ScopeType { 11907 ScopeTypeGlobal = 0, 11908 ScopeTypeLocal, 11909 ScopeTypeWith, 11910 ScopeTypeClosure, 11911 ScopeTypeCatch, 11912 ScopeTypeBlock, 11913 ScopeTypeModule 11914 }; 11915 11916 ScopeIterator(Isolate* isolate, 11917 JavaScriptFrame* frame, 11918 int inlined_jsframe_index, 11919 bool ignore_nested_scopes = false) 11920 : isolate_(isolate), 11921 frame_(frame), 11922 inlined_jsframe_index_(inlined_jsframe_index), 11923 function_(frame->function()), 11924 context_(Context::cast(frame->context())), 11925 nested_scope_chain_(4), 11926 failed_(false) { 11927 11928 // Catch the case when the debugger stops in an internal function. 11929 Handle<SharedFunctionInfo> shared_info(function_->shared()); 11930 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11931 if (shared_info->script() == isolate->heap()->undefined_value()) { 11932 while (context_->closure() == *function_) { 11933 context_ = Handle<Context>(context_->previous(), isolate_); 11934 } 11935 return; 11936 } 11937 11938 // Get the debug info (create it if it does not exist). 11939 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) { 11940 // Return if ensuring debug info failed. 11941 return; 11942 } 11943 11944 // Currently it takes too much time to find nested scopes due to script 11945 // parsing. Sometimes we want to run the ScopeIterator as fast as possible 11946 // (for example, while collecting async call stacks on every 11947 // addEventListener call), even if we drop some nested scopes. 11948 // Later we may optimize getting the nested scopes (cache the result?) 11949 // and include nested scopes into the "fast" iteration case as well. 11950 if (!ignore_nested_scopes) { 11951 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); 11952 11953 // Find the break point where execution has stopped. 11954 BreakLocationIterator break_location_iterator(debug_info, 11955 ALL_BREAK_LOCATIONS); 11956 // pc points to the instruction after the current one, possibly a break 11957 // location as well. So the "- 1" to exclude it from the search. 11958 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); 11959 11960 // Within the return sequence at the moment it is not possible to 11961 // get a source position which is consistent with the current scope chain. 11962 // Thus all nested with, catch and block contexts are skipped and we only 11963 // provide the function scope. 11964 ignore_nested_scopes = break_location_iterator.IsExit(); 11965 } 11966 11967 if (ignore_nested_scopes) { 11968 if (scope_info->HasContext()) { 11969 context_ = Handle<Context>(context_->declaration_context(), isolate_); 11970 } else { 11971 while (context_->closure() == *function_) { 11972 context_ = Handle<Context>(context_->previous(), isolate_); 11973 } 11974 } 11975 if (scope_info->scope_type() == FUNCTION_SCOPE) { 11976 nested_scope_chain_.Add(scope_info); 11977 } 11978 } else { 11979 // Reparse the code and analyze the scopes. 11980 Handle<Script> script(Script::cast(shared_info->script())); 11981 Scope* scope = NULL; 11982 11983 // Check whether we are in global, eval or function code. 11984 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11985 if (scope_info->scope_type() != FUNCTION_SCOPE) { 11986 // Global or eval code. 11987 CompilationInfoWithZone info(script); 11988 if (scope_info->scope_type() == GLOBAL_SCOPE) { 11989 info.MarkAsGlobal(); 11990 } else { 11991 ASSERT(scope_info->scope_type() == EVAL_SCOPE); 11992 info.MarkAsEval(); 11993 info.SetContext(Handle<Context>(function_->context())); 11994 } 11995 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 11996 scope = info.function()->scope(); 11997 } 11998 RetrieveScopeChain(scope, shared_info); 11999 } else { 12000 // Function code 12001 CompilationInfoWithZone info(shared_info); 12002 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 12003 scope = info.function()->scope(); 12004 } 12005 RetrieveScopeChain(scope, shared_info); 12006 } 12007 } 12008 } 12009 12010 ScopeIterator(Isolate* isolate, 12011 Handle<JSFunction> function) 12012 : isolate_(isolate), 12013 frame_(NULL), 12014 inlined_jsframe_index_(0), 12015 function_(function), 12016 context_(function->context()), 12017 failed_(false) { 12018 if (function->IsBuiltin()) { 12019 context_ = Handle<Context>(); 12020 } 12021 } 12022 12023 // More scopes? 12024 bool Done() { 12025 ASSERT(!failed_); 12026 return context_.is_null(); 12027 } 12028 12029 bool Failed() { return failed_; } 12030 12031 // Move to the next scope. 12032 void Next() { 12033 ASSERT(!failed_); 12034 ScopeType scope_type = Type(); 12035 if (scope_type == ScopeTypeGlobal) { 12036 // The global scope is always the last in the chain. 12037 ASSERT(context_->IsNativeContext()); 12038 context_ = Handle<Context>(); 12039 return; 12040 } 12041 if (nested_scope_chain_.is_empty()) { 12042 context_ = Handle<Context>(context_->previous(), isolate_); 12043 } else { 12044 if (nested_scope_chain_.last()->HasContext()) { 12045 ASSERT(context_->previous() != NULL); 12046 context_ = Handle<Context>(context_->previous(), isolate_); 12047 } 12048 nested_scope_chain_.RemoveLast(); 12049 } 12050 } 12051 12052 // Return the type of the current scope. 12053 ScopeType Type() { 12054 ASSERT(!failed_); 12055 if (!nested_scope_chain_.is_empty()) { 12056 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); 12057 switch (scope_info->scope_type()) { 12058 case FUNCTION_SCOPE: 12059 ASSERT(context_->IsFunctionContext() || 12060 !scope_info->HasContext()); 12061 return ScopeTypeLocal; 12062 case MODULE_SCOPE: 12063 ASSERT(context_->IsModuleContext()); 12064 return ScopeTypeModule; 12065 case GLOBAL_SCOPE: 12066 ASSERT(context_->IsNativeContext()); 12067 return ScopeTypeGlobal; 12068 case WITH_SCOPE: 12069 ASSERT(context_->IsWithContext()); 12070 return ScopeTypeWith; 12071 case CATCH_SCOPE: 12072 ASSERT(context_->IsCatchContext()); 12073 return ScopeTypeCatch; 12074 case BLOCK_SCOPE: 12075 ASSERT(!scope_info->HasContext() || 12076 context_->IsBlockContext()); 12077 return ScopeTypeBlock; 12078 case EVAL_SCOPE: 12079 UNREACHABLE(); 12080 } 12081 } 12082 if (context_->IsNativeContext()) { 12083 ASSERT(context_->global_object()->IsGlobalObject()); 12084 return ScopeTypeGlobal; 12085 } 12086 if (context_->IsFunctionContext()) { 12087 return ScopeTypeClosure; 12088 } 12089 if (context_->IsCatchContext()) { 12090 return ScopeTypeCatch; 12091 } 12092 if (context_->IsBlockContext()) { 12093 return ScopeTypeBlock; 12094 } 12095 if (context_->IsModuleContext()) { 12096 return ScopeTypeModule; 12097 } 12098 ASSERT(context_->IsWithContext()); 12099 return ScopeTypeWith; 12100 } 12101 12102 // Return the JavaScript object with the content of the current scope. 12103 MaybeHandle<JSObject> ScopeObject() { 12104 ASSERT(!failed_); 12105 switch (Type()) { 12106 case ScopeIterator::ScopeTypeGlobal: 12107 return Handle<JSObject>(CurrentContext()->global_object()); 12108 case ScopeIterator::ScopeTypeLocal: 12109 // Materialize the content of the local scope into a JSObject. 12110 ASSERT(nested_scope_chain_.length() == 1); 12111 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); 12112 case ScopeIterator::ScopeTypeWith: 12113 // Return the with object. 12114 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); 12115 case ScopeIterator::ScopeTypeCatch: 12116 return MaterializeCatchScope(isolate_, CurrentContext()); 12117 case ScopeIterator::ScopeTypeClosure: 12118 // Materialize the content of the closure scope into a JSObject. 12119 return MaterializeClosure(isolate_, CurrentContext()); 12120 case ScopeIterator::ScopeTypeBlock: 12121 return MaterializeBlockScope(isolate_, CurrentContext()); 12122 case ScopeIterator::ScopeTypeModule: 12123 return MaterializeModuleScope(isolate_, CurrentContext()); 12124 } 12125 UNREACHABLE(); 12126 return Handle<JSObject>(); 12127 } 12128 12129 bool SetVariableValue(Handle<String> variable_name, 12130 Handle<Object> new_value) { 12131 ASSERT(!failed_); 12132 switch (Type()) { 12133 case ScopeIterator::ScopeTypeGlobal: 12134 break; 12135 case ScopeIterator::ScopeTypeLocal: 12136 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, 12137 variable_name, new_value); 12138 case ScopeIterator::ScopeTypeWith: 12139 break; 12140 case ScopeIterator::ScopeTypeCatch: 12141 return SetCatchVariableValue(isolate_, CurrentContext(), 12142 variable_name, new_value); 12143 case ScopeIterator::ScopeTypeClosure: 12144 return SetClosureVariableValue(isolate_, CurrentContext(), 12145 variable_name, new_value); 12146 case ScopeIterator::ScopeTypeBlock: 12147 // TODO(2399): should we implement it? 12148 break; 12149 case ScopeIterator::ScopeTypeModule: 12150 // TODO(2399): should we implement it? 12151 break; 12152 } 12153 return false; 12154 } 12155 12156 Handle<ScopeInfo> CurrentScopeInfo() { 12157 ASSERT(!failed_); 12158 if (!nested_scope_chain_.is_empty()) { 12159 return nested_scope_chain_.last(); 12160 } else if (context_->IsBlockContext()) { 12161 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); 12162 } else if (context_->IsFunctionContext()) { 12163 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); 12164 } 12165 return Handle<ScopeInfo>::null(); 12166 } 12167 12168 // Return the context for this scope. For the local context there might not 12169 // be an actual context. 12170 Handle<Context> CurrentContext() { 12171 ASSERT(!failed_); 12172 if (Type() == ScopeTypeGlobal || 12173 nested_scope_chain_.is_empty()) { 12174 return context_; 12175 } else if (nested_scope_chain_.last()->HasContext()) { 12176 return context_; 12177 } else { 12178 return Handle<Context>(); 12179 } 12180 } 12181 12182 #ifdef DEBUG 12183 // Debug print of the content of the current scope. 12184 void DebugPrint() { 12185 ASSERT(!failed_); 12186 switch (Type()) { 12187 case ScopeIterator::ScopeTypeGlobal: 12188 PrintF("Global:\n"); 12189 CurrentContext()->Print(); 12190 break; 12191 12192 case ScopeIterator::ScopeTypeLocal: { 12193 PrintF("Local:\n"); 12194 function_->shared()->scope_info()->Print(); 12195 if (!CurrentContext().is_null()) { 12196 CurrentContext()->Print(); 12197 if (CurrentContext()->has_extension()) { 12198 Handle<Object> extension(CurrentContext()->extension(), isolate_); 12199 if (extension->IsJSContextExtensionObject()) { 12200 extension->Print(); 12201 } 12202 } 12203 } 12204 break; 12205 } 12206 12207 case ScopeIterator::ScopeTypeWith: 12208 PrintF("With:\n"); 12209 CurrentContext()->extension()->Print(); 12210 break; 12211 12212 case ScopeIterator::ScopeTypeCatch: 12213 PrintF("Catch:\n"); 12214 CurrentContext()->extension()->Print(); 12215 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(); 12216 break; 12217 12218 case ScopeIterator::ScopeTypeClosure: 12219 PrintF("Closure:\n"); 12220 CurrentContext()->Print(); 12221 if (CurrentContext()->has_extension()) { 12222 Handle<Object> extension(CurrentContext()->extension(), isolate_); 12223 if (extension->IsJSContextExtensionObject()) { 12224 extension->Print(); 12225 } 12226 } 12227 break; 12228 12229 default: 12230 UNREACHABLE(); 12231 } 12232 PrintF("\n"); 12233 } 12234 #endif 12235 12236 private: 12237 Isolate* isolate_; 12238 JavaScriptFrame* frame_; 12239 int inlined_jsframe_index_; 12240 Handle<JSFunction> function_; 12241 Handle<Context> context_; 12242 List<Handle<ScopeInfo> > nested_scope_chain_; 12243 bool failed_; 12244 12245 void RetrieveScopeChain(Scope* scope, 12246 Handle<SharedFunctionInfo> shared_info) { 12247 if (scope != NULL) { 12248 int source_position = shared_info->code()->SourcePosition(frame_->pc()); 12249 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); 12250 } else { 12251 // A failed reparse indicates that the preparser has diverged from the 12252 // parser or that the preparse data given to the initial parse has been 12253 // faulty. We fail in debug mode but in release mode we only provide the 12254 // information we get from the context chain but nothing about 12255 // completely stack allocated scopes or stack allocated locals. 12256 // Or it could be due to stack overflow. 12257 ASSERT(isolate_->has_pending_exception()); 12258 failed_ = true; 12259 } 12260 } 12261 12262 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 12263 }; 12264 12265 12266 RUNTIME_FUNCTION(Runtime_GetScopeCount) { 12267 HandleScope scope(isolate); 12268 ASSERT(args.length() == 2); 12269 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12270 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12271 12272 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12273 12274 // Get the frame where the debugging is performed. 12275 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12276 JavaScriptFrameIterator it(isolate, id); 12277 JavaScriptFrame* frame = it.frame(); 12278 12279 // Count the visible scopes. 12280 int n = 0; 12281 for (ScopeIterator it(isolate, frame, 0); 12282 !it.Done(); 12283 it.Next()) { 12284 n++; 12285 } 12286 12287 return Smi::FromInt(n); 12288 } 12289 12290 12291 // Returns the list of step-in positions (text offset) in a function of the 12292 // stack frame in a range from the current debug break position to the end 12293 // of the corresponding statement. 12294 RUNTIME_FUNCTION(Runtime_GetStepInPositions) { 12295 HandleScope scope(isolate); 12296 ASSERT(args.length() == 2); 12297 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12298 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12299 12300 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12301 12302 // Get the frame where the debugging is performed. 12303 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12304 JavaScriptFrameIterator frame_it(isolate, id); 12305 RUNTIME_ASSERT(!frame_it.done()); 12306 12307 JavaScriptFrame* frame = frame_it.frame(); 12308 12309 Handle<JSFunction> fun = 12310 Handle<JSFunction>(frame->function()); 12311 Handle<SharedFunctionInfo> shared = 12312 Handle<SharedFunctionInfo>(fun->shared()); 12313 12314 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { 12315 return isolate->heap()->undefined_value(); 12316 } 12317 12318 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); 12319 12320 int len = 0; 12321 Handle<JSArray> array(isolate->factory()->NewJSArray(10)); 12322 // Find the break point where execution has stopped. 12323 BreakLocationIterator break_location_iterator(debug_info, 12324 ALL_BREAK_LOCATIONS); 12325 12326 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); 12327 int current_statement_pos = break_location_iterator.statement_position(); 12328 12329 while (!break_location_iterator.Done()) { 12330 bool accept; 12331 if (break_location_iterator.pc() > frame->pc()) { 12332 accept = true; 12333 } else { 12334 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id(); 12335 // The break point is near our pc. Could be a step-in possibility, 12336 // that is currently taken by active debugger call. 12337 if (break_frame_id == StackFrame::NO_ID) { 12338 // We are not stepping. 12339 accept = false; 12340 } else { 12341 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id); 12342 // If our frame is a top frame and we are stepping, we can do step-in 12343 // at this place. 12344 accept = additional_frame_it.frame()->id() == id; 12345 } 12346 } 12347 if (accept) { 12348 if (break_location_iterator.IsStepInLocation(isolate)) { 12349 Smi* position_value = Smi::FromInt(break_location_iterator.position()); 12350 RETURN_FAILURE_ON_EXCEPTION( 12351 isolate, 12352 JSObject::SetElement(array, len, 12353 Handle<Object>(position_value, isolate), 12354 NONE, SLOPPY)); 12355 len++; 12356 } 12357 } 12358 // Advance iterator. 12359 break_location_iterator.Next(); 12360 if (current_statement_pos != 12361 break_location_iterator.statement_position()) { 12362 break; 12363 } 12364 } 12365 return *array; 12366 } 12367 12368 12369 static const int kScopeDetailsTypeIndex = 0; 12370 static const int kScopeDetailsObjectIndex = 1; 12371 static const int kScopeDetailsSize = 2; 12372 12373 12374 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails( 12375 Isolate* isolate, 12376 ScopeIterator* it) { 12377 // Calculate the size of the result. 12378 int details_size = kScopeDetailsSize; 12379 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 12380 12381 // Fill in scope details. 12382 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); 12383 Handle<JSObject> scope_object; 12384 ASSIGN_RETURN_ON_EXCEPTION( 12385 isolate, scope_object, it->ScopeObject(), JSObject); 12386 details->set(kScopeDetailsObjectIndex, *scope_object); 12387 12388 return isolate->factory()->NewJSArrayWithElements(details); 12389 } 12390 12391 12392 // Return an array with scope details 12393 // args[0]: number: break id 12394 // args[1]: number: frame index 12395 // args[2]: number: inlined frame index 12396 // args[3]: number: scope index 12397 // 12398 // The array returned contains the following information: 12399 // 0: Scope type 12400 // 1: Scope object 12401 RUNTIME_FUNCTION(Runtime_GetScopeDetails) { 12402 HandleScope scope(isolate); 12403 ASSERT(args.length() == 4); 12404 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12405 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12406 12407 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12408 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12409 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12410 12411 // Get the frame where the debugging is performed. 12412 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12413 JavaScriptFrameIterator frame_it(isolate, id); 12414 JavaScriptFrame* frame = frame_it.frame(); 12415 12416 // Find the requested scope. 12417 int n = 0; 12418 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12419 for (; !it.Done() && n < index; it.Next()) { 12420 n++; 12421 } 12422 if (it.Done()) { 12423 return isolate->heap()->undefined_value(); 12424 } 12425 Handle<JSObject> details; 12426 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 12427 isolate, details, MaterializeScopeDetails(isolate, &it)); 12428 return *details; 12429 } 12430 12431 12432 // Return an array of scope details 12433 // args[0]: number: break id 12434 // args[1]: number: frame index 12435 // args[2]: number: inlined frame index 12436 // args[3]: boolean: ignore nested scopes 12437 // 12438 // The array returned contains arrays with the following information: 12439 // 0: Scope type 12440 // 1: Scope object 12441 RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) { 12442 HandleScope scope(isolate); 12443 ASSERT(args.length() == 3 || args.length() == 4); 12444 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12445 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12446 12447 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12448 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12449 12450 bool ignore_nested_scopes = false; 12451 if (args.length() == 4) { 12452 CONVERT_BOOLEAN_ARG_CHECKED(flag, 3); 12453 ignore_nested_scopes = flag; 12454 } 12455 12456 // Get the frame where the debugging is performed. 12457 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12458 JavaScriptFrameIterator frame_it(isolate, id); 12459 JavaScriptFrame* frame = frame_it.frame(); 12460 12461 List<Handle<JSObject> > result(4); 12462 ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes); 12463 for (; !it.Done(); it.Next()) { 12464 Handle<JSObject> details; 12465 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 12466 isolate, details, MaterializeScopeDetails(isolate, &it)); 12467 result.Add(details); 12468 } 12469 12470 Handle<FixedArray> array = isolate->factory()->NewFixedArray(result.length()); 12471 for (int i = 0; i < result.length(); ++i) { 12472 array->set(i, *result[i]); 12473 } 12474 return *isolate->factory()->NewJSArrayWithElements(array); 12475 } 12476 12477 12478 RUNTIME_FUNCTION(Runtime_GetFunctionScopeCount) { 12479 HandleScope scope(isolate); 12480 ASSERT(args.length() == 1); 12481 12482 // Check arguments. 12483 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12484 12485 // Count the visible scopes. 12486 int n = 0; 12487 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { 12488 n++; 12489 } 12490 12491 return Smi::FromInt(n); 12492 } 12493 12494 12495 RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { 12496 HandleScope scope(isolate); 12497 ASSERT(args.length() == 2); 12498 12499 // Check arguments. 12500 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12501 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12502 12503 // Find the requested scope. 12504 int n = 0; 12505 ScopeIterator it(isolate, fun); 12506 for (; !it.Done() && n < index; it.Next()) { 12507 n++; 12508 } 12509 if (it.Done()) { 12510 return isolate->heap()->undefined_value(); 12511 } 12512 12513 Handle<JSObject> details; 12514 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 12515 isolate, details, MaterializeScopeDetails(isolate, &it)); 12516 return *details; 12517 } 12518 12519 12520 static bool SetScopeVariableValue(ScopeIterator* it, int index, 12521 Handle<String> variable_name, 12522 Handle<Object> new_value) { 12523 for (int n = 0; !it->Done() && n < index; it->Next()) { 12524 n++; 12525 } 12526 if (it->Done()) { 12527 return false; 12528 } 12529 return it->SetVariableValue(variable_name, new_value); 12530 } 12531 12532 12533 // Change variable value in closure or local scope 12534 // args[0]: number or JsFunction: break id or function 12535 // args[1]: number: frame index (when arg[0] is break id) 12536 // args[2]: number: inlined frame index (when arg[0] is break id) 12537 // args[3]: number: scope index 12538 // args[4]: string: variable name 12539 // args[5]: object: new value 12540 // 12541 // Return true if success and false otherwise 12542 RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { 12543 HandleScope scope(isolate); 12544 ASSERT(args.length() == 6); 12545 12546 // Check arguments. 12547 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12548 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); 12549 CONVERT_ARG_HANDLE_CHECKED(Object, new_value, 5); 12550 12551 bool res; 12552 if (args[0]->IsNumber()) { 12553 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12554 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12555 12556 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12557 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12558 12559 // Get the frame where the debugging is performed. 12560 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12561 JavaScriptFrameIterator frame_it(isolate, id); 12562 JavaScriptFrame* frame = frame_it.frame(); 12563 12564 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12565 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12566 } else { 12567 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12568 ScopeIterator it(isolate, fun); 12569 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12570 } 12571 12572 return isolate->heap()->ToBoolean(res); 12573 } 12574 12575 12576 RUNTIME_FUNCTION(Runtime_DebugPrintScopes) { 12577 HandleScope scope(isolate); 12578 ASSERT(args.length() == 0); 12579 12580 #ifdef DEBUG 12581 // Print the scopes for the top frame. 12582 StackFrameLocator locator(isolate); 12583 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 12584 for (ScopeIterator it(isolate, frame, 0); 12585 !it.Done(); 12586 it.Next()) { 12587 it.DebugPrint(); 12588 } 12589 #endif 12590 return isolate->heap()->undefined_value(); 12591 } 12592 12593 12594 RUNTIME_FUNCTION(Runtime_GetThreadCount) { 12595 HandleScope scope(isolate); 12596 ASSERT(args.length() == 1); 12597 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12598 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12599 12600 // Count all archived V8 threads. 12601 int n = 0; 12602 for (ThreadState* thread = 12603 isolate->thread_manager()->FirstThreadStateInUse(); 12604 thread != NULL; 12605 thread = thread->Next()) { 12606 n++; 12607 } 12608 12609 // Total number of threads is current thread and archived threads. 12610 return Smi::FromInt(n + 1); 12611 } 12612 12613 12614 static const int kThreadDetailsCurrentThreadIndex = 0; 12615 static const int kThreadDetailsThreadIdIndex = 1; 12616 static const int kThreadDetailsSize = 2; 12617 12618 // Return an array with thread details 12619 // args[0]: number: break id 12620 // args[1]: number: thread index 12621 // 12622 // The array returned contains the following information: 12623 // 0: Is current thread? 12624 // 1: Thread id 12625 RUNTIME_FUNCTION(Runtime_GetThreadDetails) { 12626 HandleScope scope(isolate); 12627 ASSERT(args.length() == 2); 12628 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12629 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12630 12631 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12632 12633 // Allocate array for result. 12634 Handle<FixedArray> details = 12635 isolate->factory()->NewFixedArray(kThreadDetailsSize); 12636 12637 // Thread index 0 is current thread. 12638 if (index == 0) { 12639 // Fill the details. 12640 details->set(kThreadDetailsCurrentThreadIndex, 12641 isolate->heap()->true_value()); 12642 details->set(kThreadDetailsThreadIdIndex, 12643 Smi::FromInt(ThreadId::Current().ToInteger())); 12644 } else { 12645 // Find the thread with the requested index. 12646 int n = 1; 12647 ThreadState* thread = 12648 isolate->thread_manager()->FirstThreadStateInUse(); 12649 while (index != n && thread != NULL) { 12650 thread = thread->Next(); 12651 n++; 12652 } 12653 if (thread == NULL) { 12654 return isolate->heap()->undefined_value(); 12655 } 12656 12657 // Fill the details. 12658 details->set(kThreadDetailsCurrentThreadIndex, 12659 isolate->heap()->false_value()); 12660 details->set(kThreadDetailsThreadIdIndex, 12661 Smi::FromInt(thread->id().ToInteger())); 12662 } 12663 12664 // Convert to JS array and return. 12665 return *isolate->factory()->NewJSArrayWithElements(details); 12666 } 12667 12668 12669 // Sets the disable break state 12670 // args[0]: disable break state 12671 RUNTIME_FUNCTION(Runtime_SetDisableBreak) { 12672 HandleScope scope(isolate); 12673 ASSERT(args.length() == 1); 12674 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); 12675 isolate->debug()->set_disable_break(disable_break); 12676 return isolate->heap()->undefined_value(); 12677 } 12678 12679 12680 static bool IsPositionAlignmentCodeCorrect(int alignment) { 12681 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; 12682 } 12683 12684 12685 RUNTIME_FUNCTION(Runtime_GetBreakLocations) { 12686 HandleScope scope(isolate); 12687 ASSERT(args.length() == 2); 12688 12689 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12690 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); 12691 12692 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12693 return isolate->ThrowIllegalOperation(); 12694 } 12695 BreakPositionAlignment alignment = 12696 static_cast<BreakPositionAlignment>(statement_aligned_code); 12697 12698 Handle<SharedFunctionInfo> shared(fun->shared()); 12699 // Find the number of break points 12700 Handle<Object> break_locations = 12701 Debug::GetSourceBreakLocations(shared, alignment); 12702 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); 12703 // Return array as JS array 12704 return *isolate->factory()->NewJSArrayWithElements( 12705 Handle<FixedArray>::cast(break_locations)); 12706 } 12707 12708 12709 // Set a break point in a function. 12710 // args[0]: function 12711 // args[1]: number: break source position (within the function source) 12712 // args[2]: number: break point object 12713 RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) { 12714 HandleScope scope(isolate); 12715 ASSERT(args.length() == 3); 12716 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 12717 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12718 RUNTIME_ASSERT(source_position >= function->shared()->start_position() && 12719 source_position <= function->shared()->end_position()); 12720 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2); 12721 12722 // Set break point. 12723 RUNTIME_ASSERT(isolate->debug()->SetBreakPoint( 12724 function, break_point_object_arg, &source_position)); 12725 12726 return Smi::FromInt(source_position); 12727 } 12728 12729 12730 // Changes the state of a break point in a script and returns source position 12731 // where break point was set. NOTE: Regarding performance see the NOTE for 12732 // GetScriptFromScriptData. 12733 // args[0]: script to set break point in 12734 // args[1]: number: break source position (within the script source) 12735 // args[2]: number, breakpoint position alignment 12736 // args[3]: number: break point object 12737 RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) { 12738 HandleScope scope(isolate); 12739 ASSERT(args.length() == 4); 12740 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 12741 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12742 RUNTIME_ASSERT(source_position >= 0); 12743 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); 12744 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 3); 12745 12746 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12747 return isolate->ThrowIllegalOperation(); 12748 } 12749 BreakPositionAlignment alignment = 12750 static_cast<BreakPositionAlignment>(statement_aligned_code); 12751 12752 // Get the script from the script wrapper. 12753 RUNTIME_ASSERT(wrapper->value()->IsScript()); 12754 Handle<Script> script(Script::cast(wrapper->value())); 12755 12756 // Set break point. 12757 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, 12758 &source_position, 12759 alignment)) { 12760 return isolate->heap()->undefined_value(); 12761 } 12762 12763 return Smi::FromInt(source_position); 12764 } 12765 12766 12767 // Clear a break point 12768 // args[0]: number: break point object 12769 RUNTIME_FUNCTION(Runtime_ClearBreakPoint) { 12770 HandleScope scope(isolate); 12771 ASSERT(args.length() == 1); 12772 CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0); 12773 12774 // Clear break point. 12775 isolate->debug()->ClearBreakPoint(break_point_object_arg); 12776 12777 return isolate->heap()->undefined_value(); 12778 } 12779 12780 12781 // Change the state of break on exceptions. 12782 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 12783 // args[1]: Boolean indicating on/off. 12784 RUNTIME_FUNCTION(Runtime_ChangeBreakOnException) { 12785 HandleScope scope(isolate); 12786 ASSERT(args.length() == 2); 12787 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 12788 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 12789 12790 // If the number doesn't match an enum value, the ChangeBreakOnException 12791 // function will default to affecting caught exceptions. 12792 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 12793 // Update break point state. 12794 isolate->debug()->ChangeBreakOnException(type, enable); 12795 return isolate->heap()->undefined_value(); 12796 } 12797 12798 12799 // Returns the state of break on exceptions 12800 // args[0]: boolean indicating uncaught exceptions 12801 RUNTIME_FUNCTION(Runtime_IsBreakOnException) { 12802 HandleScope scope(isolate); 12803 ASSERT(args.length() == 1); 12804 CONVERT_NUMBER_CHECKED(uint32_t, type_arg, Uint32, args[0]); 12805 12806 ExceptionBreakType type = static_cast<ExceptionBreakType>(type_arg); 12807 bool result = isolate->debug()->IsBreakOnException(type); 12808 return Smi::FromInt(result); 12809 } 12810 12811 12812 // Prepare for stepping 12813 // args[0]: break id for checking execution state 12814 // args[1]: step action from the enumeration StepAction 12815 // args[2]: number of times to perform the step, for step out it is the number 12816 // of frames to step down. 12817 RUNTIME_FUNCTION(Runtime_PrepareStep) { 12818 HandleScope scope(isolate); 12819 ASSERT(args.length() == 4); 12820 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12821 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12822 12823 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 12824 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12825 } 12826 12827 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); 12828 12829 StackFrame::Id frame_id; 12830 if (wrapped_frame_id == 0) { 12831 frame_id = StackFrame::NO_ID; 12832 } else { 12833 frame_id = UnwrapFrameId(wrapped_frame_id); 12834 } 12835 12836 // Get the step action and check validity. 12837 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 12838 if (step_action != StepIn && 12839 step_action != StepNext && 12840 step_action != StepOut && 12841 step_action != StepInMin && 12842 step_action != StepMin) { 12843 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12844 } 12845 12846 if (frame_id != StackFrame::NO_ID && step_action != StepNext && 12847 step_action != StepMin && step_action != StepOut) { 12848 return isolate->ThrowIllegalOperation(); 12849 } 12850 12851 // Get the number of steps. 12852 int step_count = NumberToInt32(args[2]); 12853 if (step_count < 1) { 12854 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12855 } 12856 12857 // Clear all current stepping setup. 12858 isolate->debug()->ClearStepping(); 12859 12860 // Prepare step. 12861 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), 12862 step_count, 12863 frame_id); 12864 return isolate->heap()->undefined_value(); 12865 } 12866 12867 12868 // Clear all stepping set by PrepareStep. 12869 RUNTIME_FUNCTION(Runtime_ClearStepping) { 12870 HandleScope scope(isolate); 12871 ASSERT(args.length() == 0); 12872 isolate->debug()->ClearStepping(); 12873 return isolate->heap()->undefined_value(); 12874 } 12875 12876 12877 // Helper function to find or create the arguments object for 12878 // Runtime_DebugEvaluate. 12879 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeArgumentsObject( 12880 Isolate* isolate, 12881 Handle<JSObject> target, 12882 Handle<JSFunction> function) { 12883 // Do not materialize the arguments object for eval or top-level code. 12884 // Skip if "arguments" is already taken. 12885 if (!function->shared()->is_function() || 12886 JSReceiver::HasOwnProperty( 12887 target, isolate->factory()->arguments_string())) { 12888 return target; 12889 } 12890 12891 // FunctionGetArguments can't throw an exception. 12892 Handle<JSObject> arguments = Handle<JSObject>::cast( 12893 Accessors::FunctionGetArguments(function)); 12894 Handle<String> arguments_str = isolate->factory()->arguments_string(); 12895 RETURN_ON_EXCEPTION( 12896 isolate, 12897 Runtime::SetObjectProperty( 12898 isolate, target, arguments_str, arguments, ::NONE, SLOPPY), 12899 JSObject); 12900 return target; 12901 } 12902 12903 12904 // Compile and evaluate source for the given context. 12905 static MaybeHandle<Object> DebugEvaluate(Isolate* isolate, 12906 Handle<Context> context, 12907 Handle<Object> context_extension, 12908 Handle<Object> receiver, 12909 Handle<String> source) { 12910 if (context_extension->IsJSObject()) { 12911 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); 12912 Handle<JSFunction> closure(context->closure(), isolate); 12913 context = isolate->factory()->NewWithContext(closure, context, extension); 12914 } 12915 12916 Handle<JSFunction> eval_fun; 12917 ASSIGN_RETURN_ON_EXCEPTION( 12918 isolate, eval_fun, 12919 Compiler::GetFunctionFromEval(source, 12920 context, 12921 SLOPPY, 12922 NO_PARSE_RESTRICTION, 12923 RelocInfo::kNoPosition), 12924 Object); 12925 12926 Handle<Object> result; 12927 ASSIGN_RETURN_ON_EXCEPTION( 12928 isolate, result, 12929 Execution::Call(isolate, eval_fun, receiver, 0, NULL), 12930 Object); 12931 12932 // Skip the global proxy as it has no properties and always delegates to the 12933 // real global object. 12934 if (result->IsJSGlobalProxy()) { 12935 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate))); 12936 } 12937 12938 // Clear the oneshot breakpoints so that the debugger does not step further. 12939 isolate->debug()->ClearStepping(); 12940 return result; 12941 } 12942 12943 12944 // Evaluate a piece of JavaScript in the context of a stack frame for 12945 // debugging. Things that need special attention are: 12946 // - Parameters and stack-allocated locals need to be materialized. Altered 12947 // values need to be written back to the stack afterwards. 12948 // - The arguments object needs to materialized. 12949 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { 12950 HandleScope scope(isolate); 12951 12952 // Check the execution state and decode arguments frame and source to be 12953 // evaluated. 12954 ASSERT(args.length() == 6); 12955 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 12956 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 12957 12958 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12959 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12960 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 12961 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); 12962 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5); 12963 12964 // Handle the processing of break. 12965 DisableBreak disable_break_scope(isolate->debug(), disable_break); 12966 12967 // Get the frame where the debugging is performed. 12968 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12969 JavaScriptFrameIterator it(isolate, id); 12970 JavaScriptFrame* frame = it.frame(); 12971 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 12972 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 12973 12974 // Traverse the saved contexts chain to find the active context for the 12975 // selected frame. 12976 SaveContext* save = FindSavedContextForFrame(isolate, frame); 12977 12978 SaveContext savex(isolate); 12979 isolate->set_context(*(save->context())); 12980 12981 // Evaluate on the context of the frame. 12982 Handle<Context> context(Context::cast(frame->context())); 12983 ASSERT(!context.is_null()); 12984 12985 // Materialize stack locals and the arguments object. 12986 Handle<JSObject> materialized = 12987 isolate->factory()->NewJSObject(isolate->object_function()); 12988 12989 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 12990 isolate, materialized, 12991 MaterializeStackLocalsWithFrameInspector( 12992 isolate, materialized, function, &frame_inspector)); 12993 12994 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 12995 isolate, materialized, 12996 MaterializeArgumentsObject(isolate, materialized, function)); 12997 12998 // Add the materialized object in a with-scope to shadow the stack locals. 12999 context = isolate->factory()->NewWithContext(function, context, materialized); 13000 13001 Handle<Object> receiver(frame->receiver(), isolate); 13002 Handle<Object> result; 13003 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 13004 isolate, result, 13005 DebugEvaluate(isolate, context, context_extension, receiver, source)); 13006 13007 // Write back potential changes to materialized stack locals to the stack. 13008 UpdateStackLocalsFromMaterializedObject( 13009 isolate, materialized, function, frame, inlined_jsframe_index); 13010 13011 return *result; 13012 } 13013 13014 13015 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { 13016 HandleScope scope(isolate); 13017 13018 // Check the execution state and decode arguments frame and source to be 13019 // evaluated. 13020 ASSERT(args.length() == 4); 13021 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 13022 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 13023 13024 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13025 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); 13026 CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3); 13027 13028 // Handle the processing of break. 13029 DisableBreak disable_break_scope(isolate->debug(), disable_break); 13030 13031 // Enter the top context from before the debugger was invoked. 13032 SaveContext save(isolate); 13033 SaveContext* top = &save; 13034 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { 13035 top = top->prev(); 13036 } 13037 if (top != NULL) { 13038 isolate->set_context(*top->context()); 13039 } 13040 13041 // Get the native context now set to the top context from before the 13042 // debugger was invoked. 13043 Handle<Context> context = isolate->native_context(); 13044 Handle<Object> receiver = isolate->global_object(); 13045 Handle<Object> result; 13046 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 13047 isolate, result, 13048 DebugEvaluate(isolate, context, context_extension, receiver, source)); 13049 return *result; 13050 } 13051 13052 13053 RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) { 13054 HandleScope scope(isolate); 13055 ASSERT(args.length() == 0); 13056 13057 // Fill the script objects. 13058 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); 13059 13060 // Convert the script objects to proper JS objects. 13061 for (int i = 0; i < instances->length(); i++) { 13062 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 13063 // Get the script wrapper in a local handle before calling GetScriptWrapper, 13064 // because using 13065 // instances->set(i, *GetScriptWrapper(script)) 13066 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 13067 // already have dereferenced the instances handle. 13068 Handle<JSObject> wrapper = Script::GetWrapper(script); 13069 instances->set(i, *wrapper); 13070 } 13071 13072 // Return result as a JS array. 13073 Handle<JSObject> result = 13074 isolate->factory()->NewJSObject(isolate->array_function()); 13075 JSArray::SetContent(Handle<JSArray>::cast(result), instances); 13076 return *result; 13077 } 13078 13079 13080 // Helper function used by Runtime_DebugReferencedBy below. 13081 static int DebugReferencedBy(HeapIterator* iterator, 13082 JSObject* target, 13083 Object* instance_filter, int max_references, 13084 FixedArray* instances, int instances_size, 13085 JSFunction* arguments_function) { 13086 Isolate* isolate = target->GetIsolate(); 13087 SealHandleScope shs(isolate); 13088 DisallowHeapAllocation no_allocation; 13089 13090 // Iterate the heap. 13091 int count = 0; 13092 JSObject* last = NULL; 13093 HeapObject* heap_obj = NULL; 13094 while (((heap_obj = iterator->next()) != NULL) && 13095 (max_references == 0 || count < max_references)) { 13096 // Only look at all JSObjects. 13097 if (heap_obj->IsJSObject()) { 13098 // Skip context extension objects and argument arrays as these are 13099 // checked in the context of functions using them. 13100 JSObject* obj = JSObject::cast(heap_obj); 13101 if (obj->IsJSContextExtensionObject() || 13102 obj->map()->constructor() == arguments_function) { 13103 continue; 13104 } 13105 13106 // Check if the JS object has a reference to the object looked for. 13107 if (obj->ReferencesObject(target)) { 13108 // Check instance filter if supplied. This is normally used to avoid 13109 // references from mirror objects (see Runtime_IsInPrototypeChain). 13110 if (!instance_filter->IsUndefined()) { 13111 Object* V = obj; 13112 while (true) { 13113 Object* prototype = V->GetPrototype(isolate); 13114 if (prototype->IsNull()) { 13115 break; 13116 } 13117 if (instance_filter == prototype) { 13118 obj = NULL; // Don't add this object. 13119 break; 13120 } 13121 V = prototype; 13122 } 13123 } 13124 13125 if (obj != NULL) { 13126 // Valid reference found add to instance array if supplied an update 13127 // count. 13128 if (instances != NULL && count < instances_size) { 13129 instances->set(count, obj); 13130 } 13131 last = obj; 13132 count++; 13133 } 13134 } 13135 } 13136 } 13137 13138 // Check for circular reference only. This can happen when the object is only 13139 // referenced from mirrors and has a circular reference in which case the 13140 // object is not really alive and would have been garbage collected if not 13141 // referenced from the mirror. 13142 if (count == 1 && last == target) { 13143 count = 0; 13144 } 13145 13146 // Return the number of referencing objects found. 13147 return count; 13148 } 13149 13150 13151 // Scan the heap for objects with direct references to an object 13152 // args[0]: the object to find references to 13153 // args[1]: constructor function for instances to exclude (Mirror) 13154 // args[2]: the the maximum number of objects to return 13155 RUNTIME_FUNCTION(Runtime_DebugReferencedBy) { 13156 HandleScope scope(isolate); 13157 ASSERT(args.length() == 3); 13158 13159 // Check parameters. 13160 CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0); 13161 CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1); 13162 RUNTIME_ASSERT(instance_filter->IsUndefined() || 13163 instance_filter->IsJSObject()); 13164 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 13165 RUNTIME_ASSERT(max_references >= 0); 13166 13167 13168 // Get the constructor function for context extension and arguments array. 13169 Handle<JSObject> arguments_boilerplate( 13170 isolate->context()->native_context()->sloppy_arguments_boilerplate()); 13171 Handle<JSFunction> arguments_function( 13172 JSFunction::cast(arguments_boilerplate->map()->constructor())); 13173 13174 // Get the number of referencing objects. 13175 int count; 13176 // First perform a full GC in order to avoid dead objects and to make the heap 13177 // iterable. 13178 Heap* heap = isolate->heap(); 13179 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); 13180 { 13181 HeapIterator heap_iterator(heap); 13182 count = DebugReferencedBy(&heap_iterator, 13183 *target, *instance_filter, max_references, 13184 NULL, 0, *arguments_function); 13185 } 13186 13187 // Allocate an array to hold the result. 13188 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); 13189 13190 // Fill the referencing objects. 13191 { 13192 HeapIterator heap_iterator(heap); 13193 count = DebugReferencedBy(&heap_iterator, 13194 *target, *instance_filter, max_references, 13195 *instances, count, *arguments_function); 13196 } 13197 13198 // Return result as JS array. 13199 Handle<JSFunction> constructor( 13200 isolate->context()->native_context()->array_function()); 13201 13202 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); 13203 JSArray::SetContent(Handle<JSArray>::cast(result), instances); 13204 return *result; 13205 } 13206 13207 13208 // Helper function used by Runtime_DebugConstructedBy below. 13209 static int DebugConstructedBy(HeapIterator* iterator, 13210 JSFunction* constructor, 13211 int max_references, 13212 FixedArray* instances, 13213 int instances_size) { 13214 DisallowHeapAllocation no_allocation; 13215 13216 // Iterate the heap. 13217 int count = 0; 13218 HeapObject* heap_obj = NULL; 13219 while (((heap_obj = iterator->next()) != NULL) && 13220 (max_references == 0 || count < max_references)) { 13221 // Only look at all JSObjects. 13222 if (heap_obj->IsJSObject()) { 13223 JSObject* obj = JSObject::cast(heap_obj); 13224 if (obj->map()->constructor() == constructor) { 13225 // Valid reference found add to instance array if supplied an update 13226 // count. 13227 if (instances != NULL && count < instances_size) { 13228 instances->set(count, obj); 13229 } 13230 count++; 13231 } 13232 } 13233 } 13234 13235 // Return the number of referencing objects found. 13236 return count; 13237 } 13238 13239 13240 // Scan the heap for objects constructed by a specific function. 13241 // args[0]: the constructor to find instances of 13242 // args[1]: the the maximum number of objects to return 13243 RUNTIME_FUNCTION(Runtime_DebugConstructedBy) { 13244 HandleScope scope(isolate); 13245 ASSERT(args.length() == 2); 13246 13247 13248 // Check parameters. 13249 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0); 13250 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 13251 RUNTIME_ASSERT(max_references >= 0); 13252 13253 // Get the number of referencing objects. 13254 int count; 13255 // First perform a full GC in order to avoid dead objects and to make the heap 13256 // iterable. 13257 Heap* heap = isolate->heap(); 13258 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); 13259 { 13260 HeapIterator heap_iterator(heap); 13261 count = DebugConstructedBy(&heap_iterator, 13262 *constructor, 13263 max_references, 13264 NULL, 13265 0); 13266 } 13267 13268 // Allocate an array to hold the result. 13269 Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count); 13270 13271 // Fill the referencing objects. 13272 { 13273 HeapIterator heap_iterator2(heap); 13274 count = DebugConstructedBy(&heap_iterator2, 13275 *constructor, 13276 max_references, 13277 *instances, 13278 count); 13279 } 13280 13281 // Return result as JS array. 13282 Handle<JSFunction> array_function( 13283 isolate->context()->native_context()->array_function()); 13284 Handle<JSObject> result = isolate->factory()->NewJSObject(array_function); 13285 JSArray::SetContent(Handle<JSArray>::cast(result), instances); 13286 return *result; 13287 } 13288 13289 13290 // Find the effective prototype object as returned by __proto__. 13291 // args[0]: the object to find the prototype for. 13292 RUNTIME_FUNCTION(Runtime_DebugGetPrototype) { 13293 HandleScope shs(isolate); 13294 ASSERT(args.length() == 1); 13295 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 13296 return *GetPrototypeSkipHiddenPrototypes(isolate, obj); 13297 } 13298 13299 13300 // Patches script source (should be called upon BeforeCompile event). 13301 RUNTIME_FUNCTION(Runtime_DebugSetScriptSource) { 13302 HandleScope scope(isolate); 13303 ASSERT(args.length() == 2); 13304 13305 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 13306 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13307 13308 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); 13309 Handle<Script> script(Script::cast(script_wrapper->value())); 13310 13311 int compilation_state = script->compilation_state(); 13312 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); 13313 script->set_source(*source); 13314 13315 return isolate->heap()->undefined_value(); 13316 } 13317 13318 13319 RUNTIME_FUNCTION(Runtime_SystemBreak) { 13320 SealHandleScope shs(isolate); 13321 ASSERT(args.length() == 0); 13322 OS::DebugBreak(); 13323 return isolate->heap()->undefined_value(); 13324 } 13325 13326 13327 RUNTIME_FUNCTION(Runtime_DebugDisassembleFunction) { 13328 HandleScope scope(isolate); 13329 #ifdef DEBUG 13330 ASSERT(args.length() == 1); 13331 // Get the function and make sure it is compiled. 13332 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 13333 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { 13334 return isolate->heap()->exception(); 13335 } 13336 func->code()->PrintLn(); 13337 #endif // DEBUG 13338 return isolate->heap()->undefined_value(); 13339 } 13340 13341 13342 RUNTIME_FUNCTION(Runtime_DebugDisassembleConstructor) { 13343 HandleScope scope(isolate); 13344 #ifdef DEBUG 13345 ASSERT(args.length() == 1); 13346 // Get the function and make sure it is compiled. 13347 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 13348 if (!Compiler::EnsureCompiled(func, KEEP_EXCEPTION)) { 13349 return isolate->heap()->exception(); 13350 } 13351 func->shared()->construct_stub()->PrintLn(); 13352 #endif // DEBUG 13353 return isolate->heap()->undefined_value(); 13354 } 13355 13356 13357 RUNTIME_FUNCTION(Runtime_FunctionGetInferredName) { 13358 SealHandleScope shs(isolate); 13359 ASSERT(args.length() == 1); 13360 13361 CONVERT_ARG_CHECKED(JSFunction, f, 0); 13362 return f->shared()->inferred_name(); 13363 } 13364 13365 13366 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, 13367 Script* script, 13368 FixedArray* buffer) { 13369 DisallowHeapAllocation no_allocation; 13370 int counter = 0; 13371 int buffer_size = buffer->length(); 13372 for (HeapObject* obj = iterator->next(); 13373 obj != NULL; 13374 obj = iterator->next()) { 13375 ASSERT(obj != NULL); 13376 if (!obj->IsSharedFunctionInfo()) { 13377 continue; 13378 } 13379 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 13380 if (shared->script() != script) { 13381 continue; 13382 } 13383 if (counter < buffer_size) { 13384 buffer->set(counter, shared); 13385 } 13386 counter++; 13387 } 13388 return counter; 13389 } 13390 13391 13392 // For a script finds all SharedFunctionInfo's in the heap that points 13393 // to this script. Returns JSArray of SharedFunctionInfo wrapped 13394 // in OpaqueReferences. 13395 RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) { 13396 HandleScope scope(isolate); 13397 CHECK(isolate->debug()->live_edit_enabled()); 13398 ASSERT(args.length() == 1); 13399 CONVERT_ARG_CHECKED(JSValue, script_value, 0); 13400 13401 RUNTIME_ASSERT(script_value->value()->IsScript()); 13402 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); 13403 13404 const int kBufferSize = 32; 13405 13406 Handle<FixedArray> array; 13407 array = isolate->factory()->NewFixedArray(kBufferSize); 13408 int number; 13409 Heap* heap = isolate->heap(); 13410 { 13411 HeapIterator heap_iterator(heap); 13412 Script* scr = *script; 13413 FixedArray* arr = *array; 13414 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13415 } 13416 if (number > kBufferSize) { 13417 array = isolate->factory()->NewFixedArray(number); 13418 HeapIterator heap_iterator(heap); 13419 Script* scr = *script; 13420 FixedArray* arr = *array; 13421 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13422 } 13423 13424 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); 13425 result->set_length(Smi::FromInt(number)); 13426 13427 LiveEdit::WrapSharedFunctionInfos(result); 13428 13429 return *result; 13430 } 13431 13432 13433 // For a script calculates compilation information about all its functions. 13434 // The script source is explicitly specified by the second argument. 13435 // The source of the actual script is not used, however it is important that 13436 // all generated code keeps references to this particular instance of script. 13437 // Returns a JSArray of compilation infos. The array is ordered so that 13438 // each function with all its descendant is always stored in a continues range 13439 // with the function itself going first. The root function is a script function. 13440 RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) { 13441 HandleScope scope(isolate); 13442 CHECK(isolate->debug()->live_edit_enabled()); 13443 ASSERT(args.length() == 2); 13444 CONVERT_ARG_CHECKED(JSValue, script, 0); 13445 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13446 13447 RUNTIME_ASSERT(script->value()->IsScript()); 13448 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 13449 13450 Handle<JSArray> result; 13451 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 13452 isolate, result, LiveEdit::GatherCompileInfo(script_handle, source)); 13453 return *result; 13454 } 13455 13456 13457 // Changes the source of the script to a new_source. 13458 // If old_script_name is provided (i.e. is a String), also creates a copy of 13459 // the script with its original source and sends notification to debugger. 13460 RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) { 13461 HandleScope scope(isolate); 13462 CHECK(isolate->debug()->live_edit_enabled()); 13463 ASSERT(args.length() == 3); 13464 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); 13465 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); 13466 CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2); 13467 13468 RUNTIME_ASSERT(original_script_value->value()->IsScript()); 13469 Handle<Script> original_script(Script::cast(original_script_value->value())); 13470 13471 Handle<Object> old_script = LiveEdit::ChangeScriptSource( 13472 original_script, new_source, old_script_name); 13473 13474 if (old_script->IsScript()) { 13475 Handle<Script> script_handle = Handle<Script>::cast(old_script); 13476 return *Script::GetWrapper(script_handle); 13477 } else { 13478 return isolate->heap()->null_value(); 13479 } 13480 } 13481 13482 13483 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) { 13484 HandleScope scope(isolate); 13485 CHECK(isolate->debug()->live_edit_enabled()); 13486 ASSERT(args.length() == 1); 13487 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); 13488 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); 13489 13490 LiveEdit::FunctionSourceUpdated(shared_info); 13491 return isolate->heap()->undefined_value(); 13492 } 13493 13494 13495 // Replaces code of SharedFunctionInfo with a new one. 13496 RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) { 13497 HandleScope scope(isolate); 13498 CHECK(isolate->debug()->live_edit_enabled()); 13499 ASSERT(args.length() == 2); 13500 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); 13501 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); 13502 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info)); 13503 13504 LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); 13505 return isolate->heap()->undefined_value(); 13506 } 13507 13508 13509 // Connects SharedFunctionInfo to another script. 13510 RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) { 13511 HandleScope scope(isolate); 13512 CHECK(isolate->debug()->live_edit_enabled()); 13513 ASSERT(args.length() == 2); 13514 CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0); 13515 CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1); 13516 13517 if (function_object->IsJSValue()) { 13518 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); 13519 if (script_object->IsJSValue()) { 13520 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); 13521 Script* script = Script::cast(JSValue::cast(*script_object)->value()); 13522 script_object = Handle<Object>(script, isolate); 13523 } 13524 RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo()); 13525 LiveEdit::SetFunctionScript(function_wrapper, script_object); 13526 } else { 13527 // Just ignore this. We may not have a SharedFunctionInfo for some functions 13528 // and we check it in this function. 13529 } 13530 13531 return isolate->heap()->undefined_value(); 13532 } 13533 13534 13535 // In a code of a parent function replaces original function as embedded object 13536 // with a substitution one. 13537 RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) { 13538 HandleScope scope(isolate); 13539 CHECK(isolate->debug()->live_edit_enabled()); 13540 ASSERT(args.length() == 3); 13541 13542 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); 13543 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); 13544 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); 13545 RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo()); 13546 RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo()); 13547 RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo()); 13548 13549 LiveEdit::ReplaceRefToNestedFunction( 13550 parent_wrapper, orig_wrapper, subst_wrapper); 13551 return isolate->heap()->undefined_value(); 13552 } 13553 13554 13555 // Updates positions of a shared function info (first parameter) according 13556 // to script source change. Text change is described in second parameter as 13557 // array of groups of 3 numbers: 13558 // (change_begin, change_end, change_end_new_position). 13559 // Each group describes a change in text; groups are sorted by change_begin. 13560 RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) { 13561 HandleScope scope(isolate); 13562 CHECK(isolate->debug()->live_edit_enabled()); 13563 ASSERT(args.length() == 2); 13564 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13565 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); 13566 RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array)) 13567 13568 LiveEdit::PatchFunctionPositions(shared_array, position_change_array); 13569 return isolate->heap()->undefined_value(); 13570 } 13571 13572 13573 // For array of SharedFunctionInfo's (each wrapped in JSValue) 13574 // checks that none of them have activations on stacks (of any thread). 13575 // Returns array of the same length with corresponding results of 13576 // LiveEdit::FunctionPatchabilityStatus type. 13577 RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) { 13578 HandleScope scope(isolate); 13579 CHECK(isolate->debug()->live_edit_enabled()); 13580 ASSERT(args.length() == 2); 13581 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13582 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); 13583 RUNTIME_ASSERT(shared_array->length()->IsSmi()); 13584 int array_length = Smi::cast(shared_array->length())->value(); 13585 for (int i = 0; i < array_length; i++) { 13586 Handle<Object> element = 13587 Object::GetElement(isolate, shared_array, i).ToHandleChecked(); 13588 RUNTIME_ASSERT( 13589 element->IsJSValue() && 13590 Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo()); 13591 } 13592 13593 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); 13594 } 13595 13596 13597 // Compares 2 strings line-by-line, then token-wise and returns diff in form 13598 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list 13599 // of diff chunks. 13600 RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) { 13601 HandleScope scope(isolate); 13602 CHECK(isolate->debug()->live_edit_enabled()); 13603 ASSERT(args.length() == 2); 13604 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); 13605 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); 13606 13607 return *LiveEdit::CompareStrings(s1, s2); 13608 } 13609 13610 13611 // Restarts a call frame and completely drops all frames above. 13612 // Returns true if successful. Otherwise returns undefined or an error message. 13613 RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) { 13614 HandleScope scope(isolate); 13615 CHECK(isolate->debug()->live_edit_enabled()); 13616 ASSERT(args.length() == 2); 13617 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 13618 RUNTIME_ASSERT(CheckExecutionState(isolate, break_id)); 13619 13620 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 13621 Heap* heap = isolate->heap(); 13622 13623 // Find the relevant frame with the requested index. 13624 StackFrame::Id id = isolate->debug()->break_frame_id(); 13625 if (id == StackFrame::NO_ID) { 13626 // If there are no JavaScript stack frames return undefined. 13627 return heap->undefined_value(); 13628 } 13629 13630 int count = 0; 13631 JavaScriptFrameIterator it(isolate, id); 13632 for (; !it.done(); it.Advance()) { 13633 if (index < count + it.frame()->GetInlineCount()) break; 13634 count += it.frame()->GetInlineCount(); 13635 } 13636 if (it.done()) return heap->undefined_value(); 13637 13638 const char* error_message = LiveEdit::RestartFrame(it.frame()); 13639 if (error_message) { 13640 return *(isolate->factory()->InternalizeUtf8String(error_message)); 13641 } 13642 return heap->true_value(); 13643 } 13644 13645 13646 // A testing entry. Returns statement position which is the closest to 13647 // source_position. 13648 RUNTIME_FUNCTION(Runtime_GetFunctionCodePositionFromSource) { 13649 HandleScope scope(isolate); 13650 CHECK(isolate->debug()->live_edit_enabled()); 13651 ASSERT(args.length() == 2); 13652 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13653 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 13654 13655 Handle<Code> code(function->code(), isolate); 13656 13657 if (code->kind() != Code::FUNCTION && 13658 code->kind() != Code::OPTIMIZED_FUNCTION) { 13659 return isolate->heap()->undefined_value(); 13660 } 13661 13662 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); 13663 int closest_pc = 0; 13664 int distance = kMaxInt; 13665 while (!it.done()) { 13666 int statement_position = static_cast<int>(it.rinfo()->data()); 13667 // Check if this break point is closer that what was previously found. 13668 if (source_position <= statement_position && 13669 statement_position - source_position < distance) { 13670 closest_pc = 13671 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 13672 distance = statement_position - source_position; 13673 // Check whether we can't get any closer. 13674 if (distance == 0) break; 13675 } 13676 it.next(); 13677 } 13678 13679 return Smi::FromInt(closest_pc); 13680 } 13681 13682 13683 // Calls specified function with or without entering the debugger. 13684 // This is used in unit tests to run code as if debugger is entered or simply 13685 // to have a stack with C++ frame in the middle. 13686 RUNTIME_FUNCTION(Runtime_ExecuteInDebugContext) { 13687 HandleScope scope(isolate); 13688 ASSERT(args.length() == 2); 13689 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13690 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); 13691 13692 MaybeHandle<Object> maybe_result; 13693 if (without_debugger) { 13694 maybe_result = Execution::Call(isolate, 13695 function, 13696 isolate->global_object(), 13697 0, 13698 NULL); 13699 } else { 13700 DebugScope debug_scope(isolate->debug()); 13701 maybe_result = Execution::Call(isolate, 13702 function, 13703 isolate->global_object(), 13704 0, 13705 NULL); 13706 } 13707 Handle<Object> result; 13708 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); 13709 return *result; 13710 } 13711 13712 13713 // Sets a v8 flag. 13714 RUNTIME_FUNCTION(Runtime_SetFlags) { 13715 SealHandleScope shs(isolate); 13716 ASSERT(args.length() == 1); 13717 CONVERT_ARG_CHECKED(String, arg, 0); 13718 SmartArrayPointer<char> flags = 13719 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 13720 FlagList::SetFlagsFromString(flags.get(), StrLength(flags.get())); 13721 return isolate->heap()->undefined_value(); 13722 } 13723 13724 13725 // Performs a GC. 13726 // Presently, it only does a full GC. 13727 RUNTIME_FUNCTION(Runtime_CollectGarbage) { 13728 SealHandleScope shs(isolate); 13729 ASSERT(args.length() == 1); 13730 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); 13731 return isolate->heap()->undefined_value(); 13732 } 13733 13734 13735 // Gets the current heap usage. 13736 RUNTIME_FUNCTION(Runtime_GetHeapUsage) { 13737 SealHandleScope shs(isolate); 13738 ASSERT(args.length() == 0); 13739 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 13740 if (!Smi::IsValid(usage)) { 13741 return *isolate->factory()->NewNumberFromInt(usage); 13742 } 13743 return Smi::FromInt(usage); 13744 } 13745 13746 13747 #ifdef V8_I18N_SUPPORT 13748 RUNTIME_FUNCTION(Runtime_CanonicalizeLanguageTag) { 13749 HandleScope scope(isolate); 13750 Factory* factory = isolate->factory(); 13751 13752 ASSERT(args.length() == 1); 13753 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); 13754 13755 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); 13756 13757 // Return value which denotes invalid language tag. 13758 const char* const kInvalidTag = "invalid-tag"; 13759 13760 UErrorCode error = U_ZERO_ERROR; 13761 char icu_result[ULOC_FULLNAME_CAPACITY]; 13762 int icu_length = 0; 13763 13764 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, 13765 &icu_length, &error); 13766 if (U_FAILURE(error) || icu_length == 0) { 13767 return *factory->NewStringFromAsciiChecked(kInvalidTag); 13768 } 13769 13770 char result[ULOC_FULLNAME_CAPACITY]; 13771 13772 // Force strict BCP47 rules. 13773 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); 13774 13775 if (U_FAILURE(error)) { 13776 return *factory->NewStringFromAsciiChecked(kInvalidTag); 13777 } 13778 13779 return *factory->NewStringFromAsciiChecked(result); 13780 } 13781 13782 13783 RUNTIME_FUNCTION(Runtime_AvailableLocalesOf) { 13784 HandleScope scope(isolate); 13785 Factory* factory = isolate->factory(); 13786 13787 ASSERT(args.length() == 1); 13788 CONVERT_ARG_HANDLE_CHECKED(String, service, 0); 13789 13790 const icu::Locale* available_locales = NULL; 13791 int32_t count = 0; 13792 13793 if (service->IsUtf8EqualTo(CStrVector("collator"))) { 13794 available_locales = icu::Collator::getAvailableLocales(count); 13795 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { 13796 available_locales = icu::NumberFormat::getAvailableLocales(count); 13797 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { 13798 available_locales = icu::DateFormat::getAvailableLocales(count); 13799 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { 13800 available_locales = icu::BreakIterator::getAvailableLocales(count); 13801 } 13802 13803 UErrorCode error = U_ZERO_ERROR; 13804 char result[ULOC_FULLNAME_CAPACITY]; 13805 Handle<JSObject> locales = 13806 factory->NewJSObject(isolate->object_function()); 13807 13808 for (int32_t i = 0; i < count; ++i) { 13809 const char* icu_name = available_locales[i].getName(); 13810 13811 error = U_ZERO_ERROR; 13812 // No need to force strict BCP47 rules. 13813 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13814 if (U_FAILURE(error)) { 13815 // This shouldn't happen, but lets not break the user. 13816 continue; 13817 } 13818 13819 RETURN_FAILURE_ON_EXCEPTION(isolate, 13820 JSObject::SetOwnPropertyIgnoreAttributes( 13821 locales, 13822 factory->NewStringFromAsciiChecked(result), 13823 factory->NewNumber(i), 13824 NONE)); 13825 } 13826 13827 return *locales; 13828 } 13829 13830 13831 RUNTIME_FUNCTION(Runtime_GetDefaultICULocale) { 13832 HandleScope scope(isolate); 13833 Factory* factory = isolate->factory(); 13834 13835 ASSERT(args.length() == 0); 13836 13837 icu::Locale default_locale; 13838 13839 // Set the locale 13840 char result[ULOC_FULLNAME_CAPACITY]; 13841 UErrorCode status = U_ZERO_ERROR; 13842 uloc_toLanguageTag( 13843 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); 13844 if (U_SUCCESS(status)) { 13845 return *factory->NewStringFromAsciiChecked(result); 13846 } 13847 13848 return *factory->NewStringFromStaticAscii("und"); 13849 } 13850 13851 13852 RUNTIME_FUNCTION(Runtime_GetLanguageTagVariants) { 13853 HandleScope scope(isolate); 13854 Factory* factory = isolate->factory(); 13855 13856 ASSERT(args.length() == 1); 13857 13858 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); 13859 13860 uint32_t length = static_cast<uint32_t>(input->length()->Number()); 13861 // Set some limit to prevent fuzz tests from going OOM. 13862 // Can be bumped when callers' requirements change. 13863 RUNTIME_ASSERT(length < 100); 13864 Handle<FixedArray> output = factory->NewFixedArray(length); 13865 Handle<Name> maximized = factory->NewStringFromStaticAscii("maximized"); 13866 Handle<Name> base = factory->NewStringFromStaticAscii("base"); 13867 for (unsigned int i = 0; i < length; ++i) { 13868 Handle<Object> locale_id; 13869 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 13870 isolate, locale_id, Object::GetElement(isolate, input, i)); 13871 if (!locale_id->IsString()) { 13872 return isolate->Throw(*factory->illegal_argument_string()); 13873 } 13874 13875 v8::String::Utf8Value utf8_locale_id( 13876 v8::Utils::ToLocal(Handle<String>::cast(locale_id))); 13877 13878 UErrorCode error = U_ZERO_ERROR; 13879 13880 // Convert from BCP47 to ICU format. 13881 // de-DE-u-co-phonebk -> de_DE@collation=phonebook 13882 char icu_locale[ULOC_FULLNAME_CAPACITY]; 13883 int icu_locale_length = 0; 13884 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, 13885 &icu_locale_length, &error); 13886 if (U_FAILURE(error) || icu_locale_length == 0) { 13887 return isolate->Throw(*factory->illegal_argument_string()); 13888 } 13889 13890 // Maximize the locale. 13891 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook 13892 char icu_max_locale[ULOC_FULLNAME_CAPACITY]; 13893 uloc_addLikelySubtags( 13894 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13895 13896 // Remove extensions from maximized locale. 13897 // de_Latn_DE@collation=phonebook -> de_Latn_DE 13898 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; 13899 uloc_getBaseName( 13900 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13901 13902 // Get original name without extensions. 13903 // de_DE@collation=phonebook -> de_DE 13904 char icu_base_locale[ULOC_FULLNAME_CAPACITY]; 13905 uloc_getBaseName( 13906 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); 13907 13908 // Convert from ICU locale format to BCP47 format. 13909 // de_Latn_DE -> de-Latn-DE 13910 char base_max_locale[ULOC_FULLNAME_CAPACITY]; 13911 uloc_toLanguageTag(icu_base_max_locale, base_max_locale, 13912 ULOC_FULLNAME_CAPACITY, FALSE, &error); 13913 13914 // de_DE -> de-DE 13915 char base_locale[ULOC_FULLNAME_CAPACITY]; 13916 uloc_toLanguageTag( 13917 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13918 13919 if (U_FAILURE(error)) { 13920 return isolate->Throw(*factory->illegal_argument_string()); 13921 } 13922 13923 Handle<JSObject> result = factory->NewJSObject(isolate->object_function()); 13924 RETURN_FAILURE_ON_EXCEPTION(isolate, 13925 JSObject::SetOwnPropertyIgnoreAttributes( 13926 result, 13927 maximized, 13928 factory->NewStringFromAsciiChecked(base_max_locale), 13929 NONE)); 13930 RETURN_FAILURE_ON_EXCEPTION(isolate, 13931 JSObject::SetOwnPropertyIgnoreAttributes( 13932 result, 13933 base, 13934 factory->NewStringFromAsciiChecked(base_locale), 13935 NONE)); 13936 output->set(i, *result); 13937 } 13938 13939 Handle<JSArray> result = factory->NewJSArrayWithElements(output); 13940 result->set_length(Smi::FromInt(length)); 13941 return *result; 13942 } 13943 13944 13945 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObject) { 13946 HandleScope scope(isolate); 13947 13948 ASSERT(args.length() == 1); 13949 13950 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 13951 13952 if (!input->IsJSObject()) return isolate->heap()->false_value(); 13953 Handle<JSObject> obj = Handle<JSObject>::cast(input); 13954 13955 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); 13956 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); 13957 return isolate->heap()->ToBoolean(!tag->IsTheHole()); 13958 } 13959 13960 13961 RUNTIME_FUNCTION(Runtime_IsInitializedIntlObjectOfType) { 13962 HandleScope scope(isolate); 13963 13964 ASSERT(args.length() == 2); 13965 13966 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 13967 CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1); 13968 13969 if (!input->IsJSObject()) return isolate->heap()->false_value(); 13970 Handle<JSObject> obj = Handle<JSObject>::cast(input); 13971 13972 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); 13973 Handle<Object> tag(obj->GetHiddenProperty(marker), isolate); 13974 return isolate->heap()->ToBoolean( 13975 tag->IsString() && String::cast(*tag)->Equals(*expected_type)); 13976 } 13977 13978 13979 RUNTIME_FUNCTION(Runtime_MarkAsInitializedIntlObjectOfType) { 13980 HandleScope scope(isolate); 13981 13982 ASSERT(args.length() == 3); 13983 13984 CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0); 13985 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 13986 CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2); 13987 13988 Handle<String> marker = isolate->factory()->intl_initialized_marker_string(); 13989 JSObject::SetHiddenProperty(input, marker, type); 13990 13991 marker = isolate->factory()->intl_impl_object_string(); 13992 JSObject::SetHiddenProperty(input, marker, impl); 13993 13994 return isolate->heap()->undefined_value(); 13995 } 13996 13997 13998 RUNTIME_FUNCTION(Runtime_GetImplFromInitializedIntlObject) { 13999 HandleScope scope(isolate); 14000 14001 ASSERT(args.length() == 1); 14002 14003 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0); 14004 14005 if (!input->IsJSObject()) { 14006 Vector< Handle<Object> > arguments = HandleVector(&input, 1); 14007 Handle<Object> type_error = 14008 isolate->factory()->NewTypeError("not_intl_object", arguments); 14009 return isolate->Throw(*type_error); 14010 } 14011 14012 Handle<JSObject> obj = Handle<JSObject>::cast(input); 14013 14014 Handle<String> marker = isolate->factory()->intl_impl_object_string(); 14015 Handle<Object> impl(obj->GetHiddenProperty(marker), isolate); 14016 if (impl->IsTheHole()) { 14017 Vector< Handle<Object> > arguments = HandleVector(&obj, 1); 14018 Handle<Object> type_error = 14019 isolate->factory()->NewTypeError("not_intl_object", arguments); 14020 return isolate->Throw(*type_error); 14021 } 14022 return *impl; 14023 } 14024 14025 14026 RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) { 14027 HandleScope scope(isolate); 14028 14029 ASSERT(args.length() == 3); 14030 14031 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14032 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14033 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14034 14035 Handle<ObjectTemplateInfo> date_format_template = 14036 I18N::GetTemplate(isolate); 14037 14038 // Create an empty object wrapper. 14039 Handle<JSObject> local_object; 14040 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14041 isolate, local_object, 14042 Execution::InstantiateObject(date_format_template)); 14043 14044 // Set date time formatter as internal field of the resulting JS object. 14045 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( 14046 isolate, locale, options, resolved); 14047 14048 if (!date_format) return isolate->ThrowIllegalOperation(); 14049 14050 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); 14051 14052 RETURN_FAILURE_ON_EXCEPTION(isolate, 14053 JSObject::SetOwnPropertyIgnoreAttributes( 14054 local_object, 14055 isolate->factory()->NewStringFromStaticAscii("dateFormat"), 14056 isolate->factory()->NewStringFromStaticAscii("valid"), 14057 NONE)); 14058 14059 // Make object handle weak so we can delete the data format once GC kicks in. 14060 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14061 GlobalHandles::MakeWeak(wrapper.location(), 14062 reinterpret_cast<void*>(wrapper.location()), 14063 DateFormat::DeleteDateFormat); 14064 return *local_object; 14065 } 14066 14067 14068 RUNTIME_FUNCTION(Runtime_InternalDateFormat) { 14069 HandleScope scope(isolate); 14070 14071 ASSERT(args.length() == 2); 14072 14073 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 14074 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); 14075 14076 Handle<Object> value; 14077 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14078 isolate, value, Execution::ToNumber(isolate, date)); 14079 14080 icu::SimpleDateFormat* date_format = 14081 DateFormat::UnpackDateFormat(isolate, date_format_holder); 14082 if (!date_format) return isolate->ThrowIllegalOperation(); 14083 14084 icu::UnicodeString result; 14085 date_format->format(value->Number(), result); 14086 14087 Handle<String> result_str; 14088 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14089 isolate, result_str, 14090 isolate->factory()->NewStringFromTwoByte( 14091 Vector<const uint16_t>( 14092 reinterpret_cast<const uint16_t*>(result.getBuffer()), 14093 result.length()))); 14094 return *result_str; 14095 } 14096 14097 14098 RUNTIME_FUNCTION(Runtime_InternalDateParse) { 14099 HandleScope scope(isolate); 14100 14101 ASSERT(args.length() == 2); 14102 14103 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 14104 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1); 14105 14106 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string)); 14107 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date)); 14108 icu::SimpleDateFormat* date_format = 14109 DateFormat::UnpackDateFormat(isolate, date_format_holder); 14110 if (!date_format) return isolate->ThrowIllegalOperation(); 14111 14112 UErrorCode status = U_ZERO_ERROR; 14113 UDate date = date_format->parse(u_date, status); 14114 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 14115 14116 Handle<Object> result; 14117 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14118 isolate, result, 14119 Execution::NewDate(isolate, static_cast<double>(date))); 14120 ASSERT(result->IsJSDate()); 14121 return *result; 14122 } 14123 14124 14125 RUNTIME_FUNCTION(Runtime_CreateNumberFormat) { 14126 HandleScope scope(isolate); 14127 14128 ASSERT(args.length() == 3); 14129 14130 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14131 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14132 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14133 14134 Handle<ObjectTemplateInfo> number_format_template = 14135 I18N::GetTemplate(isolate); 14136 14137 // Create an empty object wrapper. 14138 Handle<JSObject> local_object; 14139 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14140 isolate, local_object, 14141 Execution::InstantiateObject(number_format_template)); 14142 14143 // Set number formatter as internal field of the resulting JS object. 14144 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( 14145 isolate, locale, options, resolved); 14146 14147 if (!number_format) return isolate->ThrowIllegalOperation(); 14148 14149 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); 14150 14151 RETURN_FAILURE_ON_EXCEPTION(isolate, 14152 JSObject::SetOwnPropertyIgnoreAttributes( 14153 local_object, 14154 isolate->factory()->NewStringFromStaticAscii("numberFormat"), 14155 isolate->factory()->NewStringFromStaticAscii("valid"), 14156 NONE)); 14157 14158 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14159 GlobalHandles::MakeWeak(wrapper.location(), 14160 reinterpret_cast<void*>(wrapper.location()), 14161 NumberFormat::DeleteNumberFormat); 14162 return *local_object; 14163 } 14164 14165 14166 RUNTIME_FUNCTION(Runtime_InternalNumberFormat) { 14167 HandleScope scope(isolate); 14168 14169 ASSERT(args.length() == 2); 14170 14171 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 14172 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); 14173 14174 Handle<Object> value; 14175 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14176 isolate, value, Execution::ToNumber(isolate, number)); 14177 14178 icu::DecimalFormat* number_format = 14179 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 14180 if (!number_format) return isolate->ThrowIllegalOperation(); 14181 14182 icu::UnicodeString result; 14183 number_format->format(value->Number(), result); 14184 14185 Handle<String> result_str; 14186 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14187 isolate, result_str, 14188 isolate->factory()->NewStringFromTwoByte( 14189 Vector<const uint16_t>( 14190 reinterpret_cast<const uint16_t*>(result.getBuffer()), 14191 result.length()))); 14192 return *result_str; 14193 } 14194 14195 14196 RUNTIME_FUNCTION(Runtime_InternalNumberParse) { 14197 HandleScope scope(isolate); 14198 14199 ASSERT(args.length() == 2); 14200 14201 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 14202 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1); 14203 14204 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string)); 14205 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number)); 14206 icu::DecimalFormat* number_format = 14207 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 14208 if (!number_format) return isolate->ThrowIllegalOperation(); 14209 14210 UErrorCode status = U_ZERO_ERROR; 14211 icu::Formattable result; 14212 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 14213 // to be part of Chrome. 14214 // TODO(cira): Include currency parsing code using parseCurrency call. 14215 // We need to check if the formatter parses all currencies or only the 14216 // one it was constructed with (it will impact the API - how to return ISO 14217 // code and the value). 14218 number_format->parse(u_number, result, status); 14219 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 14220 14221 switch (result.getType()) { 14222 case icu::Formattable::kDouble: 14223 return *isolate->factory()->NewNumber(result.getDouble()); 14224 case icu::Formattable::kLong: 14225 return *isolate->factory()->NewNumberFromInt(result.getLong()); 14226 case icu::Formattable::kInt64: 14227 return *isolate->factory()->NewNumber( 14228 static_cast<double>(result.getInt64())); 14229 default: 14230 return isolate->heap()->undefined_value(); 14231 } 14232 } 14233 14234 14235 RUNTIME_FUNCTION(Runtime_CreateCollator) { 14236 HandleScope scope(isolate); 14237 14238 ASSERT(args.length() == 3); 14239 14240 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14241 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14242 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14243 14244 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); 14245 14246 // Create an empty object wrapper. 14247 Handle<JSObject> local_object; 14248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14249 isolate, local_object, Execution::InstantiateObject(collator_template)); 14250 14251 // Set collator as internal field of the resulting JS object. 14252 icu::Collator* collator = Collator::InitializeCollator( 14253 isolate, locale, options, resolved); 14254 14255 if (!collator) return isolate->ThrowIllegalOperation(); 14256 14257 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); 14258 14259 RETURN_FAILURE_ON_EXCEPTION(isolate, 14260 JSObject::SetOwnPropertyIgnoreAttributes( 14261 local_object, 14262 isolate->factory()->NewStringFromStaticAscii("collator"), 14263 isolate->factory()->NewStringFromStaticAscii("valid"), 14264 NONE)); 14265 14266 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14267 GlobalHandles::MakeWeak(wrapper.location(), 14268 reinterpret_cast<void*>(wrapper.location()), 14269 Collator::DeleteCollator); 14270 return *local_object; 14271 } 14272 14273 14274 RUNTIME_FUNCTION(Runtime_InternalCompare) { 14275 HandleScope scope(isolate); 14276 14277 ASSERT(args.length() == 3); 14278 14279 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0); 14280 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1); 14281 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2); 14282 14283 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder); 14284 if (!collator) return isolate->ThrowIllegalOperation(); 14285 14286 v8::String::Value string_value1(v8::Utils::ToLocal(string1)); 14287 v8::String::Value string_value2(v8::Utils::ToLocal(string2)); 14288 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1); 14289 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2); 14290 UErrorCode status = U_ZERO_ERROR; 14291 UCollationResult result = collator->compare(u_string1, 14292 string_value1.length(), 14293 u_string2, 14294 string_value2.length(), 14295 status); 14296 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation(); 14297 14298 return *isolate->factory()->NewNumberFromInt(result); 14299 } 14300 14301 14302 RUNTIME_FUNCTION(Runtime_StringNormalize) { 14303 HandleScope scope(isolate); 14304 static const UNormalizationMode normalizationForms[] = 14305 { UNORM_NFC, UNORM_NFD, UNORM_NFKC, UNORM_NFKD }; 14306 14307 ASSERT(args.length() == 2); 14308 14309 CONVERT_ARG_HANDLE_CHECKED(String, stringValue, 0); 14310 CONVERT_NUMBER_CHECKED(int, form_id, Int32, args[1]); 14311 RUNTIME_ASSERT(form_id >= 0 && 14312 static_cast<size_t>(form_id) < ARRAY_SIZE(normalizationForms)); 14313 14314 v8::String::Value string_value(v8::Utils::ToLocal(stringValue)); 14315 const UChar* u_value = reinterpret_cast<const UChar*>(*string_value); 14316 14317 // TODO(mnita): check Normalizer2 (not available in ICU 46) 14318 UErrorCode status = U_ZERO_ERROR; 14319 icu::UnicodeString result; 14320 icu::Normalizer::normalize(u_value, normalizationForms[form_id], 0, 14321 result, status); 14322 if (U_FAILURE(status)) { 14323 return isolate->heap()->undefined_value(); 14324 } 14325 14326 Handle<String> result_str; 14327 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14328 isolate, result_str, 14329 isolate->factory()->NewStringFromTwoByte( 14330 Vector<const uint16_t>( 14331 reinterpret_cast<const uint16_t*>(result.getBuffer()), 14332 result.length()))); 14333 return *result_str; 14334 } 14335 14336 14337 RUNTIME_FUNCTION(Runtime_CreateBreakIterator) { 14338 HandleScope scope(isolate); 14339 14340 ASSERT(args.length() == 3); 14341 14342 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14343 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14344 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14345 14346 Handle<ObjectTemplateInfo> break_iterator_template = 14347 I18N::GetTemplate2(isolate); 14348 14349 // Create an empty object wrapper. 14350 Handle<JSObject> local_object; 14351 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14352 isolate, local_object, 14353 Execution::InstantiateObject(break_iterator_template)); 14354 14355 // Set break iterator as internal field of the resulting JS object. 14356 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator( 14357 isolate, locale, options, resolved); 14358 14359 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14360 14361 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator)); 14362 // Make sure that the pointer to adopted text is NULL. 14363 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL)); 14364 14365 RETURN_FAILURE_ON_EXCEPTION(isolate, 14366 JSObject::SetOwnPropertyIgnoreAttributes( 14367 local_object, 14368 isolate->factory()->NewStringFromStaticAscii("breakIterator"), 14369 isolate->factory()->NewStringFromStaticAscii("valid"), 14370 NONE)); 14371 14372 // Make object handle weak so we can delete the break iterator once GC kicks 14373 // in. 14374 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14375 GlobalHandles::MakeWeak(wrapper.location(), 14376 reinterpret_cast<void*>(wrapper.location()), 14377 BreakIterator::DeleteBreakIterator); 14378 return *local_object; 14379 } 14380 14381 14382 RUNTIME_FUNCTION(Runtime_BreakIteratorAdoptText) { 14383 HandleScope scope(isolate); 14384 14385 ASSERT(args.length() == 2); 14386 14387 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14388 CONVERT_ARG_HANDLE_CHECKED(String, text, 1); 14389 14390 icu::BreakIterator* break_iterator = 14391 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14392 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14393 14394 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>( 14395 break_iterator_holder->GetInternalField(1)); 14396 delete u_text; 14397 14398 v8::String::Value text_value(v8::Utils::ToLocal(text)); 14399 u_text = new icu::UnicodeString( 14400 reinterpret_cast<const UChar*>(*text_value), text_value.length()); 14401 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text)); 14402 14403 break_iterator->setText(*u_text); 14404 14405 return isolate->heap()->undefined_value(); 14406 } 14407 14408 14409 RUNTIME_FUNCTION(Runtime_BreakIteratorFirst) { 14410 HandleScope scope(isolate); 14411 14412 ASSERT(args.length() == 1); 14413 14414 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14415 14416 icu::BreakIterator* break_iterator = 14417 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14418 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14419 14420 return *isolate->factory()->NewNumberFromInt(break_iterator->first()); 14421 } 14422 14423 14424 RUNTIME_FUNCTION(Runtime_BreakIteratorNext) { 14425 HandleScope scope(isolate); 14426 14427 ASSERT(args.length() == 1); 14428 14429 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14430 14431 icu::BreakIterator* break_iterator = 14432 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14433 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14434 14435 return *isolate->factory()->NewNumberFromInt(break_iterator->next()); 14436 } 14437 14438 14439 RUNTIME_FUNCTION(Runtime_BreakIteratorCurrent) { 14440 HandleScope scope(isolate); 14441 14442 ASSERT(args.length() == 1); 14443 14444 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14445 14446 icu::BreakIterator* break_iterator = 14447 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14448 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14449 14450 return *isolate->factory()->NewNumberFromInt(break_iterator->current()); 14451 } 14452 14453 14454 RUNTIME_FUNCTION(Runtime_BreakIteratorBreakType) { 14455 HandleScope scope(isolate); 14456 14457 ASSERT(args.length() == 1); 14458 14459 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14460 14461 icu::BreakIterator* break_iterator = 14462 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14463 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14464 14465 // TODO(cira): Remove cast once ICU fixes base BreakIterator class. 14466 icu::RuleBasedBreakIterator* rule_based_iterator = 14467 static_cast<icu::RuleBasedBreakIterator*>(break_iterator); 14468 int32_t status = rule_based_iterator->getRuleStatus(); 14469 // Keep return values in sync with JavaScript BreakType enum. 14470 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { 14471 return *isolate->factory()->NewStringFromStaticAscii("none"); 14472 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { 14473 return *isolate->factory()->NewStringFromStaticAscii("number"); 14474 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { 14475 return *isolate->factory()->NewStringFromStaticAscii("letter"); 14476 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { 14477 return *isolate->factory()->NewStringFromStaticAscii("kana"); 14478 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { 14479 return *isolate->factory()->NewStringFromStaticAscii("ideo"); 14480 } else { 14481 return *isolate->factory()->NewStringFromStaticAscii("unknown"); 14482 } 14483 } 14484 #endif // V8_I18N_SUPPORT 14485 14486 14487 // Finds the script object from the script data. NOTE: This operation uses 14488 // heap traversal to find the function generated for the source position 14489 // for the requested break point. For lazily compiled functions several heap 14490 // traversals might be required rendering this operation as a rather slow 14491 // operation. However for setting break points which is normally done through 14492 // some kind of user interaction the performance is not crucial. 14493 static Handle<Object> Runtime_GetScriptFromScriptName( 14494 Handle<String> script_name) { 14495 // Scan the heap for Script objects to find the script with the requested 14496 // script data. 14497 Handle<Script> script; 14498 Factory* factory = script_name->GetIsolate()->factory(); 14499 Heap* heap = script_name->GetHeap(); 14500 HeapIterator iterator(heap); 14501 HeapObject* obj = NULL; 14502 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 14503 // If a script is found check if it has the script data requested. 14504 if (obj->IsScript()) { 14505 if (Script::cast(obj)->name()->IsString()) { 14506 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 14507 script = Handle<Script>(Script::cast(obj)); 14508 } 14509 } 14510 } 14511 } 14512 14513 // If no script with the requested script data is found return undefined. 14514 if (script.is_null()) return factory->undefined_value(); 14515 14516 // Return the script found. 14517 return Script::GetWrapper(script); 14518 } 14519 14520 14521 // Get the script object from script data. NOTE: Regarding performance 14522 // see the NOTE for GetScriptFromScriptData. 14523 // args[0]: script data for the script to find the source for 14524 RUNTIME_FUNCTION(Runtime_GetScript) { 14525 HandleScope scope(isolate); 14526 14527 ASSERT(args.length() == 1); 14528 14529 CONVERT_ARG_CHECKED(String, script_name, 0); 14530 14531 // Find the requested script. 14532 Handle<Object> result = 14533 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 14534 return *result; 14535 } 14536 14537 14538 // Collect the raw data for a stack trace. Returns an array of 4 14539 // element segments each containing a receiver, function, code and 14540 // native code offset. 14541 RUNTIME_FUNCTION(Runtime_CollectStackTrace) { 14542 HandleScope scope(isolate); 14543 ASSERT(args.length() == 3); 14544 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 14545 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1); 14546 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); 14547 14548 // Optionally capture a more detailed stack trace for the message. 14549 isolate->CaptureAndSetDetailedStackTrace(error_object); 14550 // Capture a simple stack trace for the stack property. 14551 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit); 14552 } 14553 14554 14555 // Retrieve the stack trace. This is the raw stack trace that yet has to 14556 // be formatted. Since we only need this once, clear it afterwards. 14557 RUNTIME_FUNCTION(Runtime_GetAndClearOverflowedStackTrace) { 14558 HandleScope scope(isolate); 14559 ASSERT(args.length() == 1); 14560 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 14561 Handle<String> key = isolate->factory()->hidden_stack_trace_string(); 14562 Handle<Object> result(error_object->GetHiddenProperty(key), isolate); 14563 if (result->IsTheHole()) return isolate->heap()->undefined_value(); 14564 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined()); 14565 JSObject::DeleteHiddenProperty(error_object, key); 14566 return *result; 14567 } 14568 14569 14570 // Returns V8 version as a string. 14571 RUNTIME_FUNCTION(Runtime_GetV8Version) { 14572 HandleScope scope(isolate); 14573 ASSERT(args.length() == 0); 14574 14575 const char* version_string = v8::V8::GetVersion(); 14576 14577 return *isolate->factory()->NewStringFromAsciiChecked(version_string); 14578 } 14579 14580 14581 RUNTIME_FUNCTION(Runtime_Abort) { 14582 SealHandleScope shs(isolate); 14583 ASSERT(args.length() == 1); 14584 CONVERT_SMI_ARG_CHECKED(message_id, 0); 14585 const char* message = GetBailoutReason( 14586 static_cast<BailoutReason>(message_id)); 14587 OS::PrintError("abort: %s\n", message); 14588 isolate->PrintStack(stderr); 14589 OS::Abort(); 14590 UNREACHABLE(); 14591 return NULL; 14592 } 14593 14594 14595 RUNTIME_FUNCTION(Runtime_AbortJS) { 14596 HandleScope scope(isolate); 14597 ASSERT(args.length() == 1); 14598 CONVERT_ARG_HANDLE_CHECKED(String, message, 0); 14599 OS::PrintError("abort: %s\n", message->ToCString().get()); 14600 isolate->PrintStack(stderr); 14601 OS::Abort(); 14602 UNREACHABLE(); 14603 return NULL; 14604 } 14605 14606 14607 RUNTIME_FUNCTION(Runtime_FlattenString) { 14608 HandleScope scope(isolate); 14609 ASSERT(args.length() == 1); 14610 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 14611 return *String::Flatten(str); 14612 } 14613 14614 14615 RUNTIME_FUNCTION(Runtime_NotifyContextDisposed) { 14616 HandleScope scope(isolate); 14617 ASSERT(args.length() == 0); 14618 isolate->heap()->NotifyContextDisposed(); 14619 return isolate->heap()->undefined_value(); 14620 } 14621 14622 14623 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) { 14624 HandleScope scope(isolate); 14625 ASSERT(args.length() == 2); 14626 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 14627 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1); 14628 RUNTIME_ASSERT((index->value() & 1) == 1); 14629 FieldIndex field_index = 14630 FieldIndex::ForLoadByFieldIndex(object->map(), index->value()); 14631 if (field_index.is_inobject()) { 14632 RUNTIME_ASSERT(field_index.property_index() < 14633 object->map()->inobject_properties()); 14634 } else { 14635 RUNTIME_ASSERT(field_index.outobject_array_index() < 14636 object->properties()->length()); 14637 } 14638 Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate); 14639 RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized()); 14640 return *Object::NewStorageFor(isolate, raw_value, Representation::Double()); 14641 } 14642 14643 14644 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) { 14645 HandleScope scope(isolate); 14646 ASSERT(args.length() == 1); 14647 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 14648 if (!object->IsJSObject()) return Smi::FromInt(0); 14649 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 14650 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); 14651 // This call must not cause lazy deopts, because it's called from deferred 14652 // code where we can't handle lazy deopts for lack of a suitable bailout 14653 // ID. So we just try migration and signal failure if necessary, 14654 // which will also trigger a deopt. 14655 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0); 14656 return *object; 14657 } 14658 14659 14660 RUNTIME_FUNCTION(RuntimeHidden_GetFromCache) { 14661 SealHandleScope shs(isolate); 14662 // This is only called from codegen, so checks might be more lax. 14663 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); 14664 CONVERT_ARG_CHECKED(Object, key, 1); 14665 14666 { 14667 DisallowHeapAllocation no_alloc; 14668 14669 int finger_index = cache->finger_index(); 14670 Object* o = cache->get(finger_index); 14671 if (o == key) { 14672 // The fastest case: hit the same place again. 14673 return cache->get(finger_index + 1); 14674 } 14675 14676 for (int i = finger_index - 2; 14677 i >= JSFunctionResultCache::kEntriesIndex; 14678 i -= 2) { 14679 o = cache->get(i); 14680 if (o == key) { 14681 cache->set_finger_index(i); 14682 return cache->get(i + 1); 14683 } 14684 } 14685 14686 int size = cache->size(); 14687 ASSERT(size <= cache->length()); 14688 14689 for (int i = size - 2; i > finger_index; i -= 2) { 14690 o = cache->get(i); 14691 if (o == key) { 14692 cache->set_finger_index(i); 14693 return cache->get(i + 1); 14694 } 14695 } 14696 } 14697 14698 // There is no value in the cache. Invoke the function and cache result. 14699 HandleScope scope(isolate); 14700 14701 Handle<JSFunctionResultCache> cache_handle(cache); 14702 Handle<Object> key_handle(key, isolate); 14703 Handle<Object> value; 14704 { 14705 Handle<JSFunction> factory(JSFunction::cast( 14706 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); 14707 // TODO(antonm): consider passing a receiver when constructing a cache. 14708 Handle<Object> receiver(isolate->native_context()->global_object(), 14709 isolate); 14710 // This handle is nor shared, nor used later, so it's safe. 14711 Handle<Object> argv[] = { key_handle }; 14712 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 14713 isolate, value, 14714 Execution::Call(isolate, factory, receiver, ARRAY_SIZE(argv), argv)); 14715 } 14716 14717 #ifdef VERIFY_HEAP 14718 if (FLAG_verify_heap) { 14719 cache_handle->JSFunctionResultCacheVerify(); 14720 } 14721 #endif 14722 14723 // Function invocation may have cleared the cache. Reread all the data. 14724 int finger_index = cache_handle->finger_index(); 14725 int size = cache_handle->size(); 14726 14727 // If we have spare room, put new data into it, otherwise evict post finger 14728 // entry which is likely to be the least recently used. 14729 int index = -1; 14730 if (size < cache_handle->length()) { 14731 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); 14732 index = size; 14733 } else { 14734 index = finger_index + JSFunctionResultCache::kEntrySize; 14735 if (index == cache_handle->length()) { 14736 index = JSFunctionResultCache::kEntriesIndex; 14737 } 14738 } 14739 14740 ASSERT(index % 2 == 0); 14741 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); 14742 ASSERT(index < cache_handle->length()); 14743 14744 cache_handle->set(index, *key_handle); 14745 cache_handle->set(index + 1, *value); 14746 cache_handle->set_finger_index(index); 14747 14748 #ifdef VERIFY_HEAP 14749 if (FLAG_verify_heap) { 14750 cache_handle->JSFunctionResultCacheVerify(); 14751 } 14752 #endif 14753 14754 return *value; 14755 } 14756 14757 14758 RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) { 14759 SealHandleScope shs(isolate); 14760 ASSERT(args.length() == 1); 14761 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14762 return Smi::FromInt(message->start_position()); 14763 } 14764 14765 14766 RUNTIME_FUNCTION(Runtime_MessageGetScript) { 14767 SealHandleScope shs(isolate); 14768 ASSERT(args.length() == 1); 14769 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14770 return message->script(); 14771 } 14772 14773 14774 #ifdef DEBUG 14775 // ListNatives is ONLY used by the fuzz-natives.js in debug mode 14776 // Exclude the code in release mode. 14777 RUNTIME_FUNCTION(Runtime_ListNatives) { 14778 HandleScope scope(isolate); 14779 ASSERT(args.length() == 0); 14780 #define COUNT_ENTRY(Name, argc, ressize) + 1 14781 int entry_count = 0 14782 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) 14783 RUNTIME_HIDDEN_FUNCTION_LIST(COUNT_ENTRY) 14784 INLINE_FUNCTION_LIST(COUNT_ENTRY) 14785 INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY); 14786 #undef COUNT_ENTRY 14787 Factory* factory = isolate->factory(); 14788 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); 14789 int index = 0; 14790 bool inline_runtime_functions = false; 14791 #define ADD_ENTRY(Name, argc, ressize) \ 14792 { \ 14793 HandleScope inner(isolate); \ 14794 Handle<String> name; \ 14795 /* Inline runtime functions have an underscore in front of the name. */ \ 14796 if (inline_runtime_functions) { \ 14797 name = factory->NewStringFromStaticAscii("_" #Name); \ 14798 } else { \ 14799 name = factory->NewStringFromStaticAscii(#Name); \ 14800 } \ 14801 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ 14802 pair_elements->set(0, *name); \ 14803 pair_elements->set(1, Smi::FromInt(argc)); \ 14804 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ 14805 elements->set(index++, *pair); \ 14806 } 14807 inline_runtime_functions = false; 14808 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 14809 INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY) 14810 // Calling hidden runtime functions should just throw. 14811 RUNTIME_HIDDEN_FUNCTION_LIST(ADD_ENTRY) 14812 inline_runtime_functions = true; 14813 INLINE_FUNCTION_LIST(ADD_ENTRY) 14814 #undef ADD_ENTRY 14815 ASSERT_EQ(index, entry_count); 14816 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); 14817 return *result; 14818 } 14819 #endif 14820 14821 14822 RUNTIME_FUNCTION(Runtime_IS_VAR) { 14823 UNREACHABLE(); // implemented as macro in the parser 14824 return NULL; 14825 } 14826 14827 14828 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 14829 RUNTIME_FUNCTION(Runtime_Has##Name) { \ 14830 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 14831 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 14832 } 14833 14834 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) 14835 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) 14836 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) 14837 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 14838 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) 14839 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 14840 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) 14841 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) 14842 // Properties test sitting with elements tests - not fooling anyone. 14843 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) 14844 14845 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 14846 14847 14848 #define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \ 14849 RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \ 14850 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 14851 return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \ 14852 } 14853 14854 TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) 14855 14856 #undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION 14857 14858 14859 #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ 14860 RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ 14861 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 14862 return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \ 14863 } 14864 14865 TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) 14866 14867 #undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION 14868 14869 14870 RUNTIME_FUNCTION(Runtime_HaveSameMap) { 14871 SealHandleScope shs(isolate); 14872 ASSERT(args.length() == 2); 14873 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 14874 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 14875 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 14876 } 14877 14878 14879 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) { 14880 SealHandleScope shs(isolate); 14881 ASSERT(args.length() == 1); 14882 CONVERT_ARG_CHECKED(Object, obj, 0); 14883 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy()); 14884 } 14885 14886 14887 RUNTIME_FUNCTION(Runtime_IsObserved) { 14888 SealHandleScope shs(isolate); 14889 ASSERT(args.length() == 1); 14890 14891 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value(); 14892 CONVERT_ARG_CHECKED(JSReceiver, obj, 0); 14893 ASSERT(!obj->IsJSGlobalProxy() || !obj->map()->is_observed()); 14894 return isolate->heap()->ToBoolean(obj->map()->is_observed()); 14895 } 14896 14897 14898 RUNTIME_FUNCTION(Runtime_SetIsObserved) { 14899 HandleScope scope(isolate); 14900 ASSERT(args.length() == 1); 14901 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 14902 RUNTIME_ASSERT(!obj->IsJSGlobalProxy()); 14903 if (obj->IsJSProxy()) return isolate->heap()->undefined_value(); 14904 RUNTIME_ASSERT(!obj->map()->is_observed()); 14905 14906 ASSERT(obj->IsJSObject()); 14907 JSObject::SetObserved(Handle<JSObject>::cast(obj)); 14908 return isolate->heap()->undefined_value(); 14909 } 14910 14911 14912 RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) { 14913 HandleScope scope(isolate); 14914 ASSERT(args.length() == 1); 14915 CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0); 14916 isolate->EnqueueMicrotask(microtask); 14917 return isolate->heap()->undefined_value(); 14918 } 14919 14920 14921 RUNTIME_FUNCTION(Runtime_RunMicrotasks) { 14922 HandleScope scope(isolate); 14923 ASSERT(args.length() == 0); 14924 isolate->RunMicrotasks(); 14925 return isolate->heap()->undefined_value(); 14926 } 14927 14928 14929 RUNTIME_FUNCTION(Runtime_GetObservationState) { 14930 SealHandleScope shs(isolate); 14931 ASSERT(args.length() == 0); 14932 return isolate->heap()->observation_state(); 14933 } 14934 14935 14936 RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) { 14937 HandleScope scope(isolate); 14938 ASSERT(args.length() == 0); 14939 // TODO(adamk): Currently this runtime function is only called three times per 14940 // isolate. If it's called more often, the map should be moved into the 14941 // strong root list. 14942 Handle<Map> map = 14943 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); 14944 Handle<JSWeakMap> weakmap = 14945 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map)); 14946 return *WeakCollectionInitialize(isolate, weakmap); 14947 } 14948 14949 14950 static bool ContextsHaveSameOrigin(Handle<Context> context1, 14951 Handle<Context> context2) { 14952 return context1->security_token() == context2->security_token(); 14953 } 14954 14955 14956 RUNTIME_FUNCTION(Runtime_ObserverObjectAndRecordHaveSameOrigin) { 14957 HandleScope scope(isolate); 14958 ASSERT(args.length() == 3); 14959 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0); 14960 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1); 14961 CONVERT_ARG_HANDLE_CHECKED(JSObject, record, 2); 14962 14963 Handle<Context> observer_context(observer->context()->native_context(), 14964 isolate); 14965 Handle<Context> object_context(object->GetCreationContext()); 14966 Handle<Context> record_context(record->GetCreationContext()); 14967 14968 return isolate->heap()->ToBoolean( 14969 ContextsHaveSameOrigin(object_context, observer_context) && 14970 ContextsHaveSameOrigin(object_context, record_context)); 14971 } 14972 14973 14974 RUNTIME_FUNCTION(Runtime_ObjectWasCreatedInCurrentOrigin) { 14975 HandleScope scope(isolate); 14976 ASSERT(args.length() == 1); 14977 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 14978 14979 Handle<Context> creation_context(object->GetCreationContext(), isolate); 14980 return isolate->heap()->ToBoolean( 14981 ContextsHaveSameOrigin(creation_context, isolate->native_context())); 14982 } 14983 14984 14985 RUNTIME_FUNCTION(Runtime_GetObjectContextObjectObserve) { 14986 HandleScope scope(isolate); 14987 ASSERT(args.length() == 1); 14988 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 14989 14990 Handle<Context> context(object->GetCreationContext(), isolate); 14991 return context->native_object_observe(); 14992 } 14993 14994 14995 RUNTIME_FUNCTION(Runtime_GetObjectContextObjectGetNotifier) { 14996 HandleScope scope(isolate); 14997 ASSERT(args.length() == 1); 14998 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 14999 15000 Handle<Context> context(object->GetCreationContext(), isolate); 15001 return context->native_object_get_notifier(); 15002 } 15003 15004 15005 RUNTIME_FUNCTION(Runtime_GetObjectContextNotifierPerformChange) { 15006 HandleScope scope(isolate); 15007 ASSERT(args.length() == 1); 15008 CONVERT_ARG_HANDLE_CHECKED(JSObject, object_info, 0); 15009 15010 Handle<Context> context(object_info->GetCreationContext(), isolate); 15011 return context->native_object_notifier_perform_change(); 15012 } 15013 15014 15015 static Object* ArrayConstructorCommon(Isolate* isolate, 15016 Handle<JSFunction> constructor, 15017 Handle<AllocationSite> site, 15018 Arguments* caller_args) { 15019 Factory* factory = isolate->factory(); 15020 15021 bool holey = false; 15022 bool can_use_type_feedback = true; 15023 if (caller_args->length() == 1) { 15024 Handle<Object> argument_one = caller_args->at<Object>(0); 15025 if (argument_one->IsSmi()) { 15026 int value = Handle<Smi>::cast(argument_one)->value(); 15027 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) { 15028 // the array is a dictionary in this case. 15029 can_use_type_feedback = false; 15030 } else if (value != 0) { 15031 holey = true; 15032 } 15033 } else { 15034 // Non-smi length argument produces a dictionary 15035 can_use_type_feedback = false; 15036 } 15037 } 15038 15039 Handle<JSArray> array; 15040 if (!site.is_null() && can_use_type_feedback) { 15041 ElementsKind to_kind = site->GetElementsKind(); 15042 if (holey && !IsFastHoleyElementsKind(to_kind)) { 15043 to_kind = GetHoleyElementsKind(to_kind); 15044 // Update the allocation site info to reflect the advice alteration. 15045 site->SetElementsKind(to_kind); 15046 } 15047 15048 // We should allocate with an initial map that reflects the allocation site 15049 // advice. Therefore we use AllocateJSObjectFromMap instead of passing 15050 // the constructor. 15051 Handle<Map> initial_map(constructor->initial_map(), isolate); 15052 if (to_kind != initial_map->elements_kind()) { 15053 initial_map = Map::AsElementsKind(initial_map, to_kind); 15054 } 15055 15056 // If we don't care to track arrays of to_kind ElementsKind, then 15057 // don't emit a memento for them. 15058 Handle<AllocationSite> allocation_site; 15059 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) { 15060 allocation_site = site; 15061 } 15062 15063 array = Handle<JSArray>::cast(factory->NewJSObjectFromMap( 15064 initial_map, NOT_TENURED, true, allocation_site)); 15065 } else { 15066 array = Handle<JSArray>::cast(factory->NewJSObject(constructor)); 15067 15068 // We might need to transition to holey 15069 ElementsKind kind = constructor->initial_map()->elements_kind(); 15070 if (holey && !IsFastHoleyElementsKind(kind)) { 15071 kind = GetHoleyElementsKind(kind); 15072 JSObject::TransitionElementsKind(array, kind); 15073 } 15074 } 15075 15076 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS); 15077 15078 ElementsKind old_kind = array->GetElementsKind(); 15079 RETURN_FAILURE_ON_EXCEPTION( 15080 isolate, ArrayConstructInitializeElements(array, caller_args)); 15081 if (!site.is_null() && 15082 (old_kind != array->GetElementsKind() || 15083 !can_use_type_feedback)) { 15084 // The arguments passed in caused a transition. This kind of complexity 15085 // can't be dealt with in the inlined hydrogen array constructor case. 15086 // We must mark the allocationsite as un-inlinable. 15087 site->SetDoNotInlineCall(); 15088 } 15089 return *array; 15090 } 15091 15092 15093 RUNTIME_FUNCTION(RuntimeHidden_ArrayConstructor) { 15094 HandleScope scope(isolate); 15095 // If we get 2 arguments then they are the stub parameters (constructor, type 15096 // info). If we get 4, then the first one is a pointer to the arguments 15097 // passed by the caller, and the last one is the length of the arguments 15098 // passed to the caller (redundant, but useful to check on the deoptimizer 15099 // with an assert). 15100 Arguments empty_args(0, NULL); 15101 bool no_caller_args = args.length() == 2; 15102 ASSERT(no_caller_args || args.length() == 4); 15103 int parameters_start = no_caller_args ? 0 : 1; 15104 Arguments* caller_args = no_caller_args 15105 ? &empty_args 15106 : reinterpret_cast<Arguments*>(args[0]); 15107 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 15108 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1); 15109 #ifdef DEBUG 15110 if (!no_caller_args) { 15111 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2); 15112 ASSERT(arg_count == caller_args->length()); 15113 } 15114 #endif 15115 15116 Handle<AllocationSite> site; 15117 if (!type_info.is_null() && 15118 *type_info != isolate->heap()->undefined_value()) { 15119 site = Handle<AllocationSite>::cast(type_info); 15120 ASSERT(!site->SitePointsToLiteral()); 15121 } 15122 15123 return ArrayConstructorCommon(isolate, 15124 constructor, 15125 site, 15126 caller_args); 15127 } 15128 15129 15130 RUNTIME_FUNCTION(RuntimeHidden_InternalArrayConstructor) { 15131 HandleScope scope(isolate); 15132 Arguments empty_args(0, NULL); 15133 bool no_caller_args = args.length() == 1; 15134 ASSERT(no_caller_args || args.length() == 3); 15135 int parameters_start = no_caller_args ? 0 : 1; 15136 Arguments* caller_args = no_caller_args 15137 ? &empty_args 15138 : reinterpret_cast<Arguments*>(args[0]); 15139 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 15140 #ifdef DEBUG 15141 if (!no_caller_args) { 15142 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1); 15143 ASSERT(arg_count == caller_args->length()); 15144 } 15145 #endif 15146 return ArrayConstructorCommon(isolate, 15147 constructor, 15148 Handle<AllocationSite>::null(), 15149 caller_args); 15150 } 15151 15152 15153 RUNTIME_FUNCTION(Runtime_MaxSmi) { 15154 ASSERT(args.length() == 0); 15155 return Smi::FromInt(Smi::kMaxValue); 15156 } 15157 15158 15159 // ---------------------------------------------------------------------------- 15160 // Implementation of Runtime 15161 15162 #define F(name, number_of_args, result_size) \ 15163 { Runtime::k##name, Runtime::RUNTIME, #name, \ 15164 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, 15165 15166 15167 #define FH(name, number_of_args, result_size) \ 15168 { Runtime::kHidden##name, Runtime::RUNTIME_HIDDEN, NULL, \ 15169 FUNCTION_ADDR(RuntimeHidden_##name), number_of_args, result_size }, 15170 15171 15172 #define I(name, number_of_args, result_size) \ 15173 { Runtime::kInline##name, Runtime::INLINE, \ 15174 "_" #name, NULL, number_of_args, result_size }, 15175 15176 15177 #define IO(name, number_of_args, result_size) \ 15178 { Runtime::kInlineOptimized##name, Runtime::INLINE_OPTIMIZED, \ 15179 "_" #name, FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, 15180 15181 15182 static const Runtime::Function kIntrinsicFunctions[] = { 15183 RUNTIME_FUNCTION_LIST(F) 15184 INLINE_OPTIMIZED_FUNCTION_LIST(F) 15185 RUNTIME_HIDDEN_FUNCTION_LIST(FH) 15186 INLINE_FUNCTION_LIST(I) 15187 INLINE_OPTIMIZED_FUNCTION_LIST(IO) 15188 }; 15189 15190 #undef IO 15191 #undef I 15192 #undef FH 15193 #undef F 15194 15195 15196 void Runtime::InitializeIntrinsicFunctionNames(Isolate* isolate, 15197 Handle<NameDictionary> dict) { 15198 ASSERT(dict->NumberOfElements() == 0); 15199 HandleScope scope(isolate); 15200 for (int i = 0; i < kNumFunctions; ++i) { 15201 const char* name = kIntrinsicFunctions[i].name; 15202 if (name == NULL) continue; 15203 Handle<NameDictionary> new_dict = NameDictionary::Add( 15204 dict, 15205 isolate->factory()->InternalizeUtf8String(name), 15206 Handle<Smi>(Smi::FromInt(i), isolate), 15207 PropertyDetails(NONE, NORMAL, Representation::None())); 15208 // The dictionary does not need to grow. 15209 CHECK(new_dict.is_identical_to(dict)); 15210 } 15211 } 15212 15213 15214 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) { 15215 Heap* heap = name->GetHeap(); 15216 int entry = heap->intrinsic_function_names()->FindEntry(name); 15217 if (entry != kNotFound) { 15218 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); 15219 int function_index = Smi::cast(smi_index)->value(); 15220 return &(kIntrinsicFunctions[function_index]); 15221 } 15222 return NULL; 15223 } 15224 15225 15226 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { 15227 return &(kIntrinsicFunctions[static_cast<int>(id)]); 15228 } 15229 15230 } } // namespace v8::internal 15231