1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include <stdlib.h> 29 #include <limits> 30 31 #include "v8.h" 32 33 #include "accessors.h" 34 #include "allocation-site-scopes.h" 35 #include "api.h" 36 #include "arguments.h" 37 #include "bootstrapper.h" 38 #include "codegen.h" 39 #include "compilation-cache.h" 40 #include "compiler.h" 41 #include "cpu.h" 42 #include "cpu-profiler.h" 43 #include "dateparser-inl.h" 44 #include "debug.h" 45 #include "deoptimizer.h" 46 #include "date.h" 47 #include "execution.h" 48 #include "full-codegen.h" 49 #include "global-handles.h" 50 #include "isolate-inl.h" 51 #include "jsregexp.h" 52 #include "jsregexp-inl.h" 53 #include "json-parser.h" 54 #include "json-stringifier.h" 55 #include "liveedit.h" 56 #include "misc-intrinsics.h" 57 #include "parser.h" 58 #include "platform.h" 59 #include "runtime-profiler.h" 60 #include "runtime.h" 61 #include "scopeinfo.h" 62 #include "smart-pointers.h" 63 #include "string-search.h" 64 #include "stub-cache.h" 65 #include "uri.h" 66 #include "v8conversions.h" 67 #include "v8threads.h" 68 #include "vm-state-inl.h" 69 70 #ifdef V8_I18N_SUPPORT 71 #include "i18n.h" 72 #include "unicode/brkiter.h" 73 #include "unicode/calendar.h" 74 #include "unicode/coll.h" 75 #include "unicode/curramt.h" 76 #include "unicode/datefmt.h" 77 #include "unicode/dcfmtsym.h" 78 #include "unicode/decimfmt.h" 79 #include "unicode/dtfmtsym.h" 80 #include "unicode/dtptngen.h" 81 #include "unicode/locid.h" 82 #include "unicode/numfmt.h" 83 #include "unicode/numsys.h" 84 #include "unicode/rbbi.h" 85 #include "unicode/smpdtfmt.h" 86 #include "unicode/timezone.h" 87 #include "unicode/uchar.h" 88 #include "unicode/ucol.h" 89 #include "unicode/ucurr.h" 90 #include "unicode/uloc.h" 91 #include "unicode/unum.h" 92 #include "unicode/uversion.h" 93 #endif 94 95 #ifndef _STLP_VENDOR_CSTD 96 // STLPort doesn't import fpclassify and isless into the std namespace. 97 using std::fpclassify; 98 using std::isless; 99 #endif 100 101 namespace v8 { 102 namespace internal { 103 104 105 #define RUNTIME_ASSERT(value) \ 106 if (!(value)) return isolate->ThrowIllegalOperation(); 107 108 // Cast the given object to a value of the specified type and store 109 // it in a variable with the given name. If the object is not of the 110 // expected type call IllegalOperation and return. 111 #define CONVERT_ARG_CHECKED(Type, name, index) \ 112 RUNTIME_ASSERT(args[index]->Is##Type()); \ 113 Type* name = Type::cast(args[index]); 114 115 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ 116 RUNTIME_ASSERT(args[index]->Is##Type()); \ 117 Handle<Type> name = args.at<Type>(index); 118 119 // Cast the given object to a boolean and store it in a variable with 120 // the given name. If the object is not a boolean call IllegalOperation 121 // and return. 122 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ 123 RUNTIME_ASSERT(args[index]->IsBoolean()); \ 124 bool name = args[index]->IsTrue(); 125 126 // Cast the given argument to a Smi and store its value in an int variable 127 // with the given name. If the argument is not a Smi call IllegalOperation 128 // and return. 129 #define CONVERT_SMI_ARG_CHECKED(name, index) \ 130 RUNTIME_ASSERT(args[index]->IsSmi()); \ 131 int name = args.smi_at(index); 132 133 // Cast the given argument to a double and store it in a variable with 134 // the given name. If the argument is not a number (as opposed to 135 // the number not-a-number) call IllegalOperation and return. 136 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ 137 RUNTIME_ASSERT(args[index]->IsNumber()); \ 138 double name = args.number_at(index); 139 140 // Call the specified converter on the object *comand store the result in 141 // a variable of the specified type with the given name. If the 142 // object is not a Number call IllegalOperation and return. 143 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 144 RUNTIME_ASSERT(obj->IsNumber()); \ 145 type name = NumberTo##Type(obj); 146 147 148 // Cast the given argument to PropertyDetails and store its value in a 149 // variable with the given name. If the argument is not a Smi call 150 // IllegalOperation and return. 151 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ 152 RUNTIME_ASSERT(args[index]->IsSmi()); \ 153 PropertyDetails name = PropertyDetails(Smi::cast(args[index])); 154 155 156 // Assert that the given argument has a valid value for a StrictModeFlag 157 // and store it in a StrictModeFlag variable with the given name. 158 #define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \ 159 RUNTIME_ASSERT(args[index]->IsSmi()); \ 160 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \ 161 args.smi_at(index) == kNonStrictMode); \ 162 StrictModeFlag name = \ 163 static_cast<StrictModeFlag>(args.smi_at(index)); 164 165 166 // Assert that the given argument has a valid value for a LanguageMode 167 // and store it in a LanguageMode variable with the given name. 168 #define CONVERT_LANGUAGE_MODE_ARG(name, index) \ 169 ASSERT(args[index]->IsSmi()); \ 170 ASSERT(args.smi_at(index) == CLASSIC_MODE || \ 171 args.smi_at(index) == STRICT_MODE || \ 172 args.smi_at(index) == EXTENDED_MODE); \ 173 LanguageMode name = \ 174 static_cast<LanguageMode>(args.smi_at(index)); 175 176 177 static Handle<Map> ComputeObjectLiteralMap( 178 Handle<Context> context, 179 Handle<FixedArray> constant_properties, 180 bool* is_result_from_cache) { 181 Isolate* isolate = context->GetIsolate(); 182 int properties_length = constant_properties->length(); 183 int number_of_properties = properties_length / 2; 184 // Check that there are only internal strings and array indices among keys. 185 int number_of_string_keys = 0; 186 for (int p = 0; p != properties_length; p += 2) { 187 Object* key = constant_properties->get(p); 188 uint32_t element_index = 0; 189 if (key->IsInternalizedString()) { 190 number_of_string_keys++; 191 } else if (key->ToArrayIndex(&element_index)) { 192 // An index key does not require space in the property backing store. 193 number_of_properties--; 194 } else { 195 // Bail out as a non-internalized-string non-index key makes caching 196 // impossible. 197 // ASSERT to make sure that the if condition after the loop is false. 198 ASSERT(number_of_string_keys != number_of_properties); 199 break; 200 } 201 } 202 // If we only have internalized strings and array indices among keys then we 203 // can use the map cache in the native context. 204 const int kMaxKeys = 10; 205 if ((number_of_string_keys == number_of_properties) && 206 (number_of_string_keys < kMaxKeys)) { 207 // Create the fixed array with the key. 208 Handle<FixedArray> keys = 209 isolate->factory()->NewFixedArray(number_of_string_keys); 210 if (number_of_string_keys > 0) { 211 int index = 0; 212 for (int p = 0; p < properties_length; p += 2) { 213 Object* key = constant_properties->get(p); 214 if (key->IsInternalizedString()) { 215 keys->set(index++, key); 216 } 217 } 218 ASSERT(index == number_of_string_keys); 219 } 220 *is_result_from_cache = true; 221 return isolate->factory()->ObjectLiteralMapFromCache(context, keys); 222 } 223 *is_result_from_cache = false; 224 return isolate->factory()->CopyMap( 225 Handle<Map>(context->object_function()->initial_map()), 226 number_of_properties); 227 } 228 229 230 static Handle<Object> CreateLiteralBoilerplate( 231 Isolate* isolate, 232 Handle<FixedArray> literals, 233 Handle<FixedArray> constant_properties); 234 235 236 static Handle<Object> CreateObjectLiteralBoilerplate( 237 Isolate* isolate, 238 Handle<FixedArray> literals, 239 Handle<FixedArray> constant_properties, 240 bool should_have_fast_elements, 241 bool has_function_literal) { 242 // Get the native context from the literals array. This is the 243 // context in which the function was created and we use the object 244 // function from this context to create the object literal. We do 245 // not use the object function from the current native context 246 // because this might be the object function from another context 247 // which we should not have access to. 248 Handle<Context> context = 249 Handle<Context>(JSFunction::NativeContextFromLiterals(*literals)); 250 251 // In case we have function literals, we want the object to be in 252 // slow properties mode for now. We don't go in the map cache because 253 // maps with constant functions can't be shared if the functions are 254 // not the same (which is the common case). 255 bool is_result_from_cache = false; 256 Handle<Map> map = has_function_literal 257 ? Handle<Map>(context->object_function()->initial_map()) 258 : ComputeObjectLiteralMap(context, 259 constant_properties, 260 &is_result_from_cache); 261 262 Handle<JSObject> boilerplate = 263 isolate->factory()->NewJSObjectFromMap( 264 map, isolate->heap()->GetPretenureMode()); 265 266 // Normalize the elements of the boilerplate to save space if needed. 267 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); 268 269 // Add the constant properties to the boilerplate. 270 int length = constant_properties->length(); 271 bool should_transform = 272 !is_result_from_cache && boilerplate->HasFastProperties(); 273 if (should_transform || has_function_literal) { 274 // Normalize the properties of object to avoid n^2 behavior 275 // when extending the object multiple properties. Indicate the number of 276 // properties to be added. 277 JSObject::NormalizeProperties( 278 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2); 279 } 280 281 // TODO(verwaest): Support tracking representations in the boilerplate. 282 for (int index = 0; index < length; index +=2) { 283 Handle<Object> key(constant_properties->get(index+0), isolate); 284 Handle<Object> value(constant_properties->get(index+1), isolate); 285 if (value->IsFixedArray()) { 286 // The value contains the constant_properties of a 287 // simple object or array literal. 288 Handle<FixedArray> array = Handle<FixedArray>::cast(value); 289 value = CreateLiteralBoilerplate(isolate, literals, array); 290 if (value.is_null()) return value; 291 } 292 Handle<Object> result; 293 uint32_t element_index = 0; 294 StoreMode mode = value->IsJSObject() ? FORCE_FIELD : ALLOW_AS_CONSTANT; 295 if (key->IsInternalizedString()) { 296 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) { 297 // Array index as string (uint32). 298 result = JSObject::SetOwnElement( 299 boilerplate, element_index, value, kNonStrictMode); 300 } else { 301 Handle<String> name(String::cast(*key)); 302 ASSERT(!name->AsArrayIndex(&element_index)); 303 result = JSObject::SetLocalPropertyIgnoreAttributes( 304 boilerplate, name, value, NONE, 305 Object::OPTIMAL_REPRESENTATION, mode); 306 } 307 } else if (key->ToArrayIndex(&element_index)) { 308 // Array index (uint32). 309 result = JSObject::SetOwnElement( 310 boilerplate, element_index, value, kNonStrictMode); 311 } else { 312 // Non-uint32 number. 313 ASSERT(key->IsNumber()); 314 double num = key->Number(); 315 char arr[100]; 316 Vector<char> buffer(arr, ARRAY_SIZE(arr)); 317 const char* str = DoubleToCString(num, buffer); 318 Handle<String> name = 319 isolate->factory()->NewStringFromAscii(CStrVector(str)); 320 result = JSObject::SetLocalPropertyIgnoreAttributes( 321 boilerplate, name, value, NONE, 322 Object::OPTIMAL_REPRESENTATION, mode); 323 } 324 // If setting the property on the boilerplate throws an 325 // exception, the exception is converted to an empty handle in 326 // the handle based operations. In that case, we need to 327 // convert back to an exception. 328 if (result.is_null()) return result; 329 } 330 331 // Transform to fast properties if necessary. For object literals with 332 // containing function literals we defer this operation until after all 333 // computed properties have been assigned so that we can generate 334 // constant function properties. 335 if (should_transform && !has_function_literal) { 336 JSObject::TransformToFastProperties( 337 boilerplate, boilerplate->map()->unused_property_fields()); 338 } 339 340 return boilerplate; 341 } 342 343 344 MaybeObject* TransitionElements(Handle<Object> object, 345 ElementsKind to_kind, 346 Isolate* isolate) { 347 HandleScope scope(isolate); 348 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation(); 349 ElementsKind from_kind = 350 Handle<JSObject>::cast(object)->map()->elements_kind(); 351 if (Map::IsValidElementsTransition(from_kind, to_kind)) { 352 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind); 353 return *object; 354 } 355 return isolate->ThrowIllegalOperation(); 356 } 357 358 359 static const int kSmiLiteralMinimumLength = 1024; 360 361 362 Handle<Object> Runtime::CreateArrayLiteralBoilerplate( 363 Isolate* isolate, 364 Handle<FixedArray> literals, 365 Handle<FixedArray> elements) { 366 // Create the JSArray. 367 Handle<JSFunction> constructor( 368 JSFunction::NativeContextFromLiterals(*literals)->array_function()); 369 370 Handle<JSArray> object = Handle<JSArray>::cast( 371 isolate->factory()->NewJSObject( 372 constructor, isolate->heap()->GetPretenureMode())); 373 374 ElementsKind constant_elements_kind = 375 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value()); 376 Handle<FixedArrayBase> constant_elements_values( 377 FixedArrayBase::cast(elements->get(1))); 378 379 ASSERT(IsFastElementsKind(constant_elements_kind)); 380 Context* native_context = isolate->context()->native_context(); 381 Object* maybe_maps_array = native_context->js_array_maps(); 382 ASSERT(!maybe_maps_array->IsUndefined()); 383 Object* maybe_map = FixedArray::cast(maybe_maps_array)->get( 384 constant_elements_kind); 385 ASSERT(maybe_map->IsMap()); 386 object->set_map(Map::cast(maybe_map)); 387 388 Handle<FixedArrayBase> copied_elements_values; 389 if (IsFastDoubleElementsKind(constant_elements_kind)) { 390 ASSERT(FLAG_smi_only_arrays); 391 copied_elements_values = isolate->factory()->CopyFixedDoubleArray( 392 Handle<FixedDoubleArray>::cast(constant_elements_values)); 393 } else { 394 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind)); 395 const bool is_cow = 396 (constant_elements_values->map() == 397 isolate->heap()->fixed_cow_array_map()); 398 if (is_cow) { 399 copied_elements_values = constant_elements_values; 400 #if DEBUG 401 Handle<FixedArray> fixed_array_values = 402 Handle<FixedArray>::cast(copied_elements_values); 403 for (int i = 0; i < fixed_array_values->length(); i++) { 404 ASSERT(!fixed_array_values->get(i)->IsFixedArray()); 405 } 406 #endif 407 } else { 408 Handle<FixedArray> fixed_array_values = 409 Handle<FixedArray>::cast(constant_elements_values); 410 Handle<FixedArray> fixed_array_values_copy = 411 isolate->factory()->CopyFixedArray(fixed_array_values); 412 copied_elements_values = fixed_array_values_copy; 413 for (int i = 0; i < fixed_array_values->length(); i++) { 414 Object* current = fixed_array_values->get(i); 415 if (current->IsFixedArray()) { 416 // The value contains the constant_properties of a 417 // simple object or array literal. 418 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i))); 419 Handle<Object> result = 420 CreateLiteralBoilerplate(isolate, literals, fa); 421 if (result.is_null()) return result; 422 fixed_array_values_copy->set(i, *result); 423 } 424 } 425 } 426 } 427 object->set_elements(*copied_elements_values); 428 object->set_length(Smi::FromInt(copied_elements_values->length())); 429 430 // Ensure that the boilerplate object has FAST_*_ELEMENTS, unless the flag is 431 // on or the object is larger than the threshold. 432 if (!FLAG_smi_only_arrays && 433 constant_elements_values->length() < kSmiLiteralMinimumLength) { 434 ElementsKind elements_kind = object->GetElementsKind(); 435 if (!IsFastObjectElementsKind(elements_kind)) { 436 if (IsFastHoleyElementsKind(elements_kind)) { 437 CHECK(!TransitionElements(object, FAST_HOLEY_ELEMENTS, 438 isolate)->IsFailure()); 439 } else { 440 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure()); 441 } 442 } 443 } 444 445 object->ValidateElements(); 446 return object; 447 } 448 449 450 static Handle<Object> CreateLiteralBoilerplate( 451 Isolate* isolate, 452 Handle<FixedArray> literals, 453 Handle<FixedArray> array) { 454 Handle<FixedArray> elements = CompileTimeValue::GetElements(array); 455 const bool kHasNoFunctionLiteral = false; 456 switch (CompileTimeValue::GetLiteralType(array)) { 457 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: 458 return CreateObjectLiteralBoilerplate(isolate, 459 literals, 460 elements, 461 true, 462 kHasNoFunctionLiteral); 463 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: 464 return CreateObjectLiteralBoilerplate(isolate, 465 literals, 466 elements, 467 false, 468 kHasNoFunctionLiteral); 469 case CompileTimeValue::ARRAY_LITERAL: 470 return Runtime::CreateArrayLiteralBoilerplate( 471 isolate, literals, elements); 472 default: 473 UNREACHABLE(); 474 return Handle<Object>::null(); 475 } 476 } 477 478 479 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) { 480 HandleScope scope(isolate); 481 ASSERT(args.length() == 4); 482 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 483 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 484 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2); 485 CONVERT_SMI_ARG_CHECKED(flags, 3); 486 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; 487 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0; 488 489 // Check if boilerplate exists. If not, create it first. 490 Handle<Object> literal_site(literals->get(literals_index), isolate); 491 Handle<AllocationSite> site; 492 Handle<JSObject> boilerplate; 493 if (*literal_site == isolate->heap()->undefined_value()) { 494 Handle<Object> raw_boilerplate = CreateObjectLiteralBoilerplate( 495 isolate, 496 literals, 497 constant_properties, 498 should_have_fast_elements, 499 has_function_literal); 500 RETURN_IF_EMPTY_HANDLE(isolate, raw_boilerplate); 501 boilerplate = Handle<JSObject>::cast(raw_boilerplate); 502 503 AllocationSiteCreationContext creation_context(isolate); 504 site = creation_context.EnterNewScope(); 505 RETURN_IF_EMPTY_HANDLE(isolate, 506 JSObject::DeepWalk(boilerplate, &creation_context)); 507 creation_context.ExitScope(site, boilerplate); 508 509 // Update the functions literal and return the boilerplate. 510 literals->set(literals_index, *site); 511 } else { 512 site = Handle<AllocationSite>::cast(literal_site); 513 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()), 514 isolate); 515 } 516 517 AllocationSiteUsageContext usage_context(isolate, site, true); 518 usage_context.EnterNewScope(); 519 Handle<Object> copy = JSObject::DeepCopy(boilerplate, &usage_context); 520 usage_context.ExitScope(site, boilerplate); 521 RETURN_IF_EMPTY_HANDLE(isolate, copy); 522 return *copy; 523 } 524 525 526 static Handle<AllocationSite> GetLiteralAllocationSite( 527 Isolate* isolate, 528 Handle<FixedArray> literals, 529 int literals_index, 530 Handle<FixedArray> elements) { 531 // Check if boilerplate exists. If not, create it first. 532 Handle<Object> literal_site(literals->get(literals_index), isolate); 533 Handle<AllocationSite> site; 534 if (*literal_site == isolate->heap()->undefined_value()) { 535 ASSERT(*elements != isolate->heap()->empty_fixed_array()); 536 Handle<Object> boilerplate = 537 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements); 538 if (boilerplate.is_null()) return Handle<AllocationSite>::null(); 539 540 AllocationSiteCreationContext creation_context(isolate); 541 site = creation_context.EnterNewScope(); 542 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate), 543 &creation_context).is_null()) { 544 return Handle<AllocationSite>::null(); 545 } 546 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate)); 547 548 literals->set(literals_index, *site); 549 } else { 550 site = Handle<AllocationSite>::cast(literal_site); 551 } 552 553 return site; 554 } 555 556 557 static MaybeObject* CreateArrayLiteralImpl(Isolate* isolate, 558 Handle<FixedArray> literals, 559 int literals_index, 560 Handle<FixedArray> elements, 561 int flags) { 562 Handle<AllocationSite> site = GetLiteralAllocationSite(isolate, literals, 563 literals_index, elements); 564 RETURN_IF_EMPTY_HANDLE(isolate, site); 565 566 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0; 567 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info())); 568 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos); 569 usage_context.EnterNewScope(); 570 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0 571 ? JSObject::kNoHints 572 : JSObject::kObjectIsShallowArray; 573 Handle<JSObject> copy = JSObject::DeepCopy(boilerplate, &usage_context, 574 hints); 575 usage_context.ExitScope(site, boilerplate); 576 RETURN_IF_EMPTY_HANDLE(isolate, copy); 577 return *copy; 578 } 579 580 581 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) { 582 HandleScope scope(isolate); 583 ASSERT(args.length() == 4); 584 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 585 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 586 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 587 CONVERT_SMI_ARG_CHECKED(flags, 3); 588 589 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements, 590 flags); 591 } 592 593 594 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralStubBailout) { 595 HandleScope scope(isolate); 596 ASSERT(args.length() == 3); 597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 598 CONVERT_SMI_ARG_CHECKED(literals_index, 1); 599 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2); 600 601 return CreateArrayLiteralImpl(isolate, literals, literals_index, elements, 602 ArrayLiteral::kShallowElements); 603 } 604 605 606 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateSymbol) { 607 HandleScope scope(isolate); 608 ASSERT(args.length() == 1); 609 Handle<Object> name(args[0], isolate); 610 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); 611 Symbol* symbol; 612 MaybeObject* maybe = isolate->heap()->AllocateSymbol(); 613 if (!maybe->To(&symbol)) return maybe; 614 if (name->IsString()) symbol->set_name(*name); 615 return symbol; 616 } 617 618 619 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreatePrivateSymbol) { 620 HandleScope scope(isolate); 621 ASSERT(args.length() == 1); 622 Handle<Object> name(args[0], isolate); 623 RUNTIME_ASSERT(name->IsString() || name->IsUndefined()); 624 Symbol* symbol; 625 MaybeObject* maybe = isolate->heap()->AllocatePrivateSymbol(); 626 if (!maybe->To(&symbol)) return maybe; 627 if (name->IsString()) symbol->set_name(*name); 628 return symbol; 629 } 630 631 632 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolName) { 633 SealHandleScope shs(isolate); 634 ASSERT(args.length() == 1); 635 CONVERT_ARG_CHECKED(Symbol, symbol, 0); 636 return symbol->name(); 637 } 638 639 640 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) { 641 SealHandleScope shs(isolate); 642 ASSERT(args.length() == 1); 643 CONVERT_ARG_CHECKED(Symbol, symbol, 0); 644 return isolate->heap()->ToBoolean(symbol->is_private()); 645 } 646 647 648 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) { 649 SealHandleScope shs(isolate); 650 ASSERT(args.length() == 2); 651 CONVERT_ARG_CHECKED(JSReceiver, handler, 0); 652 Object* prototype = args[1]; 653 Object* used_prototype = 654 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); 655 return isolate->heap()->AllocateJSProxy(handler, used_prototype); 656 } 657 658 659 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) { 660 SealHandleScope shs(isolate); 661 ASSERT(args.length() == 4); 662 CONVERT_ARG_CHECKED(JSReceiver, handler, 0); 663 Object* call_trap = args[1]; 664 RUNTIME_ASSERT(call_trap->IsJSFunction() || call_trap->IsJSFunctionProxy()); 665 CONVERT_ARG_CHECKED(JSFunction, construct_trap, 2); 666 Object* prototype = args[3]; 667 Object* used_prototype = 668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value(); 669 return isolate->heap()->AllocateJSFunctionProxy( 670 handler, call_trap, construct_trap, used_prototype); 671 } 672 673 674 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) { 675 SealHandleScope shs(isolate); 676 ASSERT(args.length() == 1); 677 Object* obj = args[0]; 678 return isolate->heap()->ToBoolean(obj->IsJSProxy()); 679 } 680 681 682 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) { 683 SealHandleScope shs(isolate); 684 ASSERT(args.length() == 1); 685 Object* obj = args[0]; 686 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy()); 687 } 688 689 690 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) { 691 SealHandleScope shs(isolate); 692 ASSERT(args.length() == 1); 693 CONVERT_ARG_CHECKED(JSProxy, proxy, 0); 694 return proxy->handler(); 695 } 696 697 698 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) { 699 SealHandleScope shs(isolate); 700 ASSERT(args.length() == 1); 701 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 702 return proxy->call_trap(); 703 } 704 705 706 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) { 707 SealHandleScope shs(isolate); 708 ASSERT(args.length() == 1); 709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0); 710 return proxy->construct_trap(); 711 } 712 713 714 RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) { 715 HandleScope scope(isolate); 716 ASSERT(args.length() == 1); 717 CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0); 718 JSProxy::Fix(proxy); 719 return isolate->heap()->undefined_value(); 720 } 721 722 723 void Runtime::FreeArrayBuffer(Isolate* isolate, 724 JSArrayBuffer* phantom_array_buffer) { 725 if (phantom_array_buffer->should_be_freed()) { 726 ASSERT(phantom_array_buffer->is_external()); 727 free(phantom_array_buffer->backing_store()); 728 } 729 if (phantom_array_buffer->is_external()) return; 730 731 size_t allocated_length = NumberToSize( 732 isolate, phantom_array_buffer->byte_length()); 733 734 isolate->heap()->AdjustAmountOfExternalAllocatedMemory( 735 -static_cast<int64_t>(allocated_length)); 736 CHECK(V8::ArrayBufferAllocator() != NULL); 737 V8::ArrayBufferAllocator()->Free( 738 phantom_array_buffer->backing_store(), 739 allocated_length); 740 } 741 742 743 void Runtime::SetupArrayBuffer(Isolate* isolate, 744 Handle<JSArrayBuffer> array_buffer, 745 bool is_external, 746 void* data, 747 size_t allocated_length) { 748 ASSERT(array_buffer->GetInternalFieldCount() == 749 v8::ArrayBuffer::kInternalFieldCount); 750 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) { 751 array_buffer->SetInternalField(i, Smi::FromInt(0)); 752 } 753 array_buffer->set_backing_store(data); 754 array_buffer->set_flag(Smi::FromInt(0)); 755 array_buffer->set_is_external(is_external); 756 757 Handle<Object> byte_length = 758 isolate->factory()->NewNumberFromSize(allocated_length); 759 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); 760 array_buffer->set_byte_length(*byte_length); 761 762 array_buffer->set_weak_next(isolate->heap()->array_buffers_list()); 763 isolate->heap()->set_array_buffers_list(*array_buffer); 764 array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); 765 } 766 767 768 bool Runtime::SetupArrayBufferAllocatingData( 769 Isolate* isolate, 770 Handle<JSArrayBuffer> array_buffer, 771 size_t allocated_length, 772 bool initialize) { 773 void* data; 774 CHECK(V8::ArrayBufferAllocator() != NULL); 775 if (allocated_length != 0) { 776 if (initialize) { 777 data = V8::ArrayBufferAllocator()->Allocate(allocated_length); 778 } else { 779 data = 780 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length); 781 } 782 if (data == NULL) return false; 783 } else { 784 data = NULL; 785 } 786 787 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length); 788 789 isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); 790 791 return true; 792 } 793 794 795 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { 796 HandleScope scope(isolate); 797 ASSERT(args.length() == 2); 798 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); 799 CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); 800 size_t allocated_length; 801 if (byteLength->IsSmi()) { 802 allocated_length = Smi::cast(*byteLength)->value(); 803 } else { 804 ASSERT(byteLength->IsHeapNumber()); 805 double value = HeapNumber::cast(*byteLength)->value(); 806 807 ASSERT(value >= 0); 808 809 if (value > std::numeric_limits<size_t>::max()) { 810 return isolate->Throw( 811 *isolate->factory()->NewRangeError("invalid_array_buffer_length", 812 HandleVector<Object>(NULL, 0))); 813 } 814 815 allocated_length = static_cast<size_t>(value); 816 } 817 818 if (!Runtime::SetupArrayBufferAllocatingData(isolate, 819 holder, allocated_length)) { 820 return isolate->Throw(*isolate->factory()-> 821 NewRangeError("invalid_array_buffer_length", 822 HandleVector<Object>(NULL, 0))); 823 } 824 825 return *holder; 826 } 827 828 829 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { 830 SealHandleScope shs(isolate); 831 ASSERT(args.length() == 1); 832 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); 833 return holder->byte_length(); 834 } 835 836 837 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { 838 HandleScope scope(isolate); 839 ASSERT(args.length() == 3); 840 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); 841 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); 842 CONVERT_DOUBLE_ARG_CHECKED(first, 2); 843 size_t start = static_cast<size_t>(first); 844 size_t target_length = NumberToSize(isolate, target->byte_length()); 845 846 if (target_length == 0) return isolate->heap()->undefined_value(); 847 848 ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start); 849 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store()); 850 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store()); 851 CopyBytes(target_data, source_data + start, target_length); 852 return isolate->heap()->undefined_value(); 853 } 854 855 856 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferIsView) { 857 HandleScope scope(isolate); 858 ASSERT(args.length() == 1); 859 CONVERT_ARG_CHECKED(Object, object, 0); 860 return object->IsJSArrayBufferView() 861 ? isolate->heap()->true_value() 862 : isolate->heap()->false_value(); 863 } 864 865 866 void Runtime::ArrayIdToTypeAndSize( 867 int arrayId, ExternalArrayType* array_type, size_t* element_size) { 868 switch (arrayId) { 869 case ARRAY_ID_UINT8: 870 *array_type = kExternalUnsignedByteArray; 871 *element_size = 1; 872 break; 873 case ARRAY_ID_INT8: 874 *array_type = kExternalByteArray; 875 *element_size = 1; 876 break; 877 case ARRAY_ID_UINT16: 878 *array_type = kExternalUnsignedShortArray; 879 *element_size = 2; 880 break; 881 case ARRAY_ID_INT16: 882 *array_type = kExternalShortArray; 883 *element_size = 2; 884 break; 885 case ARRAY_ID_UINT32: 886 *array_type = kExternalUnsignedIntArray; 887 *element_size = 4; 888 break; 889 case ARRAY_ID_INT32: 890 *array_type = kExternalIntArray; 891 *element_size = 4; 892 break; 893 case ARRAY_ID_FLOAT32: 894 *array_type = kExternalFloatArray; 895 *element_size = 4; 896 break; 897 case ARRAY_ID_FLOAT64: 898 *array_type = kExternalDoubleArray; 899 *element_size = 8; 900 break; 901 case ARRAY_ID_UINT8C: 902 *array_type = kExternalPixelArray; 903 *element_size = 1; 904 break; 905 default: 906 UNREACHABLE(); 907 } 908 } 909 910 911 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) { 912 HandleScope scope(isolate); 913 ASSERT(args.length() == 5); 914 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 915 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 916 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2); 917 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3); 918 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4); 919 920 ASSERT(holder->GetInternalFieldCount() == 921 v8::ArrayBufferView::kInternalFieldCount); 922 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 923 holder->SetInternalField(i, Smi::FromInt(0)); 924 } 925 926 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. 927 size_t element_size = 1; // Bogus initialization. 928 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); 929 930 holder->set_buffer(*buffer); 931 holder->set_byte_offset(*byte_offset_object); 932 holder->set_byte_length(*byte_length_object); 933 934 size_t byte_offset = NumberToSize(isolate, *byte_offset_object); 935 size_t byte_length = NumberToSize(isolate, *byte_length_object); 936 ASSERT(byte_length % element_size == 0); 937 size_t length = byte_length / element_size; 938 939 if (length > static_cast<unsigned>(Smi::kMaxValue)) { 940 return isolate->Throw(*isolate->factory()-> 941 NewRangeError("invalid_typed_array_length", 942 HandleVector<Object>(NULL, 0))); 943 } 944 945 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length); 946 holder->set_length(*length_obj); 947 holder->set_weak_next(buffer->weak_first_view()); 948 buffer->set_weak_first_view(*holder); 949 950 Handle<ExternalArray> elements = 951 isolate->factory()->NewExternalArray( 952 static_cast<int>(length), array_type, 953 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset); 954 holder->set_elements(*elements); 955 return isolate->heap()->undefined_value(); 956 } 957 958 959 // Initializes a typed array from an array-like object. 960 // If an array-like object happens to be a typed array of the same type, 961 // initializes backing store using memove. 962 // 963 // Returns true if backing store was initialized or false otherwise. 964 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitializeFromArrayLike) { 965 HandleScope scope(isolate); 966 ASSERT(args.length() == 4); 967 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0); 968 CONVERT_SMI_ARG_CHECKED(arrayId, 1); 969 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2); 970 CONVERT_ARG_HANDLE_CHECKED(Object, length_obj, 3); 971 972 ASSERT(holder->GetInternalFieldCount() == 973 v8::ArrayBufferView::kInternalFieldCount); 974 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 975 holder->SetInternalField(i, Smi::FromInt(0)); 976 } 977 978 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. 979 size_t element_size = 1; // Bogus initialization. 980 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &element_size); 981 982 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 983 if (source->IsJSTypedArray() && 984 JSTypedArray::cast(*source)->type() == array_type) { 985 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate); 986 } 987 size_t length = NumberToSize(isolate, *length_obj); 988 989 if ((length > static_cast<unsigned>(Smi::kMaxValue)) || 990 (length > (kMaxInt / element_size))) { 991 return isolate->Throw(*isolate->factory()-> 992 NewRangeError("invalid_typed_array_length", 993 HandleVector<Object>(NULL, 0))); 994 } 995 size_t byte_length = length * element_size; 996 997 // NOTE: not initializing backing store. 998 // We assume that the caller of this function will initialize holder 999 // with the loop 1000 // for(i = 0; i < length; i++) { holder[i] = source[i]; } 1001 // We assume that the caller of this function is always a typed array 1002 // constructor. 1003 // If source is a typed array, this loop will always run to completion, 1004 // so we are sure that the backing store will be initialized. 1005 // Otherwise, the indexing operation might throw, so the loop will not 1006 // run to completion and the typed array might remain partly initialized. 1007 // However we further assume that the caller of this function is a typed array 1008 // constructor, and the exception will propagate out of the constructor, 1009 // therefore uninitialized memory will not be accessible by a user program. 1010 // 1011 // TODO(dslomov): revise this once we support subclassing. 1012 1013 if (!Runtime::SetupArrayBufferAllocatingData( 1014 isolate, buffer, byte_length, false)) { 1015 return isolate->Throw(*isolate->factory()-> 1016 NewRangeError("invalid_array_buffer_length", 1017 HandleVector<Object>(NULL, 0))); 1018 } 1019 1020 holder->set_buffer(*buffer); 1021 holder->set_byte_offset(Smi::FromInt(0)); 1022 Handle<Object> byte_length_obj( 1023 isolate->factory()->NewNumberFromSize(byte_length)); 1024 holder->set_byte_length(*byte_length_obj); 1025 holder->set_length(*length_obj); 1026 holder->set_weak_next(buffer->weak_first_view()); 1027 buffer->set_weak_first_view(*holder); 1028 1029 Handle<ExternalArray> elements = 1030 isolate->factory()->NewExternalArray( 1031 static_cast<int>(length), array_type, 1032 static_cast<uint8_t*>(buffer->backing_store())); 1033 holder->set_elements(*elements); 1034 1035 if (source->IsJSTypedArray()) { 1036 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source)); 1037 1038 if (typed_array->type() == holder->type()) { 1039 uint8_t* backing_store = 1040 static_cast<uint8_t*>( 1041 JSArrayBuffer::cast(typed_array->buffer())->backing_store()); 1042 size_t source_byte_offset = 1043 NumberToSize(isolate, typed_array->byte_offset()); 1044 memcpy( 1045 buffer->backing_store(), 1046 backing_store + source_byte_offset, 1047 byte_length); 1048 return *isolate->factory()->true_value(); 1049 } else { 1050 return *isolate->factory()->false_value(); 1051 } 1052 } 1053 1054 return *isolate->factory()->false_value(); 1055 } 1056 1057 1058 #define TYPED_ARRAY_GETTER(getter, accessor) \ 1059 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \ 1060 HandleScope scope(isolate); \ 1061 ASSERT(args.length() == 1); \ 1062 CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); \ 1063 if (!holder->IsJSTypedArray()) \ 1064 return isolate->Throw(*isolate->factory()->NewTypeError( \ 1065 "not_typed_array", HandleVector<Object>(NULL, 0))); \ 1066 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*holder)); \ 1067 return typed_array->accessor(); \ 1068 } 1069 1070 TYPED_ARRAY_GETTER(Buffer, buffer) 1071 TYPED_ARRAY_GETTER(ByteLength, byte_length) 1072 TYPED_ARRAY_GETTER(ByteOffset, byte_offset) 1073 TYPED_ARRAY_GETTER(Length, length) 1074 1075 #undef TYPED_ARRAY_GETTER 1076 1077 // Return codes for Runtime_TypedArraySetFastCases. 1078 // Should be synchronized with typedarray.js natives. 1079 enum TypedArraySetResultCodes { 1080 // Set from typed array of the same type. 1081 // This is processed by TypedArraySetFastCases 1082 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0, 1083 // Set from typed array of the different type, overlapping in memory. 1084 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1, 1085 // Set from typed array of the different type, non-overlapping. 1086 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2, 1087 // Set from non-typed array. 1088 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3 1089 }; 1090 1091 1092 RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { 1093 HandleScope scope(isolate); 1094 CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); 1095 CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1); 1096 CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2); 1097 1098 if (!target_obj->IsJSTypedArray()) 1099 return isolate->Throw(*isolate->factory()->NewTypeError( 1100 "not_typed_array", HandleVector<Object>(NULL, 0))); 1101 1102 if (!source_obj->IsJSTypedArray()) 1103 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY); 1104 1105 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); 1106 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); 1107 size_t offset = NumberToSize(isolate, *offset_obj); 1108 size_t target_length = NumberToSize(isolate, target->length()); 1109 size_t source_length = NumberToSize(isolate, source->length()); 1110 size_t target_byte_length = NumberToSize(isolate, target->byte_length()); 1111 size_t source_byte_length = NumberToSize(isolate, source->byte_length()); 1112 if (offset > target_length || 1113 offset + source_length > target_length || 1114 offset + source_length < offset) // overflow 1115 return isolate->Throw(*isolate->factory()->NewRangeError( 1116 "typed_array_set_source_too_large", HandleVector<Object>(NULL, 0))); 1117 1118 size_t target_offset = NumberToSize(isolate, target->byte_offset()); 1119 size_t source_offset = NumberToSize(isolate, source->byte_offset()); 1120 uint8_t* target_base = 1121 static_cast<uint8_t*>( 1122 JSArrayBuffer::cast(target->buffer())->backing_store()) + target_offset; 1123 uint8_t* source_base = 1124 static_cast<uint8_t*>( 1125 JSArrayBuffer::cast(source->buffer())->backing_store()) + source_offset; 1126 1127 // Typed arrays of the same type: use memmove. 1128 if (target->type() == source->type()) { 1129 memmove(target_base + offset * target->element_size(), 1130 source_base, source_byte_length); 1131 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE); 1132 } 1133 1134 // Typed arrays of different types over the same backing store 1135 if ((source_base <= target_base && 1136 source_base + source_byte_length > target_base) || 1137 (target_base <= source_base && 1138 target_base + target_byte_length > source_base)) { 1139 // We do not support overlapping ArrayBuffers 1140 ASSERT( 1141 JSArrayBuffer::cast(target->buffer())->backing_store() == 1142 JSArrayBuffer::cast(source->buffer())->backing_store()); 1143 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING); 1144 } else { // Non-overlapping typed arrays 1145 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING); 1146 } 1147 } 1148 1149 1150 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) { 1151 HandleScope scope(isolate); 1152 ASSERT(args.length() == 4); 1153 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); 1154 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); 1155 CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2); 1156 CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3); 1157 1158 ASSERT(holder->GetInternalFieldCount() == 1159 v8::ArrayBufferView::kInternalFieldCount); 1160 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) { 1161 holder->SetInternalField(i, Smi::FromInt(0)); 1162 } 1163 1164 holder->set_buffer(*buffer); 1165 ASSERT(byte_offset->IsNumber()); 1166 ASSERT( 1167 NumberToSize(isolate, buffer->byte_length()) >= 1168 NumberToSize(isolate, *byte_offset) 1169 + NumberToSize(isolate, *byte_length)); 1170 holder->set_byte_offset(*byte_offset); 1171 ASSERT(byte_length->IsNumber()); 1172 holder->set_byte_length(*byte_length); 1173 1174 holder->set_weak_next(buffer->weak_first_view()); 1175 buffer->set_weak_first_view(*holder); 1176 1177 return isolate->heap()->undefined_value(); 1178 } 1179 1180 1181 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) { 1182 HandleScope scope(isolate); 1183 ASSERT(args.length() == 1); 1184 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1185 return data_view->buffer(); 1186 } 1187 1188 1189 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) { 1190 HandleScope scope(isolate); 1191 ASSERT(args.length() == 1); 1192 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1193 return data_view->byte_offset(); 1194 } 1195 1196 1197 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) { 1198 HandleScope scope(isolate); 1199 ASSERT(args.length() == 1); 1200 CONVERT_ARG_HANDLE_CHECKED(JSDataView, data_view, 0); 1201 return data_view->byte_length(); 1202 } 1203 1204 1205 inline static bool NeedToFlipBytes(bool is_little_endian) { 1206 #ifdef V8_TARGET_LITTLE_ENDIAN 1207 return !is_little_endian; 1208 #else 1209 return is_little_endian; 1210 #endif 1211 } 1212 1213 1214 template<int n> 1215 inline void CopyBytes(uint8_t* target, uint8_t* source) { 1216 for (int i = 0; i < n; i++) { 1217 *(target++) = *(source++); 1218 } 1219 } 1220 1221 1222 template<int n> 1223 inline void FlipBytes(uint8_t* target, uint8_t* source) { 1224 source = source + (n-1); 1225 for (int i = 0; i < n; i++) { 1226 *(target++) = *(source--); 1227 } 1228 } 1229 1230 1231 template<typename T> 1232 inline static bool DataViewGetValue( 1233 Isolate* isolate, 1234 Handle<JSDataView> data_view, 1235 Handle<Object> byte_offset_obj, 1236 bool is_little_endian, 1237 T* result) { 1238 size_t byte_offset = 0; 1239 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { 1240 return false; 1241 } 1242 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1243 1244 size_t data_view_byte_offset = 1245 NumberToSize(isolate, data_view->byte_offset()); 1246 size_t data_view_byte_length = 1247 NumberToSize(isolate, data_view->byte_length()); 1248 if (byte_offset + sizeof(T) > data_view_byte_length || 1249 byte_offset + sizeof(T) < byte_offset) { // overflow 1250 return false; 1251 } 1252 1253 union Value { 1254 T data; 1255 uint8_t bytes[sizeof(T)]; 1256 }; 1257 1258 Value value; 1259 size_t buffer_offset = data_view_byte_offset + byte_offset; 1260 ASSERT( 1261 NumberToSize(isolate, buffer->byte_length()) 1262 >= buffer_offset + sizeof(T)); 1263 uint8_t* source = 1264 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1265 if (NeedToFlipBytes(is_little_endian)) { 1266 FlipBytes<sizeof(T)>(value.bytes, source); 1267 } else { 1268 CopyBytes<sizeof(T)>(value.bytes, source); 1269 } 1270 *result = value.data; 1271 return true; 1272 } 1273 1274 1275 template<typename T> 1276 static bool DataViewSetValue( 1277 Isolate* isolate, 1278 Handle<JSDataView> data_view, 1279 Handle<Object> byte_offset_obj, 1280 bool is_little_endian, 1281 T data) { 1282 size_t byte_offset = 0; 1283 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) { 1284 return false; 1285 } 1286 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); 1287 1288 size_t data_view_byte_offset = 1289 NumberToSize(isolate, data_view->byte_offset()); 1290 size_t data_view_byte_length = 1291 NumberToSize(isolate, data_view->byte_length()); 1292 if (byte_offset + sizeof(T) > data_view_byte_length || 1293 byte_offset + sizeof(T) < byte_offset) { // overflow 1294 return false; 1295 } 1296 1297 union Value { 1298 T data; 1299 uint8_t bytes[sizeof(T)]; 1300 }; 1301 1302 Value value; 1303 value.data = data; 1304 size_t buffer_offset = data_view_byte_offset + byte_offset; 1305 ASSERT( 1306 NumberToSize(isolate, buffer->byte_length()) 1307 >= buffer_offset + sizeof(T)); 1308 uint8_t* target = 1309 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; 1310 if (NeedToFlipBytes(is_little_endian)) { 1311 FlipBytes<sizeof(T)>(target, value.bytes); 1312 } else { 1313 CopyBytes<sizeof(T)>(target, value.bytes); 1314 } 1315 return true; 1316 } 1317 1318 1319 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \ 1320 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \ 1321 HandleScope scope(isolate); \ 1322 ASSERT(args.length() == 3); \ 1323 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1324 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ 1325 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ 1326 Type result; \ 1327 if (DataViewGetValue( \ 1328 isolate, holder, offset, is_little_endian, &result)) { \ 1329 return isolate->heap()->Converter(result); \ 1330 } else { \ 1331 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1332 "invalid_data_view_accessor_offset", \ 1333 HandleVector<Object>(NULL, 0))); \ 1334 } \ 1335 } 1336 1337 DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32) 1338 DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32) 1339 DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32) 1340 DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32) 1341 DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32) 1342 DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32) 1343 DATA_VIEW_GETTER(Float32, float, NumberFromDouble) 1344 DATA_VIEW_GETTER(Float64, double, NumberFromDouble) 1345 1346 #undef DATA_VIEW_GETTER 1347 1348 1349 template <typename T> 1350 static T DataViewConvertValue(double value); 1351 1352 1353 template <> 1354 int8_t DataViewConvertValue<int8_t>(double value) { 1355 return static_cast<int8_t>(DoubleToInt32(value)); 1356 } 1357 1358 1359 template <> 1360 int16_t DataViewConvertValue<int16_t>(double value) { 1361 return static_cast<int16_t>(DoubleToInt32(value)); 1362 } 1363 1364 1365 template <> 1366 int32_t DataViewConvertValue<int32_t>(double value) { 1367 return DoubleToInt32(value); 1368 } 1369 1370 1371 template <> 1372 uint8_t DataViewConvertValue<uint8_t>(double value) { 1373 return static_cast<uint8_t>(DoubleToUint32(value)); 1374 } 1375 1376 1377 template <> 1378 uint16_t DataViewConvertValue<uint16_t>(double value) { 1379 return static_cast<uint16_t>(DoubleToUint32(value)); 1380 } 1381 1382 1383 template <> 1384 uint32_t DataViewConvertValue<uint32_t>(double value) { 1385 return DoubleToUint32(value); 1386 } 1387 1388 1389 template <> 1390 float DataViewConvertValue<float>(double value) { 1391 return static_cast<float>(value); 1392 } 1393 1394 1395 template <> 1396 double DataViewConvertValue<double>(double value) { 1397 return value; 1398 } 1399 1400 1401 #define DATA_VIEW_SETTER(TypeName, Type) \ 1402 RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \ 1403 HandleScope scope(isolate); \ 1404 ASSERT(args.length() == 4); \ 1405 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ 1406 CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ 1407 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \ 1408 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ 1409 Type v = DataViewConvertValue<Type>(value->Number()); \ 1410 if (DataViewSetValue( \ 1411 isolate, holder, offset, is_little_endian, v)) { \ 1412 return isolate->heap()->undefined_value(); \ 1413 } else { \ 1414 return isolate->Throw(*isolate->factory()->NewRangeError( \ 1415 "invalid_data_view_accessor_offset", \ 1416 HandleVector<Object>(NULL, 0))); \ 1417 } \ 1418 } 1419 1420 DATA_VIEW_SETTER(Uint8, uint8_t) 1421 DATA_VIEW_SETTER(Int8, int8_t) 1422 DATA_VIEW_SETTER(Uint16, uint16_t) 1423 DATA_VIEW_SETTER(Int16, int16_t) 1424 DATA_VIEW_SETTER(Uint32, uint32_t) 1425 DATA_VIEW_SETTER(Int32, int32_t) 1426 DATA_VIEW_SETTER(Float32, float) 1427 DATA_VIEW_SETTER(Float64, double) 1428 1429 #undef DATA_VIEW_SETTER 1430 1431 1432 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { 1433 HandleScope scope(isolate); 1434 ASSERT(args.length() == 1); 1435 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1436 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0); 1437 holder->set_table(*table); 1438 return *holder; 1439 } 1440 1441 1442 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) { 1443 HandleScope scope(isolate); 1444 ASSERT(args.length() == 2); 1445 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1446 Handle<Object> key(args[1], isolate); 1447 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1448 table = ObjectHashSet::Add(table, key); 1449 holder->set_table(*table); 1450 return isolate->heap()->undefined_value(); 1451 } 1452 1453 1454 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) { 1455 HandleScope scope(isolate); 1456 ASSERT(args.length() == 2); 1457 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1458 Handle<Object> key(args[1], isolate); 1459 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1460 return isolate->heap()->ToBoolean(table->Contains(*key)); 1461 } 1462 1463 1464 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { 1465 HandleScope scope(isolate); 1466 ASSERT(args.length() == 2); 1467 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1468 Handle<Object> key(args[1], isolate); 1469 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1470 table = ObjectHashSet::Remove(table, key); 1471 holder->set_table(*table); 1472 return isolate->heap()->undefined_value(); 1473 } 1474 1475 1476 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetGetSize) { 1477 HandleScope scope(isolate); 1478 ASSERT(args.length() == 1); 1479 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); 1480 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table())); 1481 return Smi::FromInt(table->NumberOfElements()); 1482 } 1483 1484 1485 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) { 1486 HandleScope scope(isolate); 1487 ASSERT(args.length() == 1); 1488 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1489 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); 1490 holder->set_table(*table); 1491 return *holder; 1492 } 1493 1494 1495 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) { 1496 HandleScope scope(isolate); 1497 ASSERT(args.length() == 2); 1498 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1499 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1500 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1501 Handle<Object> lookup(table->Lookup(*key), isolate); 1502 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1503 } 1504 1505 1506 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapHas) { 1507 HandleScope scope(isolate); 1508 ASSERT(args.length() == 2); 1509 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1510 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1511 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1512 Handle<Object> lookup(table->Lookup(*key), isolate); 1513 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1514 } 1515 1516 1517 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) { 1518 HandleScope scope(isolate); 1519 ASSERT(args.length() == 2); 1520 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1521 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1522 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1523 Handle<Object> lookup(table->Lookup(*key), isolate); 1524 Handle<ObjectHashTable> new_table = 1525 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); 1526 holder->set_table(*new_table); 1527 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1528 } 1529 1530 1531 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { 1532 HandleScope scope(isolate); 1533 ASSERT(args.length() == 3); 1534 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1535 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1536 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 1537 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1538 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); 1539 holder->set_table(*new_table); 1540 return isolate->heap()->undefined_value(); 1541 } 1542 1543 1544 RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGetSize) { 1545 HandleScope scope(isolate); 1546 ASSERT(args.length() == 1); 1547 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0); 1548 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); 1549 return Smi::FromInt(table->NumberOfElements()); 1550 } 1551 1552 1553 static JSWeakCollection* WeakCollectionInitialize(Isolate* isolate, 1554 Handle<JSWeakCollection> weak_collection) { 1555 ASSERT(weak_collection->map()->inobject_properties() == 0); 1556 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0); 1557 weak_collection->set_table(*table); 1558 weak_collection->set_next(Smi::FromInt(0)); 1559 return *weak_collection; 1560 } 1561 1562 1563 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionInitialize) { 1564 HandleScope scope(isolate); 1565 ASSERT(args.length() == 1); 1566 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1567 return WeakCollectionInitialize(isolate, weak_collection); 1568 } 1569 1570 1571 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionGet) { 1572 HandleScope scope(isolate); 1573 ASSERT(args.length() == 2); 1574 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1575 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1576 Handle<ObjectHashTable> table( 1577 ObjectHashTable::cast(weak_collection->table())); 1578 Handle<Object> lookup(table->Lookup(*key), isolate); 1579 return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup; 1580 } 1581 1582 1583 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionHas) { 1584 HandleScope scope(isolate); 1585 ASSERT(args.length() == 2); 1586 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1587 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1588 Handle<ObjectHashTable> table( 1589 ObjectHashTable::cast(weak_collection->table())); 1590 Handle<Object> lookup(table->Lookup(*key), isolate); 1591 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1592 } 1593 1594 1595 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) { 1596 HandleScope scope(isolate); 1597 ASSERT(args.length() == 2); 1598 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1599 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1600 Handle<ObjectHashTable> table(ObjectHashTable::cast( 1601 weak_collection->table())); 1602 Handle<Object> lookup(table->Lookup(*key), isolate); 1603 Handle<ObjectHashTable> new_table = 1604 ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); 1605 weak_collection->set_table(*new_table); 1606 return isolate->heap()->ToBoolean(!lookup->IsTheHole()); 1607 } 1608 1609 1610 RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) { 1611 HandleScope scope(isolate); 1612 ASSERT(args.length() == 3); 1613 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0); 1614 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 1615 Handle<Object> value(args[2], isolate); 1616 Handle<ObjectHashTable> table( 1617 ObjectHashTable::cast(weak_collection->table())); 1618 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(table, key, value); 1619 weak_collection->set_table(*new_table); 1620 return isolate->heap()->undefined_value(); 1621 } 1622 1623 1624 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) { 1625 SealHandleScope shs(isolate); 1626 ASSERT(args.length() == 1); 1627 Object* obj = args[0]; 1628 if (!obj->IsJSObject()) return isolate->heap()->null_value(); 1629 return JSObject::cast(obj)->class_name(); 1630 } 1631 1632 1633 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) { 1634 HandleScope scope(isolate); 1635 ASSERT(args.length() == 1); 1636 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); 1637 // We don't expect access checks to be needed on JSProxy objects. 1638 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject()); 1639 do { 1640 if (obj->IsAccessCheckNeeded() && 1641 !isolate->MayNamedAccessWrapper(Handle<JSObject>::cast(obj), 1642 isolate->factory()->proto_string(), 1643 v8::ACCESS_GET)) { 1644 isolate->ReportFailedAccessCheck(JSObject::cast(*obj), v8::ACCESS_GET); 1645 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 1646 return isolate->heap()->undefined_value(); 1647 } 1648 obj = handle(obj->GetPrototype(isolate), isolate); 1649 } while (obj->IsJSObject() && 1650 JSObject::cast(*obj)->map()->is_hidden_prototype()); 1651 return *obj; 1652 } 1653 1654 1655 static inline Object* GetPrototypeSkipHiddenPrototypes(Isolate* isolate, 1656 Object* receiver) { 1657 Object* current = receiver->GetPrototype(isolate); 1658 while (current->IsJSObject() && 1659 JSObject::cast(current)->map()->is_hidden_prototype()) { 1660 current = current->GetPrototype(isolate); 1661 } 1662 return current; 1663 } 1664 1665 1666 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) { 1667 HandleScope scope(isolate); 1668 ASSERT(args.length() == 2); 1669 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1670 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1); 1671 if (FLAG_harmony_observation && obj->map()->is_observed()) { 1672 Handle<Object> old_value( 1673 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); 1674 1675 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); 1676 RETURN_IF_EMPTY_HANDLE(isolate, result); 1677 1678 Handle<Object> new_value( 1679 GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate); 1680 if (!new_value->SameValue(*old_value)) { 1681 JSObject::EnqueueChangeRecord(obj, "setPrototype", 1682 isolate->factory()->proto_string(), 1683 old_value); 1684 } 1685 return *result; 1686 } 1687 Handle<Object> result = JSObject::SetPrototype(obj, prototype, true); 1688 RETURN_IF_EMPTY_HANDLE(isolate, result); 1689 return *result; 1690 } 1691 1692 1693 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) { 1694 SealHandleScope shs(isolate); 1695 ASSERT(args.length() == 2); 1696 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8). 1697 Object* O = args[0]; 1698 Object* V = args[1]; 1699 while (true) { 1700 Object* prototype = V->GetPrototype(isolate); 1701 if (prototype->IsNull()) return isolate->heap()->false_value(); 1702 if (O == prototype) return isolate->heap()->true_value(); 1703 V = prototype; 1704 } 1705 } 1706 1707 1708 static bool CheckAccessException(Object* callback, 1709 v8::AccessType access_type) { 1710 DisallowHeapAllocation no_gc; 1711 if (callback->IsAccessorInfo()) { 1712 AccessorInfo* info = AccessorInfo::cast(callback); 1713 return 1714 (access_type == v8::ACCESS_HAS && 1715 (info->all_can_read() || info->all_can_write())) || 1716 (access_type == v8::ACCESS_GET && info->all_can_read()) || 1717 (access_type == v8::ACCESS_SET && info->all_can_write()); 1718 } 1719 if (callback->IsAccessorPair()) { 1720 AccessorPair* info = AccessorPair::cast(callback); 1721 return 1722 (access_type == v8::ACCESS_HAS && 1723 (info->all_can_read() || info->all_can_write())) || 1724 (access_type == v8::ACCESS_GET && info->all_can_read()) || 1725 (access_type == v8::ACCESS_SET && info->all_can_write()); 1726 } 1727 return false; 1728 } 1729 1730 1731 template<class Key> 1732 static bool CheckGenericAccess( 1733 Handle<JSObject> receiver, 1734 Handle<JSObject> holder, 1735 Key key, 1736 v8::AccessType access_type, 1737 bool (Isolate::*mayAccess)(Handle<JSObject>, Key, v8::AccessType)) { 1738 Isolate* isolate = receiver->GetIsolate(); 1739 for (Handle<JSObject> current = receiver; 1740 true; 1741 current = handle(JSObject::cast(current->GetPrototype()), isolate)) { 1742 if (current->IsAccessCheckNeeded() && 1743 !(isolate->*mayAccess)(current, key, access_type)) { 1744 return false; 1745 } 1746 if (current.is_identical_to(holder)) break; 1747 } 1748 return true; 1749 } 1750 1751 1752 enum AccessCheckResult { 1753 ACCESS_FORBIDDEN, 1754 ACCESS_ALLOWED, 1755 ACCESS_ABSENT 1756 }; 1757 1758 1759 static AccessCheckResult CheckPropertyAccess(Handle<JSObject> obj, 1760 Handle<Name> name, 1761 v8::AccessType access_type) { 1762 uint32_t index; 1763 if (name->AsArrayIndex(&index)) { 1764 // TODO(1095): we should traverse hidden prototype hierachy as well. 1765 if (CheckGenericAccess( 1766 obj, obj, index, access_type, &Isolate::MayIndexedAccessWrapper)) { 1767 return ACCESS_ALLOWED; 1768 } 1769 1770 obj->GetIsolate()->ReportFailedAccessCheck(*obj, access_type); 1771 return ACCESS_FORBIDDEN; 1772 } 1773 1774 Isolate* isolate = obj->GetIsolate(); 1775 LookupResult lookup(isolate); 1776 obj->LocalLookup(*name, &lookup, true); 1777 1778 if (!lookup.IsProperty()) return ACCESS_ABSENT; 1779 Handle<JSObject> holder(lookup.holder(), isolate); 1780 if (CheckGenericAccess<Handle<Object> >( 1781 obj, holder, name, access_type, &Isolate::MayNamedAccessWrapper)) { 1782 return ACCESS_ALLOWED; 1783 } 1784 1785 // Access check callback denied the access, but some properties 1786 // can have a special permissions which override callbacks descision 1787 // (currently see v8::AccessControl). 1788 // API callbacks can have per callback access exceptions. 1789 switch (lookup.type()) { 1790 case CALLBACKS: 1791 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1792 return ACCESS_ALLOWED; 1793 } 1794 break; 1795 case INTERCEPTOR: 1796 // If the object has an interceptor, try real named properties. 1797 // Overwrite the result to fetch the correct property later. 1798 holder->LookupRealNamedProperty(*name, &lookup); 1799 if (lookup.IsProperty() && lookup.IsPropertyCallbacks()) { 1800 if (CheckAccessException(lookup.GetCallbackObject(), access_type)) { 1801 return ACCESS_ALLOWED; 1802 } 1803 } 1804 break; 1805 default: 1806 break; 1807 } 1808 1809 isolate->ReportFailedAccessCheck(*obj, access_type); 1810 return ACCESS_FORBIDDEN; 1811 } 1812 1813 1814 // Enumerator used as indices into the array returned from GetOwnProperty 1815 enum PropertyDescriptorIndices { 1816 IS_ACCESSOR_INDEX, 1817 VALUE_INDEX, 1818 GETTER_INDEX, 1819 SETTER_INDEX, 1820 WRITABLE_INDEX, 1821 ENUMERABLE_INDEX, 1822 CONFIGURABLE_INDEX, 1823 DESCRIPTOR_SIZE 1824 }; 1825 1826 1827 static Handle<Object> GetOwnProperty(Isolate* isolate, 1828 Handle<JSObject> obj, 1829 Handle<Name> name) { 1830 Heap* heap = isolate->heap(); 1831 Factory* factory = isolate->factory(); 1832 // Due to some WebKit tests, we want to make sure that we do not log 1833 // more than one access failure here. 1834 AccessCheckResult access_check_result = 1835 CheckPropertyAccess(obj, name, v8::ACCESS_HAS); 1836 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); 1837 switch (access_check_result) { 1838 case ACCESS_FORBIDDEN: return factory->false_value(); 1839 case ACCESS_ALLOWED: break; 1840 case ACCESS_ABSENT: return factory->undefined_value(); 1841 } 1842 1843 PropertyAttributes attrs = obj->GetLocalPropertyAttribute(*name); 1844 if (attrs == ABSENT) { 1845 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); 1846 return factory->undefined_value(); 1847 } 1848 ASSERT(!isolate->has_scheduled_exception()); 1849 AccessorPair* raw_accessors = obj->GetLocalPropertyAccessorPair(*name); 1850 Handle<AccessorPair> accessors(raw_accessors, isolate); 1851 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE); 1852 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0)); 1853 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0)); 1854 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(raw_accessors != NULL)); 1855 1856 if (raw_accessors == NULL) { 1857 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0)); 1858 // GetProperty does access check. 1859 Handle<Object> value = GetProperty(isolate, obj, name); 1860 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<Object>::null()); 1861 elms->set(VALUE_INDEX, *value); 1862 } else { 1863 // Access checks are performed for both accessors separately. 1864 // When they fail, the respective field is not set in the descriptor. 1865 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate); 1866 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate); 1867 1868 if (!getter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_GET)) { 1869 ASSERT(!isolate->has_scheduled_exception()); 1870 elms->set(GETTER_INDEX, *getter); 1871 } else { 1872 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); 1873 } 1874 1875 if (!setter->IsMap() && CheckPropertyAccess(obj, name, v8::ACCESS_SET)) { 1876 ASSERT(!isolate->has_scheduled_exception()); 1877 elms->set(SETTER_INDEX, *setter); 1878 } else { 1879 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object); 1880 } 1881 } 1882 1883 return isolate->factory()->NewJSArrayWithElements(elms); 1884 } 1885 1886 1887 // Returns an array with the property description: 1888 // if args[1] is not a property on args[0] 1889 // returns undefined 1890 // if args[1] is a data property on args[0] 1891 // [false, value, Writeable, Enumerable, Configurable] 1892 // if args[1] is an accessor on args[0] 1893 // [true, GetFunction, SetFunction, Enumerable, Configurable] 1894 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) { 1895 HandleScope scope(isolate); 1896 ASSERT(args.length() == 2); 1897 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1898 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 1899 Handle<Object> result = GetOwnProperty(isolate, obj, name); 1900 RETURN_IF_EMPTY_HANDLE(isolate, result); 1901 return *result; 1902 } 1903 1904 1905 RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) { 1906 HandleScope scope(isolate); 1907 ASSERT(args.length() == 1); 1908 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 1909 Handle<Object> result = JSObject::PreventExtensions(obj); 1910 RETURN_IF_EMPTY_HANDLE(isolate, result); 1911 return *result; 1912 } 1913 1914 1915 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) { 1916 SealHandleScope shs(isolate); 1917 ASSERT(args.length() == 1); 1918 CONVERT_ARG_CHECKED(JSObject, obj, 0); 1919 if (obj->IsJSGlobalProxy()) { 1920 Object* proto = obj->GetPrototype(); 1921 if (proto->IsNull()) return isolate->heap()->false_value(); 1922 ASSERT(proto->IsJSGlobalObject()); 1923 obj = JSObject::cast(proto); 1924 } 1925 return isolate->heap()->ToBoolean(obj->map()->is_extensible()); 1926 } 1927 1928 1929 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) { 1930 HandleScope scope(isolate); 1931 ASSERT(args.length() == 3); 1932 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0); 1933 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 1934 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2); 1935 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags); 1936 RETURN_IF_EMPTY_HANDLE(isolate, result); 1937 return *result; 1938 } 1939 1940 1941 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) { 1942 HandleScope scope(isolate); 1943 ASSERT(args.length() == 1); 1944 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0); 1945 return *isolate->factory()->CreateApiFunction(data); 1946 } 1947 1948 1949 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) { 1950 SealHandleScope shs(isolate); 1951 ASSERT(args.length() == 1); 1952 Object* arg = args[0]; 1953 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); 1954 return isolate->heap()->ToBoolean(result); 1955 } 1956 1957 1958 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) { 1959 SealHandleScope shs(isolate); 1960 ASSERT(args.length() == 2); 1961 CONVERT_ARG_CHECKED(HeapObject, templ, 0); 1962 CONVERT_SMI_ARG_CHECKED(index, 1) 1963 int offset = index * kPointerSize + HeapObject::kHeaderSize; 1964 InstanceType type = templ->map()->instance_type(); 1965 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || 1966 type == OBJECT_TEMPLATE_INFO_TYPE); 1967 RUNTIME_ASSERT(offset > 0); 1968 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { 1969 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); 1970 } else { 1971 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); 1972 } 1973 return *HeapObject::RawField(templ, offset); 1974 } 1975 1976 1977 RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) { 1978 SealHandleScope shs(isolate); 1979 ASSERT(args.length() == 1); 1980 CONVERT_ARG_CHECKED(HeapObject, object, 0); 1981 Map* old_map = object->map(); 1982 bool needs_access_checks = old_map->is_access_check_needed(); 1983 if (needs_access_checks) { 1984 // Copy map so it won't interfere constructor's initial map. 1985 Map* new_map; 1986 MaybeObject* maybe_new_map = old_map->Copy(); 1987 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 1988 1989 new_map->set_is_access_check_needed(false); 1990 object->set_map(new_map); 1991 } 1992 return isolate->heap()->ToBoolean(needs_access_checks); 1993 } 1994 1995 1996 RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) { 1997 SealHandleScope shs(isolate); 1998 ASSERT(args.length() == 1); 1999 CONVERT_ARG_CHECKED(HeapObject, object, 0); 2000 Map* old_map = object->map(); 2001 if (!old_map->is_access_check_needed()) { 2002 // Copy map so it won't interfere constructor's initial map. 2003 Map* new_map; 2004 MaybeObject* maybe_new_map = old_map->Copy(); 2005 if (!maybe_new_map->To(&new_map)) return maybe_new_map; 2006 2007 new_map->set_is_access_check_needed(true); 2008 object->set_map(new_map); 2009 } 2010 return isolate->heap()->undefined_value(); 2011 } 2012 2013 2014 // Transform getter or setter into something DefineAccessor can handle. 2015 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate, 2016 Handle<Object> component) { 2017 if (component->IsUndefined()) return isolate->factory()->null_value(); 2018 Handle<FunctionTemplateInfo> info = 2019 Handle<FunctionTemplateInfo>::cast(component); 2020 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction()); 2021 } 2022 2023 2024 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) { 2025 HandleScope scope(isolate); 2026 ASSERT(args.length() == 6); 2027 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 2028 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 2029 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 2030 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 2031 CONVERT_SMI_ARG_CHECKED(attribute, 4); 2032 CONVERT_SMI_ARG_CHECKED(access_control, 5); 2033 JSObject::DefineAccessor(object, 2034 name, 2035 InstantiateAccessorComponent(isolate, getter), 2036 InstantiateAccessorComponent(isolate, setter), 2037 static_cast<PropertyAttributes>(attribute), 2038 static_cast<v8::AccessControl>(access_control)); 2039 return isolate->heap()->undefined_value(); 2040 } 2041 2042 2043 static Failure* ThrowRedeclarationError(Isolate* isolate, 2044 const char* type, 2045 Handle<String> name) { 2046 HandleScope scope(isolate); 2047 Handle<Object> type_handle = 2048 isolate->factory()->NewStringFromAscii(CStrVector(type)); 2049 Handle<Object> args[2] = { type_handle, name }; 2050 Handle<Object> error = 2051 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2)); 2052 return isolate->Throw(*error); 2053 } 2054 2055 2056 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { 2057 HandleScope scope(isolate); 2058 ASSERT(args.length() == 3); 2059 Handle<GlobalObject> global = Handle<GlobalObject>( 2060 isolate->context()->global_object()); 2061 2062 Handle<Context> context = args.at<Context>(0); 2063 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); 2064 CONVERT_SMI_ARG_CHECKED(flags, 2); 2065 2066 // Traverse the name/value pairs and set the properties. 2067 int length = pairs->length(); 2068 for (int i = 0; i < length; i += 2) { 2069 HandleScope scope(isolate); 2070 Handle<String> name(String::cast(pairs->get(i))); 2071 Handle<Object> value(pairs->get(i + 1), isolate); 2072 2073 // We have to declare a global const property. To capture we only 2074 // assign to it when evaluating the assignment for "const x = 2075 // <expr>" the initial value is the hole. 2076 bool is_var = value->IsUndefined(); 2077 bool is_const = value->IsTheHole(); 2078 bool is_function = value->IsSharedFunctionInfo(); 2079 ASSERT(is_var + is_const + is_function == 1); 2080 2081 if (is_var || is_const) { 2082 // Lookup the property in the global object, and don't set the 2083 // value of the variable if the property is already there. 2084 // Do the lookup locally only, see ES5 erratum. 2085 LookupResult lookup(isolate); 2086 if (FLAG_es52_globals) { 2087 global->LocalLookup(*name, &lookup, true); 2088 } else { 2089 global->Lookup(*name, &lookup); 2090 } 2091 if (lookup.IsFound()) { 2092 // We found an existing property. Unless it was an interceptor 2093 // that claims the property is absent, skip this declaration. 2094 if (!lookup.IsInterceptor()) continue; 2095 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 2096 if (attributes != ABSENT) continue; 2097 // Fall-through and introduce the absent property by using 2098 // SetProperty. 2099 } 2100 } else if (is_function) { 2101 // Copy the function and update its context. Use it as value. 2102 Handle<SharedFunctionInfo> shared = 2103 Handle<SharedFunctionInfo>::cast(value); 2104 Handle<JSFunction> function = 2105 isolate->factory()->NewFunctionFromSharedFunctionInfo( 2106 shared, context, TENURED); 2107 value = function; 2108 } 2109 2110 LookupResult lookup(isolate); 2111 global->LocalLookup(*name, &lookup, true); 2112 2113 // Compute the property attributes. According to ECMA-262, 2114 // the property must be non-configurable except in eval. 2115 int attr = NONE; 2116 bool is_eval = DeclareGlobalsEvalFlag::decode(flags); 2117 if (!is_eval) { 2118 attr |= DONT_DELETE; 2119 } 2120 bool is_native = DeclareGlobalsNativeFlag::decode(flags); 2121 if (is_const || (is_native && is_function)) { 2122 attr |= READ_ONLY; 2123 } 2124 2125 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); 2126 2127 if (!lookup.IsFound() || is_function) { 2128 // If the local property exists, check that we can reconfigure it 2129 // as required for function declarations. 2130 if (lookup.IsFound() && lookup.IsDontDelete()) { 2131 if (lookup.IsReadOnly() || lookup.IsDontEnum() || 2132 lookup.IsPropertyCallbacks()) { 2133 return ThrowRedeclarationError(isolate, "function", name); 2134 } 2135 // If the existing property is not configurable, keep its attributes. 2136 attr = lookup.GetAttributes(); 2137 } 2138 // Define or redefine own property. 2139 RETURN_IF_EMPTY_HANDLE(isolate, 2140 JSObject::SetLocalPropertyIgnoreAttributes( 2141 global, name, value, static_cast<PropertyAttributes>(attr))); 2142 } else { 2143 // Do a [[Put]] on the existing (own) property. 2144 RETURN_IF_EMPTY_HANDLE(isolate, 2145 JSObject::SetProperty( 2146 global, name, value, static_cast<PropertyAttributes>(attr), 2147 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode)); 2148 } 2149 } 2150 2151 ASSERT(!isolate->has_pending_exception()); 2152 return isolate->heap()->undefined_value(); 2153 } 2154 2155 2156 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { 2157 HandleScope scope(isolate); 2158 ASSERT(args.length() == 4); 2159 2160 // Declarations are always made in a function or native context. In the 2161 // case of eval code, the context passed is the context of the caller, 2162 // which may be some nested context and not the declaration context. 2163 RUNTIME_ASSERT(args[0]->IsContext()); 2164 Handle<Context> context(Context::cast(args[0])->declaration_context()); 2165 2166 Handle<String> name(String::cast(args[1])); 2167 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2)); 2168 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE); 2169 Handle<Object> initial_value(args[3], isolate); 2170 2171 int index; 2172 PropertyAttributes attributes; 2173 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 2174 BindingFlags binding_flags; 2175 Handle<Object> holder = 2176 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2177 2178 if (attributes != ABSENT) { 2179 // The name was declared before; check for conflicting re-declarations. 2180 // Note: this is actually inconsistent with what happens for globals (where 2181 // we silently ignore such declarations). 2182 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 2183 // Functions are not read-only. 2184 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 2185 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 2186 return ThrowRedeclarationError(isolate, type, name); 2187 } 2188 2189 // Initialize it if necessary. 2190 if (*initial_value != NULL) { 2191 if (index >= 0) { 2192 ASSERT(holder.is_identical_to(context)); 2193 if (((attributes & READ_ONLY) == 0) || 2194 context->get(index)->IsTheHole()) { 2195 context->set(index, *initial_value); 2196 } 2197 } else { 2198 // Slow case: The property is in the context extension object of a 2199 // function context or the global object of a native context. 2200 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2201 RETURN_IF_EMPTY_HANDLE( 2202 isolate, 2203 JSReceiver::SetProperty(object, name, initial_value, mode, 2204 kNonStrictMode)); 2205 } 2206 } 2207 2208 } else { 2209 // The property is not in the function context. It needs to be 2210 // "declared" in the function context's extension context or as a 2211 // property of the the global object. 2212 Handle<JSObject> object; 2213 if (context->has_extension()) { 2214 object = Handle<JSObject>(JSObject::cast(context->extension())); 2215 } else { 2216 // Context extension objects are allocated lazily. 2217 ASSERT(context->IsFunctionContext()); 2218 object = isolate->factory()->NewJSObject( 2219 isolate->context_extension_function()); 2220 context->set_extension(*object); 2221 } 2222 ASSERT(*object != NULL); 2223 2224 // Declare the property by setting it to the initial value if provided, 2225 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for 2226 // constant declarations). 2227 ASSERT(!JSReceiver::HasLocalProperty(object, name)); 2228 Handle<Object> value(isolate->heap()->undefined_value(), isolate); 2229 if (*initial_value != NULL) value = initial_value; 2230 // Declaring a const context slot is a conflicting declaration if 2231 // there is a callback with that name in a prototype. It is 2232 // allowed to introduce const variables in 2233 // JSContextExtensionObjects. They are treated specially in 2234 // SetProperty and no setters are invoked for those since they are 2235 // not real JSObjects. 2236 if (initial_value->IsTheHole() && 2237 !object->IsJSContextExtensionObject()) { 2238 LookupResult lookup(isolate); 2239 object->Lookup(*name, &lookup); 2240 if (lookup.IsPropertyCallbacks()) { 2241 return ThrowRedeclarationError(isolate, "const", name); 2242 } 2243 } 2244 if (object->IsJSGlobalObject()) { 2245 // Define own property on the global object. 2246 RETURN_IF_EMPTY_HANDLE(isolate, 2247 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode)); 2248 } else { 2249 RETURN_IF_EMPTY_HANDLE(isolate, 2250 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); 2251 } 2252 } 2253 2254 return isolate->heap()->undefined_value(); 2255 } 2256 2257 2258 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { 2259 HandleScope scope(isolate); 2260 // args[0] == name 2261 // args[1] == language_mode 2262 // args[2] == value (optional) 2263 2264 // Determine if we need to assign to the variable if it already 2265 // exists (based on the number of arguments). 2266 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); 2267 bool assign = args.length() == 3; 2268 2269 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2270 RUNTIME_ASSERT(args[1]->IsSmi()); 2271 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); 2272 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) 2273 ? kNonStrictMode : kStrictMode; 2274 2275 // According to ECMA-262, section 12.2, page 62, the property must 2276 // not be deletable. 2277 PropertyAttributes attributes = DONT_DELETE; 2278 2279 // Lookup the property locally in the global object. If it isn't 2280 // there, there is a property with this name in the prototype chain. 2281 // We follow Safari and Firefox behavior and only set the property 2282 // locally if there is an explicit initialization value that we have 2283 // to assign to the property. 2284 // Note that objects can have hidden prototypes, so we need to traverse 2285 // the whole chain of hidden prototypes to do a 'local' lookup. 2286 LookupResult lookup(isolate); 2287 isolate->context()->global_object()->LocalLookup(*name, &lookup, true); 2288 if (lookup.IsInterceptor()) { 2289 PropertyAttributes intercepted = 2290 lookup.holder()->GetPropertyAttribute(*name); 2291 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 2292 // Found an interceptor that's not read only. 2293 if (assign) { 2294 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 2295 Handle<Object> result = JSObject::SetPropertyForResult( 2296 handle(lookup.holder()), &lookup, name, value, attributes, 2297 strict_mode_flag); 2298 RETURN_IF_EMPTY_HANDLE(isolate, result); 2299 return *result; 2300 } else { 2301 return isolate->heap()->undefined_value(); 2302 } 2303 } 2304 } 2305 2306 if (assign) { 2307 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 2308 Handle<GlobalObject> global(isolate->context()->global_object()); 2309 Handle<Object> result = JSReceiver::SetProperty( 2310 global, name, value, attributes, strict_mode_flag); 2311 RETURN_IF_EMPTY_HANDLE(isolate, result); 2312 return *result; 2313 } 2314 return isolate->heap()->undefined_value(); 2315 } 2316 2317 2318 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { 2319 SealHandleScope shs(isolate); 2320 // All constants are declared with an initial value. The name 2321 // of the constant is the first argument and the initial value 2322 // is the second. 2323 RUNTIME_ASSERT(args.length() == 2); 2324 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 2325 Handle<Object> value = args.at<Object>(1); 2326 2327 // Get the current global object from top. 2328 GlobalObject* global = isolate->context()->global_object(); 2329 2330 // According to ECMA-262, section 12.2, page 62, the property must 2331 // not be deletable. Since it's a const, it must be READ_ONLY too. 2332 PropertyAttributes attributes = 2333 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY); 2334 2335 // Lookup the property locally in the global object. If it isn't 2336 // there, we add the property and take special precautions to always 2337 // add it as a local property even in case of callbacks in the 2338 // prototype chain (this rules out using SetProperty). 2339 // We use SetLocalPropertyIgnoreAttributes instead 2340 LookupResult lookup(isolate); 2341 global->LocalLookup(*name, &lookup); 2342 if (!lookup.IsFound()) { 2343 HandleScope handle_scope(isolate); 2344 Handle<GlobalObject> global(isolate->context()->global_object()); 2345 RETURN_IF_EMPTY_HANDLE( 2346 isolate, 2347 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value, 2348 attributes)); 2349 return *value; 2350 } 2351 2352 if (!lookup.IsReadOnly()) { 2353 // Restore global object from context (in case of GC) and continue 2354 // with setting the value. 2355 HandleScope handle_scope(isolate); 2356 Handle<GlobalObject> global(isolate->context()->global_object()); 2357 2358 // BUG 1213575: Handle the case where we have to set a read-only 2359 // property through an interceptor and only do it if it's 2360 // uninitialized, e.g. the hole. Nirk... 2361 // Passing non-strict mode because the property is writable. 2362 RETURN_IF_EMPTY_HANDLE( 2363 isolate, 2364 JSReceiver::SetProperty(global, name, value, attributes, 2365 kNonStrictMode)); 2366 return *value; 2367 } 2368 2369 // Set the value, but only if we're assigning the initial value to a 2370 // constant. For now, we determine this by checking if the 2371 // current value is the hole. 2372 // Strict mode handling not needed (const is disallowed in strict mode). 2373 if (lookup.IsField()) { 2374 FixedArray* properties = global->properties(); 2375 int index = lookup.GetFieldIndex().field_index(); 2376 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) { 2377 properties->set(index, *value); 2378 } 2379 } else if (lookup.IsNormal()) { 2380 if (global->GetNormalizedProperty(&lookup)->IsTheHole() || 2381 !lookup.IsReadOnly()) { 2382 HandleScope scope(isolate); 2383 JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value); 2384 } 2385 } else { 2386 // Ignore re-initialization of constants that have already been 2387 // assigned a constant value. 2388 ASSERT(lookup.IsReadOnly() && lookup.IsConstant()); 2389 } 2390 2391 // Use the set value as the result of the operation. 2392 return *value; 2393 } 2394 2395 2396 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) { 2397 HandleScope scope(isolate); 2398 ASSERT(args.length() == 3); 2399 2400 Handle<Object> value(args[0], isolate); 2401 ASSERT(!value->IsTheHole()); 2402 2403 // Initializations are always done in a function or native context. 2404 RUNTIME_ASSERT(args[1]->IsContext()); 2405 Handle<Context> context(Context::cast(args[1])->declaration_context()); 2406 2407 Handle<String> name(String::cast(args[2])); 2408 2409 int index; 2410 PropertyAttributes attributes; 2411 ContextLookupFlags flags = FOLLOW_CHAINS; 2412 BindingFlags binding_flags; 2413 Handle<Object> holder = 2414 context->Lookup(name, flags, &index, &attributes, &binding_flags); 2415 2416 if (index >= 0) { 2417 ASSERT(holder->IsContext()); 2418 // Property was found in a context. Perform the assignment if we 2419 // found some non-constant or an uninitialized constant. 2420 Handle<Context> context = Handle<Context>::cast(holder); 2421 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) { 2422 context->set(index, *value); 2423 } 2424 return *value; 2425 } 2426 2427 // The property could not be found, we introduce it as a property of the 2428 // global object. 2429 if (attributes == ABSENT) { 2430 Handle<JSObject> global = Handle<JSObject>( 2431 isolate->context()->global_object()); 2432 // Strict mode not needed (const disallowed in strict mode). 2433 RETURN_IF_EMPTY_HANDLE( 2434 isolate, 2435 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode)); 2436 return *value; 2437 } 2438 2439 // The property was present in some function's context extension object, 2440 // as a property on the subject of a with, or as a property of the global 2441 // object. 2442 // 2443 // In most situations, eval-introduced consts should still be present in 2444 // the context extension object. However, because declaration and 2445 // initialization are separate, the property might have been deleted 2446 // before we reach the initialization point. 2447 // 2448 // Example: 2449 // 2450 // function f() { eval("delete x; const x;"); } 2451 // 2452 // In that case, the initialization behaves like a normal assignment. 2453 Handle<JSObject> object = Handle<JSObject>::cast(holder); 2454 2455 if (*object == context->extension()) { 2456 // This is the property that was introduced by the const declaration. 2457 // Set it if it hasn't been set before. NOTE: We cannot use 2458 // GetProperty() to get the current value as it 'unholes' the value. 2459 LookupResult lookup(isolate); 2460 object->LocalLookupRealNamedProperty(*name, &lookup); 2461 ASSERT(lookup.IsFound()); // the property was declared 2462 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only 2463 2464 if (lookup.IsField()) { 2465 FixedArray* properties = object->properties(); 2466 int index = lookup.GetFieldIndex().field_index(); 2467 if (properties->get(index)->IsTheHole()) { 2468 properties->set(index, *value); 2469 } 2470 } else if (lookup.IsNormal()) { 2471 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) { 2472 JSObject::SetNormalizedProperty(object, &lookup, value); 2473 } 2474 } else { 2475 // We should not reach here. Any real, named property should be 2476 // either a field or a dictionary slot. 2477 UNREACHABLE(); 2478 } 2479 } else { 2480 // The property was found on some other object. Set it if it is not a 2481 // read-only property. 2482 if ((attributes & READ_ONLY) == 0) { 2483 // Strict mode not needed (const disallowed in strict mode). 2484 RETURN_IF_EMPTY_HANDLE( 2485 isolate, 2486 JSReceiver::SetProperty(object, name, value, attributes, 2487 kNonStrictMode)); 2488 } 2489 } 2490 2491 return *value; 2492 } 2493 2494 2495 RUNTIME_FUNCTION(MaybeObject*, 2496 Runtime_OptimizeObjectForAddingMultipleProperties) { 2497 HandleScope scope(isolate); 2498 ASSERT(args.length() == 2); 2499 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 2500 CONVERT_SMI_ARG_CHECKED(properties, 1); 2501 if (object->HasFastProperties()) { 2502 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties); 2503 } 2504 return *object; 2505 } 2506 2507 2508 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) { 2509 HandleScope scope(isolate); 2510 ASSERT(args.length() == 4); 2511 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 2512 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 2513 // Due to the way the JS calls are constructed this must be less than the 2514 // length of a string, i.e. it is always a Smi. We check anyway for security. 2515 CONVERT_SMI_ARG_CHECKED(index, 2); 2516 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 2517 RUNTIME_ASSERT(index >= 0); 2518 RUNTIME_ASSERT(index <= subject->length()); 2519 isolate->counters()->regexp_entry_runtime()->Increment(); 2520 Handle<Object> result = RegExpImpl::Exec(regexp, 2521 subject, 2522 index, 2523 last_match_info); 2524 RETURN_IF_EMPTY_HANDLE(isolate, result); 2525 return *result; 2526 } 2527 2528 2529 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) { 2530 SealHandleScope shs(isolate); 2531 ASSERT(args.length() == 3); 2532 CONVERT_SMI_ARG_CHECKED(elements_count, 0); 2533 if (elements_count < 0 || 2534 elements_count > FixedArray::kMaxLength || 2535 !Smi::IsValid(elements_count)) { 2536 return isolate->ThrowIllegalOperation(); 2537 } 2538 Object* new_object; 2539 { MaybeObject* maybe_new_object = 2540 isolate->heap()->AllocateFixedArray(elements_count); 2541 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 2542 } 2543 FixedArray* elements = FixedArray::cast(new_object); 2544 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw( 2545 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE); 2546 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object; 2547 } 2548 { 2549 DisallowHeapAllocation no_gc; 2550 HandleScope scope(isolate); 2551 reinterpret_cast<HeapObject*>(new_object)-> 2552 set_map(isolate->native_context()->regexp_result_map()); 2553 } 2554 JSArray* array = JSArray::cast(new_object); 2555 array->set_properties(isolate->heap()->empty_fixed_array()); 2556 array->set_elements(elements); 2557 array->set_length(Smi::FromInt(elements_count)); 2558 // Write in-object properties after the length of the array. 2559 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]); 2560 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]); 2561 return array; 2562 } 2563 2564 2565 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) { 2566 HandleScope scope(isolate); 2567 DisallowHeapAllocation no_allocation; 2568 ASSERT(args.length() == 5); 2569 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 2570 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 2571 // If source is the empty string we set it to "(?:)" instead as 2572 // suggested by ECMA-262, 5th, section 15.10.4.1. 2573 if (source->length() == 0) source = isolate->factory()->query_colon_string(); 2574 2575 CONVERT_ARG_HANDLE_CHECKED(Object, global, 2); 2576 if (!global->IsTrue()) global = isolate->factory()->false_value(); 2577 2578 CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3); 2579 if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value(); 2580 2581 CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4); 2582 if (!multiline->IsTrue()) multiline = isolate->factory()->false_value(); 2583 2584 Map* map = regexp->map(); 2585 Object* constructor = map->constructor(); 2586 if (constructor->IsJSFunction() && 2587 JSFunction::cast(constructor)->initial_map() == map) { 2588 // If we still have the original map, set in-object properties directly. 2589 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source); 2590 // Both true and false are immovable immortal objects so no need for write 2591 // barrier. 2592 regexp->InObjectPropertyAtPut( 2593 JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER); 2594 regexp->InObjectPropertyAtPut( 2595 JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER); 2596 regexp->InObjectPropertyAtPut( 2597 JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER); 2598 regexp->InObjectPropertyAtPut( 2599 JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER); 2600 return *regexp; 2601 } 2602 2603 // Map has changed, so use generic, but slower, method. 2604 PropertyAttributes final = 2605 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE); 2606 PropertyAttributes writable = 2607 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE); 2608 Handle<Object> zero(Smi::FromInt(0), isolate); 2609 Factory* factory = isolate->factory(); 2610 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( 2611 regexp, factory->source_string(), source, final)); 2612 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( 2613 regexp, factory->global_string(), global, final)); 2614 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( 2615 regexp, factory->ignore_case_string(), ignoreCase, final)); 2616 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( 2617 regexp, factory->multiline_string(), multiline, final)); 2618 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes( 2619 regexp, factory->last_index_string(), zero, writable)); 2620 return *regexp; 2621 } 2622 2623 2624 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) { 2625 HandleScope scope(isolate); 2626 ASSERT(args.length() == 1); 2627 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0); 2628 // This is necessary to enable fast checks for absence of elements 2629 // on Array.prototype and below. 2630 prototype->set_elements(isolate->heap()->empty_fixed_array()); 2631 return Smi::FromInt(0); 2632 } 2633 2634 2635 static Handle<JSFunction> InstallBuiltin(Isolate* isolate, 2636 Handle<JSObject> holder, 2637 const char* name, 2638 Builtins::Name builtin_name) { 2639 Handle<String> key = isolate->factory()->InternalizeUtf8String(name); 2640 Handle<Code> code(isolate->builtins()->builtin(builtin_name)); 2641 Handle<JSFunction> optimized = 2642 isolate->factory()->NewFunction(key, 2643 JS_OBJECT_TYPE, 2644 JSObject::kHeaderSize, 2645 code, 2646 false); 2647 optimized->shared()->DontAdaptArguments(); 2648 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode); 2649 return optimized; 2650 } 2651 2652 2653 RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) { 2654 HandleScope scope(isolate); 2655 ASSERT(args.length() == 1); 2656 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0); 2657 2658 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop); 2659 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush); 2660 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift); 2661 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift); 2662 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice); 2663 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice); 2664 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat); 2665 2666 return *holder; 2667 } 2668 2669 2670 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsCallable) { 2671 SealHandleScope shs(isolate); 2672 ASSERT(args.length() == 1); 2673 CONVERT_ARG_CHECKED(Object, obj, 0); 2674 return isolate->heap()->ToBoolean(obj->IsCallable()); 2675 } 2676 2677 2678 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsClassicModeFunction) { 2679 SealHandleScope shs(isolate); 2680 ASSERT(args.length() == 1); 2681 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2682 if (!callable->IsJSFunction()) { 2683 HandleScope scope(isolate); 2684 bool threw = false; 2685 Handle<Object> delegate = Execution::TryGetFunctionDelegate( 2686 isolate, Handle<JSReceiver>(callable), &threw); 2687 if (threw) return Failure::Exception(); 2688 callable = JSFunction::cast(*delegate); 2689 } 2690 JSFunction* function = JSFunction::cast(callable); 2691 SharedFunctionInfo* shared = function->shared(); 2692 return isolate->heap()->ToBoolean(shared->is_classic_mode()); 2693 } 2694 2695 2696 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) { 2697 SealHandleScope shs(isolate); 2698 ASSERT(args.length() == 1); 2699 CONVERT_ARG_CHECKED(JSReceiver, callable, 0); 2700 2701 if (!callable->IsJSFunction()) { 2702 HandleScope scope(isolate); 2703 bool threw = false; 2704 Handle<Object> delegate = Execution::TryGetFunctionDelegate( 2705 isolate, Handle<JSReceiver>(callable), &threw); 2706 if (threw) return Failure::Exception(); 2707 callable = JSFunction::cast(*delegate); 2708 } 2709 JSFunction* function = JSFunction::cast(callable); 2710 2711 SharedFunctionInfo* shared = function->shared(); 2712 if (shared->native() || !shared->is_classic_mode()) { 2713 return isolate->heap()->undefined_value(); 2714 } 2715 // Returns undefined for strict or native functions, or 2716 // the associated global receiver for "normal" functions. 2717 2718 Context* native_context = 2719 function->context()->global_object()->native_context(); 2720 return native_context->global_object()->global_receiver(); 2721 } 2722 2723 2724 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) { 2725 HandleScope scope(isolate); 2726 ASSERT(args.length() == 4); 2727 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0); 2728 int index = args.smi_at(1); 2729 Handle<String> pattern = args.at<String>(2); 2730 Handle<String> flags = args.at<String>(3); 2731 2732 // Get the RegExp function from the context in the literals array. 2733 // This is the RegExp function from the context in which the 2734 // function was created. We do not use the RegExp function from the 2735 // current native context because this might be the RegExp function 2736 // from another context which we should not have access to. 2737 Handle<JSFunction> constructor = 2738 Handle<JSFunction>( 2739 JSFunction::NativeContextFromLiterals(*literals)->regexp_function()); 2740 // Compute the regular expression literal. 2741 bool has_pending_exception; 2742 Handle<Object> regexp = 2743 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags, 2744 &has_pending_exception); 2745 if (has_pending_exception) { 2746 ASSERT(isolate->has_pending_exception()); 2747 return Failure::Exception(); 2748 } 2749 literals->set(index, *regexp); 2750 return *regexp; 2751 } 2752 2753 2754 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) { 2755 SealHandleScope shs(isolate); 2756 ASSERT(args.length() == 1); 2757 2758 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2759 return f->shared()->name(); 2760 } 2761 2762 2763 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) { 2764 SealHandleScope shs(isolate); 2765 ASSERT(args.length() == 2); 2766 2767 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2768 CONVERT_ARG_CHECKED(String, name, 1); 2769 f->shared()->set_name(name); 2770 return isolate->heap()->undefined_value(); 2771 } 2772 2773 2774 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) { 2775 SealHandleScope shs(isolate); 2776 ASSERT(args.length() == 1); 2777 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2778 return isolate->heap()->ToBoolean( 2779 f->shared()->name_should_print_as_anonymous()); 2780 } 2781 2782 2783 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) { 2784 SealHandleScope shs(isolate); 2785 ASSERT(args.length() == 1); 2786 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2787 f->shared()->set_name_should_print_as_anonymous(true); 2788 return isolate->heap()->undefined_value(); 2789 } 2790 2791 2792 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsGenerator) { 2793 SealHandleScope shs(isolate); 2794 ASSERT(args.length() == 1); 2795 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2796 return isolate->heap()->ToBoolean(f->shared()->is_generator()); 2797 } 2798 2799 2800 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) { 2801 SealHandleScope shs(isolate); 2802 ASSERT(args.length() == 1); 2803 2804 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2805 f->RemovePrototype(); 2806 2807 return isolate->heap()->undefined_value(); 2808 } 2809 2810 2811 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) { 2812 HandleScope scope(isolate); 2813 ASSERT(args.length() == 1); 2814 2815 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2816 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate); 2817 if (!script->IsScript()) return isolate->heap()->undefined_value(); 2818 2819 return *GetScriptWrapper(Handle<Script>::cast(script)); 2820 } 2821 2822 2823 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) { 2824 HandleScope scope(isolate); 2825 ASSERT(args.length() == 1); 2826 2827 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); 2828 Handle<SharedFunctionInfo> shared(f->shared()); 2829 return *shared->GetSourceCode(); 2830 } 2831 2832 2833 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) { 2834 SealHandleScope shs(isolate); 2835 ASSERT(args.length() == 1); 2836 2837 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2838 int pos = fun->shared()->start_position(); 2839 return Smi::FromInt(pos); 2840 } 2841 2842 2843 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) { 2844 SealHandleScope shs(isolate); 2845 ASSERT(args.length() == 2); 2846 2847 CONVERT_ARG_CHECKED(Code, code, 0); 2848 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); 2849 2850 RUNTIME_ASSERT(0 <= offset && offset < code->Size()); 2851 2852 Address pc = code->address() + offset; 2853 return Smi::FromInt(code->SourcePosition(pc)); 2854 } 2855 2856 2857 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) { 2858 SealHandleScope shs(isolate); 2859 ASSERT(args.length() == 2); 2860 2861 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2862 CONVERT_ARG_CHECKED(String, name, 1); 2863 fun->SetInstanceClassName(name); 2864 return isolate->heap()->undefined_value(); 2865 } 2866 2867 2868 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) { 2869 SealHandleScope shs(isolate); 2870 ASSERT(args.length() == 2); 2871 2872 CONVERT_ARG_CHECKED(JSFunction, fun, 0); 2873 CONVERT_SMI_ARG_CHECKED(length, 1); 2874 fun->shared()->set_length(length); 2875 return isolate->heap()->undefined_value(); 2876 } 2877 2878 2879 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) { 2880 HandleScope scope(isolate); 2881 ASSERT(args.length() == 2); 2882 2883 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 2884 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); 2885 ASSERT(fun->should_have_prototype()); 2886 Accessors::FunctionSetPrototype(fun, value); 2887 return args[0]; // return TOS 2888 } 2889 2890 2891 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) { 2892 SealHandleScope shs(isolate); 2893 RUNTIME_ASSERT(args.length() == 1); 2894 CONVERT_ARG_CHECKED(JSFunction, function, 0); 2895 2896 String* name = isolate->heap()->prototype_string(); 2897 2898 if (function->HasFastProperties()) { 2899 // Construct a new field descriptor with updated attributes. 2900 DescriptorArray* instance_desc = function->map()->instance_descriptors(); 2901 2902 int index = instance_desc->SearchWithCache(name, function->map()); 2903 ASSERT(index != DescriptorArray::kNotFound); 2904 PropertyDetails details = instance_desc->GetDetails(index); 2905 2906 CallbacksDescriptor new_desc(name, 2907 instance_desc->GetValue(index), 2908 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY)); 2909 2910 // Create a new map featuring the new field descriptors array. 2911 Map* new_map; 2912 MaybeObject* maybe_map = 2913 function->map()->CopyReplaceDescriptor( 2914 instance_desc, &new_desc, index, OMIT_TRANSITION); 2915 if (!maybe_map->To(&new_map)) return maybe_map; 2916 2917 function->set_map(new_map); 2918 } else { // Dictionary properties. 2919 // Directly manipulate the property details. 2920 int entry = function->property_dictionary()->FindEntry(name); 2921 ASSERT(entry != NameDictionary::kNotFound); 2922 PropertyDetails details = function->property_dictionary()->DetailsAt(entry); 2923 PropertyDetails new_details( 2924 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY), 2925 details.type(), 2926 details.dictionary_index()); 2927 function->property_dictionary()->DetailsAtPut(entry, new_details); 2928 } 2929 return function; 2930 } 2931 2932 2933 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) { 2934 SealHandleScope shs(isolate); 2935 ASSERT(args.length() == 1); 2936 2937 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2938 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); 2939 } 2940 2941 2942 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) { 2943 SealHandleScope shs(isolate); 2944 ASSERT(args.length() == 1); 2945 2946 CONVERT_ARG_CHECKED(JSFunction, f, 0); 2947 return isolate->heap()->ToBoolean(f->IsBuiltin()); 2948 } 2949 2950 2951 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) { 2952 HandleScope scope(isolate); 2953 ASSERT(args.length() == 2); 2954 2955 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); 2956 Handle<Object> code = args.at<Object>(1); 2957 2958 if (code->IsNull()) return *target; 2959 RUNTIME_ASSERT(code->IsJSFunction()); 2960 Handle<JSFunction> source = Handle<JSFunction>::cast(code); 2961 Handle<SharedFunctionInfo> target_shared(target->shared()); 2962 Handle<SharedFunctionInfo> source_shared(source->shared()); 2963 2964 if (!JSFunction::EnsureCompiled(source, KEEP_EXCEPTION)) { 2965 return Failure::Exception(); 2966 } 2967 2968 // Mark both, the source and the target, as un-flushable because the 2969 // shared unoptimized code makes them impossible to enqueue in a list. 2970 ASSERT(target_shared->code()->gc_metadata() == NULL); 2971 ASSERT(source_shared->code()->gc_metadata() == NULL); 2972 target_shared->set_dont_flush(true); 2973 source_shared->set_dont_flush(true); 2974 2975 // Set the code, scope info, formal parameter count, and the length 2976 // of the target shared function info. 2977 target_shared->ReplaceCode(source_shared->code()); 2978 target_shared->set_scope_info(source_shared->scope_info()); 2979 target_shared->set_length(source_shared->length()); 2980 target_shared->set_formal_parameter_count( 2981 source_shared->formal_parameter_count()); 2982 target_shared->set_script(source_shared->script()); 2983 target_shared->set_start_position_and_type( 2984 source_shared->start_position_and_type()); 2985 target_shared->set_end_position(source_shared->end_position()); 2986 bool was_native = target_shared->native(); 2987 target_shared->set_compiler_hints(source_shared->compiler_hints()); 2988 target_shared->set_native(was_native); 2989 2990 // Set the code of the target function. 2991 target->ReplaceCode(source_shared->code()); 2992 ASSERT(target->next_function_link()->IsUndefined()); 2993 2994 // Make sure we get a fresh copy of the literal vector to avoid cross 2995 // context contamination. 2996 Handle<Context> context(source->context()); 2997 int number_of_literals = source->NumberOfLiterals(); 2998 Handle<FixedArray> literals = 2999 isolate->factory()->NewFixedArray(number_of_literals, TENURED); 3000 if (number_of_literals > 0) { 3001 literals->set(JSFunction::kLiteralNativeContextIndex, 3002 context->native_context()); 3003 } 3004 target->set_context(*context); 3005 target->set_literals(*literals); 3006 3007 if (isolate->logger()->is_logging_code_events() || 3008 isolate->cpu_profiler()->is_profiling()) { 3009 isolate->logger()->LogExistingFunction( 3010 source_shared, Handle<Code>(source_shared->code())); 3011 } 3012 3013 return *target; 3014 } 3015 3016 3017 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) { 3018 HandleScope scope(isolate); 3019 ASSERT(args.length() == 2); 3020 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 3021 CONVERT_SMI_ARG_CHECKED(num, 1); 3022 RUNTIME_ASSERT(num >= 0); 3023 // If objects constructed from this function exist then changing 3024 // 'estimated_nof_properties' is dangerous since the previous value might 3025 // have been compiled into the fast construct stub. Moreover, the inobject 3026 // slack tracking logic might have adjusted the previous value, so even 3027 // passing the same value is risky. 3028 if (!func->shared()->live_objects_may_exist()) { 3029 func->shared()->set_expected_nof_properties(num); 3030 if (func->has_initial_map()) { 3031 Handle<Map> new_initial_map = 3032 func->GetIsolate()->factory()->CopyMap( 3033 Handle<Map>(func->initial_map())); 3034 new_initial_map->set_unused_property_fields(num); 3035 func->set_initial_map(*new_initial_map); 3036 } 3037 } 3038 return isolate->heap()->undefined_value(); 3039 } 3040 3041 3042 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSGeneratorObject) { 3043 HandleScope scope(isolate); 3044 ASSERT(args.length() == 0); 3045 3046 JavaScriptFrameIterator it(isolate); 3047 JavaScriptFrame* frame = it.frame(); 3048 Handle<JSFunction> function(frame->function()); 3049 RUNTIME_ASSERT(function->shared()->is_generator()); 3050 3051 Handle<JSGeneratorObject> generator; 3052 if (frame->IsConstructor()) { 3053 generator = handle(JSGeneratorObject::cast(frame->receiver())); 3054 } else { 3055 generator = isolate->factory()->NewJSGeneratorObject(function); 3056 } 3057 generator->set_function(*function); 3058 generator->set_context(Context::cast(frame->context())); 3059 generator->set_receiver(frame->receiver()); 3060 generator->set_continuation(0); 3061 generator->set_operand_stack(isolate->heap()->empty_fixed_array()); 3062 generator->set_stack_handler_index(-1); 3063 3064 return *generator; 3065 } 3066 3067 3068 RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) { 3069 SealHandleScope shs(isolate); 3070 ASSERT(args.length() == 1); 3071 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); 3072 3073 JavaScriptFrameIterator stack_iterator(isolate); 3074 JavaScriptFrame* frame = stack_iterator.frame(); 3075 RUNTIME_ASSERT(frame->function()->shared()->is_generator()); 3076 ASSERT_EQ(frame->function(), generator_object->function()); 3077 3078 // The caller should have saved the context and continuation already. 3079 ASSERT_EQ(generator_object->context(), Context::cast(frame->context())); 3080 ASSERT_LT(0, generator_object->continuation()); 3081 3082 // We expect there to be at least two values on the operand stack: the return 3083 // value of the yield expression, and the argument to this runtime call. 3084 // Neither of those should be saved. 3085 int operands_count = frame->ComputeOperandsCount(); 3086 ASSERT_GE(operands_count, 2); 3087 operands_count -= 2; 3088 3089 if (operands_count == 0) { 3090 // Although it's semantically harmless to call this function with an 3091 // operands_count of zero, it is also unnecessary. 3092 ASSERT_EQ(generator_object->operand_stack(), 3093 isolate->heap()->empty_fixed_array()); 3094 ASSERT_EQ(generator_object->stack_handler_index(), -1); 3095 // If there are no operands on the stack, there shouldn't be a handler 3096 // active either. 3097 ASSERT(!frame->HasHandler()); 3098 } else { 3099 int stack_handler_index = -1; 3100 MaybeObject* alloc = isolate->heap()->AllocateFixedArray(operands_count); 3101 FixedArray* operand_stack; 3102 if (!alloc->To(&operand_stack)) return alloc; 3103 frame->SaveOperandStack(operand_stack, &stack_handler_index); 3104 generator_object->set_operand_stack(operand_stack); 3105 generator_object->set_stack_handler_index(stack_handler_index); 3106 } 3107 3108 return isolate->heap()->undefined_value(); 3109 } 3110 3111 3112 // Note that this function is the slow path for resuming generators. It is only 3113 // called if the suspended activation had operands on the stack, stack handlers 3114 // needing rewinding, or if the resume should throw an exception. The fast path 3115 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is 3116 // inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is 3117 // called in any case, as it needs to reconstruct the stack frame and make space 3118 // for arguments and operands. 3119 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) { 3120 SealHandleScope shs(isolate); 3121 ASSERT(args.length() == 3); 3122 CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0); 3123 CONVERT_ARG_CHECKED(Object, value, 1); 3124 CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2); 3125 JavaScriptFrameIterator stack_iterator(isolate); 3126 JavaScriptFrame* frame = stack_iterator.frame(); 3127 3128 ASSERT_EQ(frame->function(), generator_object->function()); 3129 ASSERT(frame->function()->is_compiled()); 3130 3131 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0); 3132 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0); 3133 3134 Address pc = generator_object->function()->code()->instruction_start(); 3135 int offset = generator_object->continuation(); 3136 ASSERT(offset > 0); 3137 frame->set_pc(pc + offset); 3138 generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting); 3139 3140 FixedArray* operand_stack = generator_object->operand_stack(); 3141 int operands_count = operand_stack->length(); 3142 if (operands_count != 0) { 3143 frame->RestoreOperandStack(operand_stack, 3144 generator_object->stack_handler_index()); 3145 generator_object->set_operand_stack(isolate->heap()->empty_fixed_array()); 3146 generator_object->set_stack_handler_index(-1); 3147 } 3148 3149 JSGeneratorObject::ResumeMode resume_mode = 3150 static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int); 3151 switch (resume_mode) { 3152 case JSGeneratorObject::NEXT: 3153 return value; 3154 case JSGeneratorObject::THROW: 3155 return isolate->Throw(value); 3156 } 3157 3158 UNREACHABLE(); 3159 return isolate->ThrowIllegalOperation(); 3160 } 3161 3162 3163 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowGeneratorStateError) { 3164 HandleScope scope(isolate); 3165 ASSERT(args.length() == 1); 3166 CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0); 3167 int continuation = generator->continuation(); 3168 const char* message = continuation == JSGeneratorObject::kGeneratorClosed ? 3169 "generator_finished" : "generator_running"; 3170 Vector< Handle<Object> > argv = HandleVector<Object>(NULL, 0); 3171 Handle<Object> error = isolate->factory()->NewError(message, argv); 3172 return isolate->Throw(*error); 3173 } 3174 3175 3176 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) { 3177 HandleScope scope(isolate); 3178 ASSERT(args.length() == 1); 3179 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 3180 Handle<Object> result = JSObject::Freeze(object); 3181 RETURN_IF_EMPTY_HANDLE(isolate, result); 3182 return *result; 3183 } 3184 3185 3186 MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate, 3187 Object* char_code) { 3188 if (char_code->IsNumber()) { 3189 return isolate->heap()->LookupSingleCharacterStringFromCode( 3190 NumberToUint32(char_code) & 0xffff); 3191 } 3192 return isolate->heap()->empty_string(); 3193 } 3194 3195 3196 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) { 3197 SealHandleScope shs(isolate); 3198 ASSERT(args.length() == 2); 3199 3200 CONVERT_ARG_CHECKED(String, subject, 0); 3201 CONVERT_NUMBER_CHECKED(uint32_t, i, Uint32, args[1]); 3202 3203 // Flatten the string. If someone wants to get a char at an index 3204 // in a cons string, it is likely that more indices will be 3205 // accessed. 3206 Object* flat; 3207 { MaybeObject* maybe_flat = subject->TryFlatten(); 3208 if (!maybe_flat->ToObject(&flat)) return maybe_flat; 3209 } 3210 subject = String::cast(flat); 3211 3212 if (i >= static_cast<uint32_t>(subject->length())) { 3213 return isolate->heap()->nan_value(); 3214 } 3215 3216 return Smi::FromInt(subject->Get(i)); 3217 } 3218 3219 3220 RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) { 3221 SealHandleScope shs(isolate); 3222 ASSERT(args.length() == 1); 3223 return CharFromCode(isolate, args[0]); 3224 } 3225 3226 3227 class FixedArrayBuilder { 3228 public: 3229 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity) 3230 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)), 3231 length_(0), 3232 has_non_smi_elements_(false) { 3233 // Require a non-zero initial size. Ensures that doubling the size to 3234 // extend the array will work. 3235 ASSERT(initial_capacity > 0); 3236 } 3237 3238 explicit FixedArrayBuilder(Handle<FixedArray> backing_store) 3239 : array_(backing_store), 3240 length_(0), 3241 has_non_smi_elements_(false) { 3242 // Require a non-zero initial size. Ensures that doubling the size to 3243 // extend the array will work. 3244 ASSERT(backing_store->length() > 0); 3245 } 3246 3247 bool HasCapacity(int elements) { 3248 int length = array_->length(); 3249 int required_length = length_ + elements; 3250 return (length >= required_length); 3251 } 3252 3253 void EnsureCapacity(int elements) { 3254 int length = array_->length(); 3255 int required_length = length_ + elements; 3256 if (length < required_length) { 3257 int new_length = length; 3258 do { 3259 new_length *= 2; 3260 } while (new_length < required_length); 3261 Handle<FixedArray> extended_array = 3262 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length); 3263 array_->CopyTo(0, *extended_array, 0, length_); 3264 array_ = extended_array; 3265 } 3266 } 3267 3268 void Add(Object* value) { 3269 ASSERT(!value->IsSmi()); 3270 ASSERT(length_ < capacity()); 3271 array_->set(length_, value); 3272 length_++; 3273 has_non_smi_elements_ = true; 3274 } 3275 3276 void Add(Smi* value) { 3277 ASSERT(value->IsSmi()); 3278 ASSERT(length_ < capacity()); 3279 array_->set(length_, value); 3280 length_++; 3281 } 3282 3283 Handle<FixedArray> array() { 3284 return array_; 3285 } 3286 3287 int length() { 3288 return length_; 3289 } 3290 3291 int capacity() { 3292 return array_->length(); 3293 } 3294 3295 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) { 3296 Factory* factory = target_array->GetIsolate()->factory(); 3297 factory->SetContent(target_array, array_); 3298 target_array->set_length(Smi::FromInt(length_)); 3299 return target_array; 3300 } 3301 3302 3303 private: 3304 Handle<FixedArray> array_; 3305 int length_; 3306 bool has_non_smi_elements_; 3307 }; 3308 3309 3310 // Forward declarations. 3311 const int kStringBuilderConcatHelperLengthBits = 11; 3312 const int kStringBuilderConcatHelperPositionBits = 19; 3313 3314 template <typename schar> 3315 static inline void StringBuilderConcatHelper(String*, 3316 schar*, 3317 FixedArray*, 3318 int); 3319 3320 typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits> 3321 StringBuilderSubstringLength; 3322 typedef BitField<int, 3323 kStringBuilderConcatHelperLengthBits, 3324 kStringBuilderConcatHelperPositionBits> 3325 StringBuilderSubstringPosition; 3326 3327 3328 class ReplacementStringBuilder { 3329 public: 3330 ReplacementStringBuilder(Heap* heap, 3331 Handle<String> subject, 3332 int estimated_part_count) 3333 : heap_(heap), 3334 array_builder_(heap->isolate(), estimated_part_count), 3335 subject_(subject), 3336 character_count_(0), 3337 is_ascii_(subject->IsOneByteRepresentation()) { 3338 // Require a non-zero initial size. Ensures that doubling the size to 3339 // extend the array will work. 3340 ASSERT(estimated_part_count > 0); 3341 } 3342 3343 static inline void AddSubjectSlice(FixedArrayBuilder* builder, 3344 int from, 3345 int to) { 3346 ASSERT(from >= 0); 3347 int length = to - from; 3348 ASSERT(length > 0); 3349 if (StringBuilderSubstringLength::is_valid(length) && 3350 StringBuilderSubstringPosition::is_valid(from)) { 3351 int encoded_slice = StringBuilderSubstringLength::encode(length) | 3352 StringBuilderSubstringPosition::encode(from); 3353 builder->Add(Smi::FromInt(encoded_slice)); 3354 } else { 3355 // Otherwise encode as two smis. 3356 builder->Add(Smi::FromInt(-length)); 3357 builder->Add(Smi::FromInt(from)); 3358 } 3359 } 3360 3361 3362 void EnsureCapacity(int elements) { 3363 array_builder_.EnsureCapacity(elements); 3364 } 3365 3366 3367 void AddSubjectSlice(int from, int to) { 3368 AddSubjectSlice(&array_builder_, from, to); 3369 IncrementCharacterCount(to - from); 3370 } 3371 3372 3373 void AddString(Handle<String> string) { 3374 int length = string->length(); 3375 ASSERT(length > 0); 3376 AddElement(*string); 3377 if (!string->IsOneByteRepresentation()) { 3378 is_ascii_ = false; 3379 } 3380 IncrementCharacterCount(length); 3381 } 3382 3383 3384 Handle<String> ToString() { 3385 if (array_builder_.length() == 0) { 3386 return heap_->isolate()->factory()->empty_string(); 3387 } 3388 3389 Handle<String> joined_string; 3390 if (is_ascii_) { 3391 Handle<SeqOneByteString> seq = NewRawOneByteString(character_count_); 3392 DisallowHeapAllocation no_gc; 3393 uint8_t* char_buffer = seq->GetChars(); 3394 StringBuilderConcatHelper(*subject_, 3395 char_buffer, 3396 *array_builder_.array(), 3397 array_builder_.length()); 3398 joined_string = Handle<String>::cast(seq); 3399 } else { 3400 // Non-ASCII. 3401 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_); 3402 DisallowHeapAllocation no_gc; 3403 uc16* char_buffer = seq->GetChars(); 3404 StringBuilderConcatHelper(*subject_, 3405 char_buffer, 3406 *array_builder_.array(), 3407 array_builder_.length()); 3408 joined_string = Handle<String>::cast(seq); 3409 } 3410 return joined_string; 3411 } 3412 3413 3414 void IncrementCharacterCount(int by) { 3415 if (character_count_ > String::kMaxLength - by) { 3416 V8::FatalProcessOutOfMemory("String.replace result too large."); 3417 } 3418 character_count_ += by; 3419 } 3420 3421 private: 3422 Handle<SeqOneByteString> NewRawOneByteString(int length) { 3423 return heap_->isolate()->factory()->NewRawOneByteString(length); 3424 } 3425 3426 3427 Handle<SeqTwoByteString> NewRawTwoByteString(int length) { 3428 return heap_->isolate()->factory()->NewRawTwoByteString(length); 3429 } 3430 3431 3432 void AddElement(Object* element) { 3433 ASSERT(element->IsSmi() || element->IsString()); 3434 ASSERT(array_builder_.capacity() > array_builder_.length()); 3435 array_builder_.Add(element); 3436 } 3437 3438 Heap* heap_; 3439 FixedArrayBuilder array_builder_; 3440 Handle<String> subject_; 3441 int character_count_; 3442 bool is_ascii_; 3443 }; 3444 3445 3446 class CompiledReplacement { 3447 public: 3448 explicit CompiledReplacement(Zone* zone) 3449 : parts_(1, zone), replacement_substrings_(0, zone), zone_(zone) {} 3450 3451 // Return whether the replacement is simple. 3452 bool Compile(Handle<String> replacement, 3453 int capture_count, 3454 int subject_length); 3455 3456 // Use Apply only if Compile returned false. 3457 void Apply(ReplacementStringBuilder* builder, 3458 int match_from, 3459 int match_to, 3460 int32_t* match); 3461 3462 // Number of distinct parts of the replacement pattern. 3463 int parts() { 3464 return parts_.length(); 3465 } 3466 3467 Zone* zone() const { return zone_; } 3468 3469 private: 3470 enum PartType { 3471 SUBJECT_PREFIX = 1, 3472 SUBJECT_SUFFIX, 3473 SUBJECT_CAPTURE, 3474 REPLACEMENT_SUBSTRING, 3475 REPLACEMENT_STRING, 3476 3477 NUMBER_OF_PART_TYPES 3478 }; 3479 3480 struct ReplacementPart { 3481 static inline ReplacementPart SubjectMatch() { 3482 return ReplacementPart(SUBJECT_CAPTURE, 0); 3483 } 3484 static inline ReplacementPart SubjectCapture(int capture_index) { 3485 return ReplacementPart(SUBJECT_CAPTURE, capture_index); 3486 } 3487 static inline ReplacementPart SubjectPrefix() { 3488 return ReplacementPart(SUBJECT_PREFIX, 0); 3489 } 3490 static inline ReplacementPart SubjectSuffix(int subject_length) { 3491 return ReplacementPart(SUBJECT_SUFFIX, subject_length); 3492 } 3493 static inline ReplacementPart ReplacementString() { 3494 return ReplacementPart(REPLACEMENT_STRING, 0); 3495 } 3496 static inline ReplacementPart ReplacementSubString(int from, int to) { 3497 ASSERT(from >= 0); 3498 ASSERT(to > from); 3499 return ReplacementPart(-from, to); 3500 } 3501 3502 // If tag <= 0 then it is the negation of a start index of a substring of 3503 // the replacement pattern, otherwise it's a value from PartType. 3504 ReplacementPart(int tag, int data) 3505 : tag(tag), data(data) { 3506 // Must be non-positive or a PartType value. 3507 ASSERT(tag < NUMBER_OF_PART_TYPES); 3508 } 3509 // Either a value of PartType or a non-positive number that is 3510 // the negation of an index into the replacement string. 3511 int tag; 3512 // The data value's interpretation depends on the value of tag: 3513 // tag == SUBJECT_PREFIX || 3514 // tag == SUBJECT_SUFFIX: data is unused. 3515 // tag == SUBJECT_CAPTURE: data is the number of the capture. 3516 // tag == REPLACEMENT_SUBSTRING || 3517 // tag == REPLACEMENT_STRING: data is index into array of substrings 3518 // of the replacement string. 3519 // tag <= 0: Temporary representation of the substring of the replacement 3520 // string ranging over -tag .. data. 3521 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the 3522 // substring objects. 3523 int data; 3524 }; 3525 3526 template<typename Char> 3527 bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts, 3528 Vector<Char> characters, 3529 int capture_count, 3530 int subject_length, 3531 Zone* zone) { 3532 int length = characters.length(); 3533 int last = 0; 3534 for (int i = 0; i < length; i++) { 3535 Char c = characters[i]; 3536 if (c == '$') { 3537 int next_index = i + 1; 3538 if (next_index == length) { // No next character! 3539 break; 3540 } 3541 Char c2 = characters[next_index]; 3542 switch (c2) { 3543 case '$': 3544 if (i > last) { 3545 // There is a substring before. Include the first "$". 3546 parts->Add(ReplacementPart::ReplacementSubString(last, next_index), 3547 zone); 3548 last = next_index + 1; // Continue after the second "$". 3549 } else { 3550 // Let the next substring start with the second "$". 3551 last = next_index; 3552 } 3553 i = next_index; 3554 break; 3555 case '`': 3556 if (i > last) { 3557 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3558 } 3559 parts->Add(ReplacementPart::SubjectPrefix(), zone); 3560 i = next_index; 3561 last = i + 1; 3562 break; 3563 case '\'': 3564 if (i > last) { 3565 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3566 } 3567 parts->Add(ReplacementPart::SubjectSuffix(subject_length), zone); 3568 i = next_index; 3569 last = i + 1; 3570 break; 3571 case '&': 3572 if (i > last) { 3573 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3574 } 3575 parts->Add(ReplacementPart::SubjectMatch(), zone); 3576 i = next_index; 3577 last = i + 1; 3578 break; 3579 case '0': 3580 case '1': 3581 case '2': 3582 case '3': 3583 case '4': 3584 case '5': 3585 case '6': 3586 case '7': 3587 case '8': 3588 case '9': { 3589 int capture_ref = c2 - '0'; 3590 if (capture_ref > capture_count) { 3591 i = next_index; 3592 continue; 3593 } 3594 int second_digit_index = next_index + 1; 3595 if (second_digit_index < length) { 3596 // Peek ahead to see if we have two digits. 3597 Char c3 = characters[second_digit_index]; 3598 if ('0' <= c3 && c3 <= '9') { // Double digits. 3599 int double_digit_ref = capture_ref * 10 + c3 - '0'; 3600 if (double_digit_ref <= capture_count) { 3601 next_index = second_digit_index; 3602 capture_ref = double_digit_ref; 3603 } 3604 } 3605 } 3606 if (capture_ref > 0) { 3607 if (i > last) { 3608 parts->Add(ReplacementPart::ReplacementSubString(last, i), zone); 3609 } 3610 ASSERT(capture_ref <= capture_count); 3611 parts->Add(ReplacementPart::SubjectCapture(capture_ref), zone); 3612 last = next_index + 1; 3613 } 3614 i = next_index; 3615 break; 3616 } 3617 default: 3618 i = next_index; 3619 break; 3620 } 3621 } 3622 } 3623 if (length > last) { 3624 if (last == 0) { 3625 // Replacement is simple. Do not use Apply to do the replacement. 3626 return true; 3627 } else { 3628 parts->Add(ReplacementPart::ReplacementSubString(last, length), zone); 3629 } 3630 } 3631 return false; 3632 } 3633 3634 ZoneList<ReplacementPart> parts_; 3635 ZoneList<Handle<String> > replacement_substrings_; 3636 Zone* zone_; 3637 }; 3638 3639 3640 bool CompiledReplacement::Compile(Handle<String> replacement, 3641 int capture_count, 3642 int subject_length) { 3643 { 3644 DisallowHeapAllocation no_gc; 3645 String::FlatContent content = replacement->GetFlatContent(); 3646 ASSERT(content.IsFlat()); 3647 bool simple = false; 3648 if (content.IsAscii()) { 3649 simple = ParseReplacementPattern(&parts_, 3650 content.ToOneByteVector(), 3651 capture_count, 3652 subject_length, 3653 zone()); 3654 } else { 3655 ASSERT(content.IsTwoByte()); 3656 simple = ParseReplacementPattern(&parts_, 3657 content.ToUC16Vector(), 3658 capture_count, 3659 subject_length, 3660 zone()); 3661 } 3662 if (simple) return true; 3663 } 3664 3665 Isolate* isolate = replacement->GetIsolate(); 3666 // Find substrings of replacement string and create them as String objects. 3667 int substring_index = 0; 3668 for (int i = 0, n = parts_.length(); i < n; i++) { 3669 int tag = parts_[i].tag; 3670 if (tag <= 0) { // A replacement string slice. 3671 int from = -tag; 3672 int to = parts_[i].data; 3673 replacement_substrings_.Add( 3674 isolate->factory()->NewSubString(replacement, from, to), zone()); 3675 parts_[i].tag = REPLACEMENT_SUBSTRING; 3676 parts_[i].data = substring_index; 3677 substring_index++; 3678 } else if (tag == REPLACEMENT_STRING) { 3679 replacement_substrings_.Add(replacement, zone()); 3680 parts_[i].data = substring_index; 3681 substring_index++; 3682 } 3683 } 3684 return false; 3685 } 3686 3687 3688 void CompiledReplacement::Apply(ReplacementStringBuilder* builder, 3689 int match_from, 3690 int match_to, 3691 int32_t* match) { 3692 ASSERT_LT(0, parts_.length()); 3693 for (int i = 0, n = parts_.length(); i < n; i++) { 3694 ReplacementPart part = parts_[i]; 3695 switch (part.tag) { 3696 case SUBJECT_PREFIX: 3697 if (match_from > 0) builder->AddSubjectSlice(0, match_from); 3698 break; 3699 case SUBJECT_SUFFIX: { 3700 int subject_length = part.data; 3701 if (match_to < subject_length) { 3702 builder->AddSubjectSlice(match_to, subject_length); 3703 } 3704 break; 3705 } 3706 case SUBJECT_CAPTURE: { 3707 int capture = part.data; 3708 int from = match[capture * 2]; 3709 int to = match[capture * 2 + 1]; 3710 if (from >= 0 && to > from) { 3711 builder->AddSubjectSlice(from, to); 3712 } 3713 break; 3714 } 3715 case REPLACEMENT_SUBSTRING: 3716 case REPLACEMENT_STRING: 3717 builder->AddString(replacement_substrings_[part.data]); 3718 break; 3719 default: 3720 UNREACHABLE(); 3721 } 3722 } 3723 } 3724 3725 3726 void FindAsciiStringIndices(Vector<const uint8_t> subject, 3727 char pattern, 3728 ZoneList<int>* indices, 3729 unsigned int limit, 3730 Zone* zone) { 3731 ASSERT(limit > 0); 3732 // Collect indices of pattern in subject using memchr. 3733 // Stop after finding at most limit values. 3734 const uint8_t* subject_start = subject.start(); 3735 const uint8_t* subject_end = subject_start + subject.length(); 3736 const uint8_t* pos = subject_start; 3737 while (limit > 0) { 3738 pos = reinterpret_cast<const uint8_t*>( 3739 memchr(pos, pattern, subject_end - pos)); 3740 if (pos == NULL) return; 3741 indices->Add(static_cast<int>(pos - subject_start), zone); 3742 pos++; 3743 limit--; 3744 } 3745 } 3746 3747 3748 void FindTwoByteStringIndices(const Vector<const uc16> subject, 3749 uc16 pattern, 3750 ZoneList<int>* indices, 3751 unsigned int limit, 3752 Zone* zone) { 3753 ASSERT(limit > 0); 3754 const uc16* subject_start = subject.start(); 3755 const uc16* subject_end = subject_start + subject.length(); 3756 for (const uc16* pos = subject_start; pos < subject_end && limit > 0; pos++) { 3757 if (*pos == pattern) { 3758 indices->Add(static_cast<int>(pos - subject_start), zone); 3759 limit--; 3760 } 3761 } 3762 } 3763 3764 3765 template <typename SubjectChar, typename PatternChar> 3766 void FindStringIndices(Isolate* isolate, 3767 Vector<const SubjectChar> subject, 3768 Vector<const PatternChar> pattern, 3769 ZoneList<int>* indices, 3770 unsigned int limit, 3771 Zone* zone) { 3772 ASSERT(limit > 0); 3773 // Collect indices of pattern in subject. 3774 // Stop after finding at most limit values. 3775 int pattern_length = pattern.length(); 3776 int index = 0; 3777 StringSearch<PatternChar, SubjectChar> search(isolate, pattern); 3778 while (limit > 0) { 3779 index = search.Search(subject, index); 3780 if (index < 0) return; 3781 indices->Add(index, zone); 3782 index += pattern_length; 3783 limit--; 3784 } 3785 } 3786 3787 3788 void FindStringIndicesDispatch(Isolate* isolate, 3789 String* subject, 3790 String* pattern, 3791 ZoneList<int>* indices, 3792 unsigned int limit, 3793 Zone* zone) { 3794 { 3795 DisallowHeapAllocation no_gc; 3796 String::FlatContent subject_content = subject->GetFlatContent(); 3797 String::FlatContent pattern_content = pattern->GetFlatContent(); 3798 ASSERT(subject_content.IsFlat()); 3799 ASSERT(pattern_content.IsFlat()); 3800 if (subject_content.IsAscii()) { 3801 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector(); 3802 if (pattern_content.IsAscii()) { 3803 Vector<const uint8_t> pattern_vector = 3804 pattern_content.ToOneByteVector(); 3805 if (pattern_vector.length() == 1) { 3806 FindAsciiStringIndices(subject_vector, 3807 pattern_vector[0], 3808 indices, 3809 limit, 3810 zone); 3811 } else { 3812 FindStringIndices(isolate, 3813 subject_vector, 3814 pattern_vector, 3815 indices, 3816 limit, 3817 zone); 3818 } 3819 } else { 3820 FindStringIndices(isolate, 3821 subject_vector, 3822 pattern_content.ToUC16Vector(), 3823 indices, 3824 limit, 3825 zone); 3826 } 3827 } else { 3828 Vector<const uc16> subject_vector = subject_content.ToUC16Vector(); 3829 if (pattern_content.IsAscii()) { 3830 Vector<const uint8_t> pattern_vector = 3831 pattern_content.ToOneByteVector(); 3832 if (pattern_vector.length() == 1) { 3833 FindTwoByteStringIndices(subject_vector, 3834 pattern_vector[0], 3835 indices, 3836 limit, 3837 zone); 3838 } else { 3839 FindStringIndices(isolate, 3840 subject_vector, 3841 pattern_vector, 3842 indices, 3843 limit, 3844 zone); 3845 } 3846 } else { 3847 Vector<const uc16> pattern_vector = pattern_content.ToUC16Vector(); 3848 if (pattern_vector.length() == 1) { 3849 FindTwoByteStringIndices(subject_vector, 3850 pattern_vector[0], 3851 indices, 3852 limit, 3853 zone); 3854 } else { 3855 FindStringIndices(isolate, 3856 subject_vector, 3857 pattern_vector, 3858 indices, 3859 limit, 3860 zone); 3861 } 3862 } 3863 } 3864 } 3865 } 3866 3867 3868 template<typename ResultSeqString> 3869 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString( 3870 Isolate* isolate, 3871 Handle<String> subject, 3872 Handle<JSRegExp> pattern_regexp, 3873 Handle<String> replacement, 3874 Handle<JSArray> last_match_info) { 3875 ASSERT(subject->IsFlat()); 3876 ASSERT(replacement->IsFlat()); 3877 3878 ZoneScope zone_scope(isolate->runtime_zone()); 3879 ZoneList<int> indices(8, zone_scope.zone()); 3880 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag()); 3881 String* pattern = 3882 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex)); 3883 int subject_len = subject->length(); 3884 int pattern_len = pattern->length(); 3885 int replacement_len = replacement->length(); 3886 3887 FindStringIndicesDispatch( 3888 isolate, *subject, pattern, &indices, 0xffffffff, zone_scope.zone()); 3889 3890 int matches = indices.length(); 3891 if (matches == 0) return *subject; 3892 3893 // Detect integer overflow. 3894 int64_t result_len_64 = 3895 (static_cast<int64_t>(replacement_len) - 3896 static_cast<int64_t>(pattern_len)) * 3897 static_cast<int64_t>(matches) + 3898 static_cast<int64_t>(subject_len); 3899 if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11); 3900 int result_len = static_cast<int>(result_len_64); 3901 3902 int subject_pos = 0; 3903 int result_pos = 0; 3904 3905 Handle<ResultSeqString> result; 3906 if (ResultSeqString::kHasAsciiEncoding) { 3907 result = Handle<ResultSeqString>::cast( 3908 isolate->factory()->NewRawOneByteString(result_len)); 3909 } else { 3910 result = Handle<ResultSeqString>::cast( 3911 isolate->factory()->NewRawTwoByteString(result_len)); 3912 } 3913 3914 for (int i = 0; i < matches; i++) { 3915 // Copy non-matched subject content. 3916 if (subject_pos < indices.at(i)) { 3917 String::WriteToFlat(*subject, 3918 result->GetChars() + result_pos, 3919 subject_pos, 3920 indices.at(i)); 3921 result_pos += indices.at(i) - subject_pos; 3922 } 3923 3924 // Replace match. 3925 if (replacement_len > 0) { 3926 String::WriteToFlat(*replacement, 3927 result->GetChars() + result_pos, 3928 0, 3929 replacement_len); 3930 result_pos += replacement_len; 3931 } 3932 3933 subject_pos = indices.at(i) + pattern_len; 3934 } 3935 // Add remaining subject content at the end. 3936 if (subject_pos < subject_len) { 3937 String::WriteToFlat(*subject, 3938 result->GetChars() + result_pos, 3939 subject_pos, 3940 subject_len); 3941 } 3942 3943 int32_t match_indices[] = { indices.at(matches - 1), 3944 indices.at(matches - 1) + pattern_len }; 3945 RegExpImpl::SetLastMatchInfo(last_match_info, subject, 0, match_indices); 3946 3947 return *result; 3948 } 3949 3950 3951 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithString( 3952 Isolate* isolate, 3953 Handle<String> subject, 3954 Handle<JSRegExp> regexp, 3955 Handle<String> replacement, 3956 Handle<JSArray> last_match_info) { 3957 ASSERT(subject->IsFlat()); 3958 ASSERT(replacement->IsFlat()); 3959 3960 int capture_count = regexp->CaptureCount(); 3961 int subject_length = subject->length(); 3962 3963 // CompiledReplacement uses zone allocation. 3964 ZoneScope zone_scope(isolate->runtime_zone()); 3965 CompiledReplacement compiled_replacement(zone_scope.zone()); 3966 bool simple_replace = compiled_replacement.Compile(replacement, 3967 capture_count, 3968 subject_length); 3969 3970 // Shortcut for simple non-regexp global replacements 3971 if (regexp->TypeTag() == JSRegExp::ATOM && simple_replace) { 3972 if (subject->HasOnlyOneByteChars() && 3973 replacement->HasOnlyOneByteChars()) { 3974 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 3975 isolate, subject, regexp, replacement, last_match_info); 3976 } else { 3977 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 3978 isolate, subject, regexp, replacement, last_match_info); 3979 } 3980 } 3981 3982 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 3983 if (global_cache.HasException()) return Failure::Exception(); 3984 3985 int32_t* current_match = global_cache.FetchNext(); 3986 if (current_match == NULL) { 3987 if (global_cache.HasException()) return Failure::Exception(); 3988 return *subject; 3989 } 3990 3991 // Guessing the number of parts that the final result string is built 3992 // from. Global regexps can match any number of times, so we guess 3993 // conservatively. 3994 int expected_parts = (compiled_replacement.parts() + 1) * 4 + 1; 3995 ReplacementStringBuilder builder(isolate->heap(), 3996 subject, 3997 expected_parts); 3998 3999 // Number of parts added by compiled replacement plus preceeding 4000 // string and possibly suffix after last match. It is possible for 4001 // all components to use two elements when encoded as two smis. 4002 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2); 4003 4004 int prev = 0; 4005 4006 do { 4007 builder.EnsureCapacity(parts_added_per_loop); 4008 4009 int start = current_match[0]; 4010 int end = current_match[1]; 4011 4012 if (prev < start) { 4013 builder.AddSubjectSlice(prev, start); 4014 } 4015 4016 if (simple_replace) { 4017 builder.AddString(replacement); 4018 } else { 4019 compiled_replacement.Apply(&builder, 4020 start, 4021 end, 4022 current_match); 4023 } 4024 prev = end; 4025 4026 current_match = global_cache.FetchNext(); 4027 } while (current_match != NULL); 4028 4029 if (global_cache.HasException()) return Failure::Exception(); 4030 4031 if (prev < subject_length) { 4032 builder.EnsureCapacity(2); 4033 builder.AddSubjectSlice(prev, subject_length); 4034 } 4035 4036 RegExpImpl::SetLastMatchInfo(last_match_info, 4037 subject, 4038 capture_count, 4039 global_cache.LastSuccessfulMatch()); 4040 4041 return *(builder.ToString()); 4042 } 4043 4044 4045 template <typename ResultSeqString> 4046 MUST_USE_RESULT static MaybeObject* StringReplaceGlobalRegExpWithEmptyString( 4047 Isolate* isolate, 4048 Handle<String> subject, 4049 Handle<JSRegExp> regexp, 4050 Handle<JSArray> last_match_info) { 4051 ASSERT(subject->IsFlat()); 4052 4053 // Shortcut for simple non-regexp global replacements 4054 if (regexp->TypeTag() == JSRegExp::ATOM) { 4055 Handle<String> empty_string = isolate->factory()->empty_string(); 4056 if (subject->IsOneByteRepresentation()) { 4057 return StringReplaceGlobalAtomRegExpWithString<SeqOneByteString>( 4058 isolate, subject, regexp, empty_string, last_match_info); 4059 } else { 4060 return StringReplaceGlobalAtomRegExpWithString<SeqTwoByteString>( 4061 isolate, subject, regexp, empty_string, last_match_info); 4062 } 4063 } 4064 4065 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4066 if (global_cache.HasException()) return Failure::Exception(); 4067 4068 int32_t* current_match = global_cache.FetchNext(); 4069 if (current_match == NULL) { 4070 if (global_cache.HasException()) return Failure::Exception(); 4071 return *subject; 4072 } 4073 4074 int start = current_match[0]; 4075 int end = current_match[1]; 4076 int capture_count = regexp->CaptureCount(); 4077 int subject_length = subject->length(); 4078 4079 int new_length = subject_length - (end - start); 4080 if (new_length == 0) return isolate->heap()->empty_string(); 4081 4082 Handle<ResultSeqString> answer; 4083 if (ResultSeqString::kHasAsciiEncoding) { 4084 answer = Handle<ResultSeqString>::cast( 4085 isolate->factory()->NewRawOneByteString(new_length)); 4086 } else { 4087 answer = Handle<ResultSeqString>::cast( 4088 isolate->factory()->NewRawTwoByteString(new_length)); 4089 } 4090 4091 int prev = 0; 4092 int position = 0; 4093 4094 do { 4095 start = current_match[0]; 4096 end = current_match[1]; 4097 if (prev < start) { 4098 // Add substring subject[prev;start] to answer string. 4099 String::WriteToFlat(*subject, answer->GetChars() + position, prev, start); 4100 position += start - prev; 4101 } 4102 prev = end; 4103 4104 current_match = global_cache.FetchNext(); 4105 } while (current_match != NULL); 4106 4107 if (global_cache.HasException()) return Failure::Exception(); 4108 4109 RegExpImpl::SetLastMatchInfo(last_match_info, 4110 subject, 4111 capture_count, 4112 global_cache.LastSuccessfulMatch()); 4113 4114 if (prev < subject_length) { 4115 // Add substring subject[prev;length] to answer string. 4116 String::WriteToFlat( 4117 *subject, answer->GetChars() + position, prev, subject_length); 4118 position += subject_length - prev; 4119 } 4120 4121 if (position == 0) return isolate->heap()->empty_string(); 4122 4123 // Shorten string and fill 4124 int string_size = ResultSeqString::SizeFor(position); 4125 int allocated_string_size = ResultSeqString::SizeFor(new_length); 4126 int delta = allocated_string_size - string_size; 4127 4128 answer->set_length(position); 4129 if (delta == 0) return *answer; 4130 4131 Address end_of_string = answer->address() + string_size; 4132 isolate->heap()->CreateFillerObjectAt(end_of_string, delta); 4133 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) { 4134 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta); 4135 } 4136 4137 return *answer; 4138 } 4139 4140 4141 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceGlobalRegExpWithString) { 4142 HandleScope scope(isolate); 4143 ASSERT(args.length() == 4); 4144 4145 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4146 CONVERT_ARG_HANDLE_CHECKED(String, replacement, 2); 4147 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4148 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3); 4149 4150 ASSERT(regexp->GetFlags().is_global()); 4151 4152 if (!subject->IsFlat()) subject = FlattenGetString(subject); 4153 4154 if (replacement->length() == 0) { 4155 if (subject->HasOnlyOneByteChars()) { 4156 return StringReplaceGlobalRegExpWithEmptyString<SeqOneByteString>( 4157 isolate, subject, regexp, last_match_info); 4158 } else { 4159 return StringReplaceGlobalRegExpWithEmptyString<SeqTwoByteString>( 4160 isolate, subject, regexp, last_match_info); 4161 } 4162 } 4163 4164 if (!replacement->IsFlat()) replacement = FlattenGetString(replacement); 4165 4166 return StringReplaceGlobalRegExpWithString( 4167 isolate, subject, regexp, replacement, last_match_info); 4168 } 4169 4170 4171 Handle<String> StringReplaceOneCharWithString(Isolate* isolate, 4172 Handle<String> subject, 4173 Handle<String> search, 4174 Handle<String> replace, 4175 bool* found, 4176 int recursion_limit) { 4177 if (recursion_limit == 0) return Handle<String>::null(); 4178 if (subject->IsConsString()) { 4179 ConsString* cons = ConsString::cast(*subject); 4180 Handle<String> first = Handle<String>(cons->first()); 4181 Handle<String> second = Handle<String>(cons->second()); 4182 Handle<String> new_first = 4183 StringReplaceOneCharWithString(isolate, 4184 first, 4185 search, 4186 replace, 4187 found, 4188 recursion_limit - 1); 4189 if (*found) return isolate->factory()->NewConsString(new_first, second); 4190 if (new_first.is_null()) return new_first; 4191 4192 Handle<String> new_second = 4193 StringReplaceOneCharWithString(isolate, 4194 second, 4195 search, 4196 replace, 4197 found, 4198 recursion_limit - 1); 4199 if (*found) return isolate->factory()->NewConsString(first, new_second); 4200 if (new_second.is_null()) return new_second; 4201 4202 return subject; 4203 } else { 4204 int index = Runtime::StringMatch(isolate, subject, search, 0); 4205 if (index == -1) return subject; 4206 *found = true; 4207 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index); 4208 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace); 4209 Handle<String> second = 4210 isolate->factory()->NewSubString(subject, index + 1, subject->length()); 4211 return isolate->factory()->NewConsString(cons1, second); 4212 } 4213 } 4214 4215 4216 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) { 4217 HandleScope scope(isolate); 4218 ASSERT(args.length() == 3); 4219 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4220 CONVERT_ARG_HANDLE_CHECKED(String, search, 1); 4221 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2); 4222 4223 // If the cons string tree is too deep, we simply abort the recursion and 4224 // retry with a flattened subject string. 4225 const int kRecursionLimit = 0x1000; 4226 bool found = false; 4227 Handle<String> result = StringReplaceOneCharWithString(isolate, 4228 subject, 4229 search, 4230 replace, 4231 &found, 4232 kRecursionLimit); 4233 if (!result.is_null()) return *result; 4234 return *StringReplaceOneCharWithString(isolate, 4235 FlattenGetString(subject), 4236 search, 4237 replace, 4238 &found, 4239 kRecursionLimit); 4240 } 4241 4242 4243 // Perform string match of pattern on subject, starting at start index. 4244 // Caller must ensure that 0 <= start_index <= sub->length(), 4245 // and should check that pat->length() + start_index <= sub->length(). 4246 int Runtime::StringMatch(Isolate* isolate, 4247 Handle<String> sub, 4248 Handle<String> pat, 4249 int start_index) { 4250 ASSERT(0 <= start_index); 4251 ASSERT(start_index <= sub->length()); 4252 4253 int pattern_length = pat->length(); 4254 if (pattern_length == 0) return start_index; 4255 4256 int subject_length = sub->length(); 4257 if (start_index + pattern_length > subject_length) return -1; 4258 4259 if (!sub->IsFlat()) FlattenString(sub); 4260 if (!pat->IsFlat()) FlattenString(pat); 4261 4262 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4263 // Extract flattened substrings of cons strings before determining asciiness. 4264 String::FlatContent seq_sub = sub->GetFlatContent(); 4265 String::FlatContent seq_pat = pat->GetFlatContent(); 4266 4267 // dispatch on type of strings 4268 if (seq_pat.IsAscii()) { 4269 Vector<const uint8_t> pat_vector = seq_pat.ToOneByteVector(); 4270 if (seq_sub.IsAscii()) { 4271 return SearchString(isolate, 4272 seq_sub.ToOneByteVector(), 4273 pat_vector, 4274 start_index); 4275 } 4276 return SearchString(isolate, 4277 seq_sub.ToUC16Vector(), 4278 pat_vector, 4279 start_index); 4280 } 4281 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector(); 4282 if (seq_sub.IsAscii()) { 4283 return SearchString(isolate, 4284 seq_sub.ToOneByteVector(), 4285 pat_vector, 4286 start_index); 4287 } 4288 return SearchString(isolate, 4289 seq_sub.ToUC16Vector(), 4290 pat_vector, 4291 start_index); 4292 } 4293 4294 4295 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) { 4296 HandleScope scope(isolate); 4297 ASSERT(args.length() == 3); 4298 4299 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4300 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4301 4302 Object* index = args[2]; 4303 uint32_t start_index; 4304 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4305 4306 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length())); 4307 int position = 4308 Runtime::StringMatch(isolate, sub, pat, start_index); 4309 return Smi::FromInt(position); 4310 } 4311 4312 4313 template <typename schar, typename pchar> 4314 static int StringMatchBackwards(Vector<const schar> subject, 4315 Vector<const pchar> pattern, 4316 int idx) { 4317 int pattern_length = pattern.length(); 4318 ASSERT(pattern_length >= 1); 4319 ASSERT(idx + pattern_length <= subject.length()); 4320 4321 if (sizeof(schar) == 1 && sizeof(pchar) > 1) { 4322 for (int i = 0; i < pattern_length; i++) { 4323 uc16 c = pattern[i]; 4324 if (c > String::kMaxOneByteCharCode) { 4325 return -1; 4326 } 4327 } 4328 } 4329 4330 pchar pattern_first_char = pattern[0]; 4331 for (int i = idx; i >= 0; i--) { 4332 if (subject[i] != pattern_first_char) continue; 4333 int j = 1; 4334 while (j < pattern_length) { 4335 if (pattern[j] != subject[i+j]) { 4336 break; 4337 } 4338 j++; 4339 } 4340 if (j == pattern_length) { 4341 return i; 4342 } 4343 } 4344 return -1; 4345 } 4346 4347 4348 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) { 4349 HandleScope scope(isolate); 4350 ASSERT(args.length() == 3); 4351 4352 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0); 4353 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1); 4354 4355 Object* index = args[2]; 4356 uint32_t start_index; 4357 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1); 4358 4359 uint32_t pat_length = pat->length(); 4360 uint32_t sub_length = sub->length(); 4361 4362 if (start_index + pat_length > sub_length) { 4363 start_index = sub_length - pat_length; 4364 } 4365 4366 if (pat_length == 0) { 4367 return Smi::FromInt(start_index); 4368 } 4369 4370 if (!sub->IsFlat()) FlattenString(sub); 4371 if (!pat->IsFlat()) FlattenString(pat); 4372 4373 int position = -1; 4374 DisallowHeapAllocation no_gc; // ensure vectors stay valid 4375 4376 String::FlatContent sub_content = sub->GetFlatContent(); 4377 String::FlatContent pat_content = pat->GetFlatContent(); 4378 4379 if (pat_content.IsAscii()) { 4380 Vector<const uint8_t> pat_vector = pat_content.ToOneByteVector(); 4381 if (sub_content.IsAscii()) { 4382 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4383 pat_vector, 4384 start_index); 4385 } else { 4386 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4387 pat_vector, 4388 start_index); 4389 } 4390 } else { 4391 Vector<const uc16> pat_vector = pat_content.ToUC16Vector(); 4392 if (sub_content.IsAscii()) { 4393 position = StringMatchBackwards(sub_content.ToOneByteVector(), 4394 pat_vector, 4395 start_index); 4396 } else { 4397 position = StringMatchBackwards(sub_content.ToUC16Vector(), 4398 pat_vector, 4399 start_index); 4400 } 4401 } 4402 4403 return Smi::FromInt(position); 4404 } 4405 4406 4407 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) { 4408 SealHandleScope shs(isolate); 4409 ASSERT(args.length() == 2); 4410 4411 CONVERT_ARG_CHECKED(String, str1, 0); 4412 CONVERT_ARG_CHECKED(String, str2, 1); 4413 4414 if (str1 == str2) return Smi::FromInt(0); // Equal. 4415 int str1_length = str1->length(); 4416 int str2_length = str2->length(); 4417 4418 // Decide trivial cases without flattening. 4419 if (str1_length == 0) { 4420 if (str2_length == 0) return Smi::FromInt(0); // Equal. 4421 return Smi::FromInt(-str2_length); 4422 } else { 4423 if (str2_length == 0) return Smi::FromInt(str1_length); 4424 } 4425 4426 int end = str1_length < str2_length ? str1_length : str2_length; 4427 4428 // No need to flatten if we are going to find the answer on the first 4429 // character. At this point we know there is at least one character 4430 // in each string, due to the trivial case handling above. 4431 int d = str1->Get(0) - str2->Get(0); 4432 if (d != 0) return Smi::FromInt(d); 4433 4434 str1->TryFlatten(); 4435 str2->TryFlatten(); 4436 4437 ConsStringIteratorOp* op1 = 4438 isolate->runtime_state()->string_locale_compare_it1(); 4439 ConsStringIteratorOp* op2 = 4440 isolate->runtime_state()->string_locale_compare_it2(); 4441 // TODO(dcarney) Can do array compares here more efficiently. 4442 StringCharacterStream stream1(str1, op1); 4443 StringCharacterStream stream2(str2, op2); 4444 4445 for (int i = 0; i < end; i++) { 4446 uint16_t char1 = stream1.GetNext(); 4447 uint16_t char2 = stream2.GetNext(); 4448 if (char1 != char2) return Smi::FromInt(char1 - char2); 4449 } 4450 4451 return Smi::FromInt(str1_length - str2_length); 4452 } 4453 4454 4455 RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) { 4456 SealHandleScope shs(isolate); 4457 ASSERT(args.length() == 3); 4458 4459 CONVERT_ARG_CHECKED(String, value, 0); 4460 int start, end; 4461 // We have a fast integer-only case here to avoid a conversion to double in 4462 // the common case where from and to are Smis. 4463 if (args[1]->IsSmi() && args[2]->IsSmi()) { 4464 CONVERT_SMI_ARG_CHECKED(from_number, 1); 4465 CONVERT_SMI_ARG_CHECKED(to_number, 2); 4466 start = from_number; 4467 end = to_number; 4468 } else { 4469 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1); 4470 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2); 4471 start = FastD2IChecked(from_number); 4472 end = FastD2IChecked(to_number); 4473 } 4474 RUNTIME_ASSERT(end >= start); 4475 RUNTIME_ASSERT(start >= 0); 4476 RUNTIME_ASSERT(end <= value->length()); 4477 isolate->counters()->sub_string_runtime()->Increment(); 4478 return value->SubString(start, end); 4479 } 4480 4481 4482 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) { 4483 HandleScope handles(isolate); 4484 ASSERT_EQ(3, args.length()); 4485 4486 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 4487 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1); 4488 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2); 4489 4490 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4491 if (global_cache.HasException()) return Failure::Exception(); 4492 4493 int capture_count = regexp->CaptureCount(); 4494 4495 ZoneScope zone_scope(isolate->runtime_zone()); 4496 ZoneList<int> offsets(8, zone_scope.zone()); 4497 4498 while (true) { 4499 int32_t* match = global_cache.FetchNext(); 4500 if (match == NULL) break; 4501 offsets.Add(match[0], zone_scope.zone()); // start 4502 offsets.Add(match[1], zone_scope.zone()); // end 4503 } 4504 4505 if (global_cache.HasException()) return Failure::Exception(); 4506 4507 if (offsets.length() == 0) { 4508 // Not a single match. 4509 return isolate->heap()->null_value(); 4510 } 4511 4512 RegExpImpl::SetLastMatchInfo(regexp_info, 4513 subject, 4514 capture_count, 4515 global_cache.LastSuccessfulMatch()); 4516 4517 int matches = offsets.length() / 2; 4518 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches); 4519 Handle<String> substring = 4520 isolate->factory()->NewSubString(subject, offsets.at(0), offsets.at(1)); 4521 elements->set(0, *substring); 4522 for (int i = 1; i < matches; i++) { 4523 HandleScope temp_scope(isolate); 4524 int from = offsets.at(i * 2); 4525 int to = offsets.at(i * 2 + 1); 4526 Handle<String> substring = 4527 isolate->factory()->NewProperSubString(subject, from, to); 4528 elements->set(i, *substring); 4529 } 4530 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements); 4531 result->set_length(Smi::FromInt(matches)); 4532 return *result; 4533 } 4534 4535 4536 // Only called from Runtime_RegExpExecMultiple so it doesn't need to maintain 4537 // separate last match info. See comment on that function. 4538 template<bool has_capture> 4539 static MaybeObject* SearchRegExpMultiple( 4540 Isolate* isolate, 4541 Handle<String> subject, 4542 Handle<JSRegExp> regexp, 4543 Handle<JSArray> last_match_array, 4544 Handle<JSArray> result_array) { 4545 ASSERT(subject->IsFlat()); 4546 ASSERT_NE(has_capture, regexp->CaptureCount() == 0); 4547 4548 int capture_count = regexp->CaptureCount(); 4549 int subject_length = subject->length(); 4550 4551 static const int kMinLengthToCache = 0x1000; 4552 4553 if (subject_length > kMinLengthToCache) { 4554 Handle<Object> cached_answer(RegExpResultsCache::Lookup( 4555 isolate->heap(), 4556 *subject, 4557 regexp->data(), 4558 RegExpResultsCache::REGEXP_MULTIPLE_INDICES), isolate); 4559 if (*cached_answer != Smi::FromInt(0)) { 4560 Handle<FixedArray> cached_fixed_array = 4561 Handle<FixedArray>(FixedArray::cast(*cached_answer)); 4562 // The cache FixedArray is a COW-array and can therefore be reused. 4563 isolate->factory()->SetContent(result_array, cached_fixed_array); 4564 // The actual length of the result array is stored in the last element of 4565 // the backing store (the backing FixedArray may have a larger capacity). 4566 Object* cached_fixed_array_last_element = 4567 cached_fixed_array->get(cached_fixed_array->length() - 1); 4568 Smi* js_array_length = Smi::cast(cached_fixed_array_last_element); 4569 result_array->set_length(js_array_length); 4570 RegExpImpl::SetLastMatchInfo( 4571 last_match_array, subject, capture_count, NULL); 4572 return *result_array; 4573 } 4574 } 4575 4576 RegExpImpl::GlobalCache global_cache(regexp, subject, true, isolate); 4577 if (global_cache.HasException()) return Failure::Exception(); 4578 4579 Handle<FixedArray> result_elements; 4580 if (result_array->HasFastObjectElements()) { 4581 result_elements = 4582 Handle<FixedArray>(FixedArray::cast(result_array->elements())); 4583 } 4584 if (result_elements.is_null() || result_elements->length() < 16) { 4585 result_elements = isolate->factory()->NewFixedArrayWithHoles(16); 4586 } 4587 4588 FixedArrayBuilder builder(result_elements); 4589 4590 // Position to search from. 4591 int match_start = -1; 4592 int match_end = 0; 4593 bool first = true; 4594 4595 // Two smis before and after the match, for very long strings. 4596 static const int kMaxBuilderEntriesPerRegExpMatch = 5; 4597 4598 while (true) { 4599 int32_t* current_match = global_cache.FetchNext(); 4600 if (current_match == NULL) break; 4601 match_start = current_match[0]; 4602 builder.EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch); 4603 if (match_end < match_start) { 4604 ReplacementStringBuilder::AddSubjectSlice(&builder, 4605 match_end, 4606 match_start); 4607 } 4608 match_end = current_match[1]; 4609 { 4610 // Avoid accumulating new handles inside loop. 4611 HandleScope temp_scope(isolate); 4612 Handle<String> match; 4613 if (!first) { 4614 match = isolate->factory()->NewProperSubString(subject, 4615 match_start, 4616 match_end); 4617 } else { 4618 match = isolate->factory()->NewSubString(subject, 4619 match_start, 4620 match_end); 4621 first = false; 4622 } 4623 4624 if (has_capture) { 4625 // Arguments array to replace function is match, captures, index and 4626 // subject, i.e., 3 + capture count in total. 4627 Handle<FixedArray> elements = 4628 isolate->factory()->NewFixedArray(3 + capture_count); 4629 4630 elements->set(0, *match); 4631 for (int i = 1; i <= capture_count; i++) { 4632 int start = current_match[i * 2]; 4633 if (start >= 0) { 4634 int end = current_match[i * 2 + 1]; 4635 ASSERT(start <= end); 4636 Handle<String> substring = 4637 isolate->factory()->NewSubString(subject, start, end); 4638 elements->set(i, *substring); 4639 } else { 4640 ASSERT(current_match[i * 2 + 1] < 0); 4641 elements->set(i, isolate->heap()->undefined_value()); 4642 } 4643 } 4644 elements->set(capture_count + 1, Smi::FromInt(match_start)); 4645 elements->set(capture_count + 2, *subject); 4646 builder.Add(*isolate->factory()->NewJSArrayWithElements(elements)); 4647 } else { 4648 builder.Add(*match); 4649 } 4650 } 4651 } 4652 4653 if (global_cache.HasException()) return Failure::Exception(); 4654 4655 if (match_start >= 0) { 4656 // Finished matching, with at least one match. 4657 if (match_end < subject_length) { 4658 ReplacementStringBuilder::AddSubjectSlice(&builder, 4659 match_end, 4660 subject_length); 4661 } 4662 4663 RegExpImpl::SetLastMatchInfo( 4664 last_match_array, subject, capture_count, NULL); 4665 4666 if (subject_length > kMinLengthToCache) { 4667 // Store the length of the result array into the last element of the 4668 // backing FixedArray. 4669 builder.EnsureCapacity(1); 4670 Handle<FixedArray> fixed_array = builder.array(); 4671 fixed_array->set(fixed_array->length() - 1, 4672 Smi::FromInt(builder.length())); 4673 // Cache the result and turn the FixedArray into a COW array. 4674 RegExpResultsCache::Enter(isolate->heap(), 4675 *subject, 4676 regexp->data(), 4677 *fixed_array, 4678 RegExpResultsCache::REGEXP_MULTIPLE_INDICES); 4679 } 4680 return *builder.ToJSArray(result_array); 4681 } else { 4682 return isolate->heap()->null_value(); // No matches at all. 4683 } 4684 } 4685 4686 4687 // This is only called for StringReplaceGlobalRegExpWithFunction. This sets 4688 // lastMatchInfoOverride to maintain the last match info, so we don't need to 4689 // set any other last match array info. 4690 RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) { 4691 HandleScope handles(isolate); 4692 ASSERT(args.length() == 4); 4693 4694 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1); 4695 if (!subject->IsFlat()) FlattenString(subject); 4696 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0); 4697 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2); 4698 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3); 4699 4700 ASSERT(regexp->GetFlags().is_global()); 4701 4702 if (regexp->CaptureCount() == 0) { 4703 return SearchRegExpMultiple<false>( 4704 isolate, subject, regexp, last_match_info, result_array); 4705 } else { 4706 return SearchRegExpMultiple<true>( 4707 isolate, subject, regexp, last_match_info, result_array); 4708 } 4709 } 4710 4711 4712 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) { 4713 SealHandleScope shs(isolate); 4714 ASSERT(args.length() == 2); 4715 CONVERT_SMI_ARG_CHECKED(radix, 1); 4716 RUNTIME_ASSERT(2 <= radix && radix <= 36); 4717 4718 // Fast case where the result is a one character string. 4719 if (args[0]->IsSmi()) { 4720 int value = args.smi_at(0); 4721 if (value >= 0 && value < radix) { 4722 // Character array used for conversion. 4723 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 4724 return isolate->heap()-> 4725 LookupSingleCharacterStringFromCode(kCharTable[value]); 4726 } 4727 } 4728 4729 // Slow case. 4730 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4731 if (std::isnan(value)) { 4732 return *isolate->factory()->nan_string(); 4733 } 4734 if (std::isinf(value)) { 4735 if (value < 0) { 4736 return *isolate->factory()->minus_infinity_string(); 4737 } 4738 return *isolate->factory()->infinity_string(); 4739 } 4740 char* str = DoubleToRadixCString(value, radix); 4741 MaybeObject* result = 4742 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4743 DeleteArray(str); 4744 return result; 4745 } 4746 4747 4748 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) { 4749 SealHandleScope shs(isolate); 4750 ASSERT(args.length() == 2); 4751 4752 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4753 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4754 int f = FastD2IChecked(f_number); 4755 RUNTIME_ASSERT(f >= 0); 4756 char* str = DoubleToFixedCString(value, f); 4757 MaybeObject* res = 4758 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4759 DeleteArray(str); 4760 return res; 4761 } 4762 4763 4764 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) { 4765 SealHandleScope shs(isolate); 4766 ASSERT(args.length() == 2); 4767 4768 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4769 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4770 int f = FastD2IChecked(f_number); 4771 RUNTIME_ASSERT(f >= -1 && f <= 20); 4772 char* str = DoubleToExponentialCString(value, f); 4773 MaybeObject* res = 4774 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4775 DeleteArray(str); 4776 return res; 4777 } 4778 4779 4780 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) { 4781 SealHandleScope shs(isolate); 4782 ASSERT(args.length() == 2); 4783 4784 CONVERT_DOUBLE_ARG_CHECKED(value, 0); 4785 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1); 4786 int f = FastD2IChecked(f_number); 4787 RUNTIME_ASSERT(f >= 1 && f <= 21); 4788 char* str = DoubleToPrecisionCString(value, f); 4789 MaybeObject* res = 4790 isolate->heap()->AllocateStringFromOneByte(CStrVector(str)); 4791 DeleteArray(str); 4792 return res; 4793 } 4794 4795 4796 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsValidSmi) { 4797 HandleScope shs(isolate); 4798 ASSERT(args.length() == 1); 4799 4800 CONVERT_NUMBER_CHECKED(int32_t, number, Int32, args[0]); 4801 if (Smi::IsValid(number)) { 4802 return isolate->heap()->true_value(); 4803 } else { 4804 return isolate->heap()->false_value(); 4805 } 4806 } 4807 4808 4809 // Returns a single character string where first character equals 4810 // string->Get(index). 4811 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) { 4812 if (index < static_cast<uint32_t>(string->length())) { 4813 string->TryFlatten(); 4814 return LookupSingleCharacterStringFromCode( 4815 string->GetIsolate(), 4816 string->Get(index)); 4817 } 4818 return Execution::CharAt(string, index); 4819 } 4820 4821 4822 MaybeObject* Runtime::GetElementOrCharAtOrFail(Isolate* isolate, 4823 Handle<Object> object, 4824 uint32_t index) { 4825 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, 4826 GetElementOrCharAt(isolate, object, index)); 4827 } 4828 4829 4830 MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate, 4831 Handle<Object> object, 4832 uint32_t index) { 4833 // Handle [] indexing on Strings 4834 if (object->IsString()) { 4835 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index); 4836 if (!result->IsUndefined()) return *result; 4837 } 4838 4839 // Handle [] indexing on String objects 4840 if (object->IsStringObjectWithCharacterAt(index)) { 4841 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 4842 Handle<Object> result = 4843 GetCharAt(Handle<String>(String::cast(js_value->value())), index); 4844 if (!result->IsUndefined()) return *result; 4845 } 4846 4847 if (object->IsString() || object->IsNumber() || object->IsBoolean()) { 4848 return object->GetPrototype(isolate)->GetElement(isolate, index); 4849 } 4850 4851 return object->GetElement(isolate, index); 4852 } 4853 4854 4855 static Handle<Name> ToName(Isolate* isolate, Handle<Object> key) { 4856 if (key->IsName()) { 4857 return Handle<Name>::cast(key); 4858 } else { 4859 bool has_pending_exception = false; 4860 Handle<Object> converted = 4861 Execution::ToString(isolate, key, &has_pending_exception); 4862 if (has_pending_exception) return Handle<Name>(); 4863 return Handle<Name>::cast(converted); 4864 } 4865 } 4866 4867 4868 MaybeObject* Runtime::HasObjectProperty(Isolate* isolate, 4869 Handle<JSReceiver> object, 4870 Handle<Object> key) { 4871 HandleScope scope(isolate); 4872 4873 // Check if the given key is an array index. 4874 uint32_t index; 4875 if (key->ToArrayIndex(&index)) { 4876 return isolate->heap()->ToBoolean(JSReceiver::HasElement(object, index)); 4877 } 4878 4879 // Convert the key to a name - possibly by calling back into JavaScript. 4880 Handle<Name> name = ToName(isolate, key); 4881 RETURN_IF_EMPTY_HANDLE(isolate, name); 4882 4883 return isolate->heap()->ToBoolean(JSReceiver::HasProperty(object, name)); 4884 } 4885 4886 MaybeObject* Runtime::GetObjectPropertyOrFail( 4887 Isolate* isolate, 4888 Handle<Object> object, 4889 Handle<Object> key) { 4890 CALL_HEAP_FUNCTION_PASS_EXCEPTION(isolate, 4891 GetObjectProperty(isolate, object, key)); 4892 } 4893 4894 MaybeObject* Runtime::GetObjectProperty(Isolate* isolate, 4895 Handle<Object> object, 4896 Handle<Object> key) { 4897 HandleScope scope(isolate); 4898 4899 if (object->IsUndefined() || object->IsNull()) { 4900 Handle<Object> args[2] = { key, object }; 4901 Handle<Object> error = 4902 isolate->factory()->NewTypeError("non_object_property_load", 4903 HandleVector(args, 2)); 4904 return isolate->Throw(*error); 4905 } 4906 4907 // Check if the given key is an array index. 4908 uint32_t index; 4909 if (key->ToArrayIndex(&index)) { 4910 return GetElementOrCharAt(isolate, object, index); 4911 } 4912 4913 // Convert the key to a name - possibly by calling back into JavaScript. 4914 Handle<Name> name = ToName(isolate, key); 4915 RETURN_IF_EMPTY_HANDLE(isolate, name); 4916 4917 // Check if the name is trivially convertible to an index and get 4918 // the element if so. 4919 if (name->AsArrayIndex(&index)) { 4920 return GetElementOrCharAt(isolate, object, index); 4921 } else { 4922 return object->GetProperty(*name); 4923 } 4924 } 4925 4926 4927 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) { 4928 SealHandleScope shs(isolate); 4929 ASSERT(args.length() == 2); 4930 4931 Handle<Object> object = args.at<Object>(0); 4932 Handle<Object> key = args.at<Object>(1); 4933 4934 return Runtime::GetObjectProperty(isolate, object, key); 4935 } 4936 4937 4938 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. 4939 RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) { 4940 SealHandleScope shs(isolate); 4941 ASSERT(args.length() == 2); 4942 4943 // Fast cases for getting named properties of the receiver JSObject 4944 // itself. 4945 // 4946 // The global proxy objects has to be excluded since LocalLookup on 4947 // the global proxy object can return a valid result even though the 4948 // global proxy object never has properties. This is the case 4949 // because the global proxy object forwards everything to its hidden 4950 // prototype including local lookups. 4951 // 4952 // Additionally, we need to make sure that we do not cache results 4953 // for objects that require access checks. 4954 if (args[0]->IsJSObject()) { 4955 if (!args[0]->IsJSGlobalProxy() && 4956 !args[0]->IsAccessCheckNeeded() && 4957 args[1]->IsName()) { 4958 JSObject* receiver = JSObject::cast(args[0]); 4959 Name* key = Name::cast(args[1]); 4960 if (receiver->HasFastProperties()) { 4961 // Attempt to use lookup cache. 4962 Map* receiver_map = receiver->map(); 4963 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache(); 4964 int offset = keyed_lookup_cache->Lookup(receiver_map, key); 4965 if (offset != -1) { 4966 // Doubles are not cached, so raw read the value. 4967 Object* value = receiver->RawFastPropertyAt(offset); 4968 return value->IsTheHole() 4969 ? isolate->heap()->undefined_value() 4970 : value; 4971 } 4972 // Lookup cache miss. Perform lookup and update the cache if 4973 // appropriate. 4974 LookupResult result(isolate); 4975 receiver->LocalLookup(key, &result); 4976 if (result.IsField()) { 4977 int offset = result.GetFieldIndex().field_index(); 4978 // Do not track double fields in the keyed lookup cache. Reading 4979 // double values requires boxing. 4980 if (!FLAG_track_double_fields || 4981 !result.representation().IsDouble()) { 4982 keyed_lookup_cache->Update(receiver_map, key, offset); 4983 } 4984 return receiver->FastPropertyAt(result.representation(), offset); 4985 } 4986 } else { 4987 // Attempt dictionary lookup. 4988 NameDictionary* dictionary = receiver->property_dictionary(); 4989 int entry = dictionary->FindEntry(key); 4990 if ((entry != NameDictionary::kNotFound) && 4991 (dictionary->DetailsAt(entry).type() == NORMAL)) { 4992 Object* value = dictionary->ValueAt(entry); 4993 if (!receiver->IsGlobalObject()) return value; 4994 value = PropertyCell::cast(value)->value(); 4995 if (!value->IsTheHole()) return value; 4996 // If value is the hole do the general lookup. 4997 } 4998 } 4999 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) { 5000 // JSObject without a name key. If the key is a Smi, check for a 5001 // definite out-of-bounds access to elements, which is a strong indicator 5002 // that subsequent accesses will also call the runtime. Proactively 5003 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of 5004 // doubles for those future calls in the case that the elements would 5005 // become FAST_DOUBLE_ELEMENTS. 5006 Handle<JSObject> js_object(args.at<JSObject>(0)); 5007 ElementsKind elements_kind = js_object->GetElementsKind(); 5008 if (IsFastDoubleElementsKind(elements_kind)) { 5009 FixedArrayBase* elements = js_object->elements(); 5010 if (args.at<Smi>(1)->value() >= elements->length()) { 5011 if (IsFastHoleyElementsKind(elements_kind)) { 5012 elements_kind = FAST_HOLEY_ELEMENTS; 5013 } else { 5014 elements_kind = FAST_ELEMENTS; 5015 } 5016 MaybeObject* maybe_object = TransitionElements(js_object, 5017 elements_kind, 5018 isolate); 5019 if (maybe_object->IsFailure()) return maybe_object; 5020 } 5021 } else { 5022 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || 5023 !IsFastElementsKind(elements_kind)); 5024 } 5025 } 5026 } else if (args[0]->IsString() && args[1]->IsSmi()) { 5027 // Fast case for string indexing using [] with a smi index. 5028 HandleScope scope(isolate); 5029 Handle<String> str = args.at<String>(0); 5030 int index = args.smi_at(1); 5031 if (index >= 0 && index < str->length()) { 5032 Handle<Object> result = GetCharAt(str, index); 5033 return *result; 5034 } 5035 } 5036 5037 // Fall back to GetObjectProperty. 5038 return Runtime::GetObjectProperty(isolate, 5039 args.at<Object>(0), 5040 args.at<Object>(1)); 5041 } 5042 5043 5044 static bool IsValidAccessor(Handle<Object> obj) { 5045 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull(); 5046 } 5047 5048 5049 // Implements part of 8.12.9 DefineOwnProperty. 5050 // There are 3 cases that lead here: 5051 // Step 4b - define a new accessor property. 5052 // Steps 9c & 12 - replace an existing data property with an accessor property. 5053 // Step 12 - update an existing accessor property with an accessor or generic 5054 // descriptor. 5055 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) { 5056 HandleScope scope(isolate); 5057 ASSERT(args.length() == 5); 5058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5059 RUNTIME_ASSERT(!obj->IsNull()); 5060 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5061 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2); 5062 RUNTIME_ASSERT(IsValidAccessor(getter)); 5063 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3); 5064 RUNTIME_ASSERT(IsValidAccessor(setter)); 5065 CONVERT_SMI_ARG_CHECKED(unchecked, 4); 5066 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5067 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 5068 5069 bool fast = obj->HasFastProperties(); 5070 JSObject::DefineAccessor(obj, name, getter, setter, attr); 5071 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5072 if (fast) JSObject::TransformToFastProperties(obj, 0); 5073 return isolate->heap()->undefined_value(); 5074 } 5075 5076 5077 // Implements part of 8.12.9 DefineOwnProperty. 5078 // There are 3 cases that lead here: 5079 // Step 4a - define a new data property. 5080 // Steps 9b & 12 - replace an existing accessor property with a data property. 5081 // Step 12 - update an existing data property with a data or generic 5082 // descriptor. 5083 RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) { 5084 HandleScope scope(isolate); 5085 ASSERT(args.length() == 4); 5086 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); 5087 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5088 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2); 5089 CONVERT_SMI_ARG_CHECKED(unchecked, 3); 5090 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5091 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); 5092 5093 LookupResult lookup(isolate); 5094 js_object->LocalLookupRealNamedProperty(*name, &lookup); 5095 5096 // Special case for callback properties. 5097 if (lookup.IsPropertyCallbacks()) { 5098 Handle<Object> callback(lookup.GetCallbackObject(), isolate); 5099 // To be compatible with Safari we do not change the value on API objects 5100 // in Object.defineProperty(). Firefox disagrees here, and actually changes 5101 // the value. 5102 if (callback->IsAccessorInfo()) { 5103 return isolate->heap()->undefined_value(); 5104 } 5105 // Avoid redefining foreign callback as data property, just use the stored 5106 // setter to update the value instead. 5107 // TODO(mstarzinger): So far this only works if property attributes don't 5108 // change, this should be fixed once we cleanup the underlying code. 5109 if (callback->IsForeign() && lookup.GetAttributes() == attr) { 5110 Handle<Object> result_object = 5111 JSObject::SetPropertyWithCallback(js_object, 5112 callback, 5113 name, 5114 obj_value, 5115 handle(lookup.holder()), 5116 kStrictMode); 5117 RETURN_IF_EMPTY_HANDLE(isolate, result_object); 5118 return *result_object; 5119 } 5120 } 5121 5122 // Take special care when attributes are different and there is already 5123 // a property. For simplicity we normalize the property which enables us 5124 // to not worry about changing the instance_descriptor and creating a new 5125 // map. The current version of SetObjectProperty does not handle attributes 5126 // correctly in the case where a property is a field and is reset with 5127 // new attributes. 5128 if (lookup.IsFound() && 5129 (attr != lookup.GetAttributes() || lookup.IsPropertyCallbacks())) { 5130 // New attributes - normalize to avoid writing to instance descriptor 5131 if (js_object->IsJSGlobalProxy()) { 5132 // Since the result is a property, the prototype will exist so 5133 // we don't have to check for null. 5134 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype())); 5135 } 5136 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0); 5137 // Use IgnoreAttributes version since a readonly property may be 5138 // overridden and SetProperty does not allow this. 5139 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes( 5140 js_object, name, obj_value, attr); 5141 RETURN_IF_EMPTY_HANDLE(isolate, result); 5142 return *result; 5143 } 5144 5145 Handle<Object> result = Runtime::ForceSetObjectProperty(isolate, js_object, 5146 name, 5147 obj_value, 5148 attr); 5149 RETURN_IF_EMPTY_HANDLE(isolate, result); 5150 return *result; 5151 } 5152 5153 5154 // Return property without being observable by accessors or interceptors. 5155 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) { 5156 SealHandleScope shs(isolate); 5157 ASSERT(args.length() == 2); 5158 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5159 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5160 LookupResult lookup(isolate); 5161 object->LookupRealNamedProperty(*key, &lookup); 5162 if (!lookup.IsFound()) return isolate->heap()->undefined_value(); 5163 switch (lookup.type()) { 5164 case NORMAL: 5165 return lookup.holder()->GetNormalizedProperty(&lookup); 5166 case FIELD: 5167 return lookup.holder()->FastPropertyAt( 5168 lookup.representation(), 5169 lookup.GetFieldIndex().field_index()); 5170 case CONSTANT: 5171 return lookup.GetConstant(); 5172 case CALLBACKS: 5173 case HANDLER: 5174 case INTERCEPTOR: 5175 case TRANSITION: 5176 return isolate->heap()->undefined_value(); 5177 case NONEXISTENT: 5178 UNREACHABLE(); 5179 } 5180 return isolate->heap()->undefined_value(); 5181 } 5182 5183 5184 Handle<Object> Runtime::SetObjectProperty(Isolate* isolate, 5185 Handle<Object> object, 5186 Handle<Object> key, 5187 Handle<Object> value, 5188 PropertyAttributes attr, 5189 StrictModeFlag strict_mode) { 5190 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; 5191 5192 if (object->IsUndefined() || object->IsNull()) { 5193 Handle<Object> args[2] = { key, object }; 5194 Handle<Object> error = 5195 isolate->factory()->NewTypeError("non_object_property_store", 5196 HandleVector(args, 2)); 5197 isolate->Throw(*error); 5198 return Handle<Object>(); 5199 } 5200 5201 if (object->IsJSProxy()) { 5202 bool has_pending_exception = false; 5203 Handle<Object> name_object = key->IsSymbol() 5204 ? key : Execution::ToString(isolate, key, &has_pending_exception); 5205 if (has_pending_exception) return Handle<Object>(); // exception 5206 Handle<Name> name = Handle<Name>::cast(name_object); 5207 return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value, 5208 attr, 5209 strict_mode); 5210 } 5211 5212 // If the object isn't a JavaScript object, we ignore the store. 5213 if (!object->IsJSObject()) return value; 5214 5215 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 5216 5217 // Check if the given key is an array index. 5218 uint32_t index; 5219 if (key->ToArrayIndex(&index)) { 5220 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5221 // of a string using [] notation. We need to support this too in 5222 // JavaScript. 5223 // In the case of a String object we just need to redirect the assignment to 5224 // the underlying string if the index is in range. Since the underlying 5225 // string does nothing with the assignment then we can ignore such 5226 // assignments. 5227 if (js_object->IsStringObjectWithCharacterAt(index)) { 5228 return value; 5229 } 5230 5231 js_object->ValidateElements(); 5232 if (js_object->HasExternalArrayElements()) { 5233 if (!value->IsNumber() && !value->IsUndefined()) { 5234 bool has_exception; 5235 Handle<Object> number = 5236 Execution::ToNumber(isolate, value, &has_exception); 5237 if (has_exception) return Handle<Object>(); // exception 5238 value = number; 5239 } 5240 } 5241 Handle<Object> result = JSObject::SetElement(js_object, index, value, attr, 5242 strict_mode, 5243 true, 5244 set_mode); 5245 js_object->ValidateElements(); 5246 return result.is_null() ? result : value; 5247 } 5248 5249 if (key->IsName()) { 5250 Handle<Name> name = Handle<Name>::cast(key); 5251 if (name->AsArrayIndex(&index)) { 5252 if (js_object->HasExternalArrayElements()) { 5253 if (!value->IsNumber() && !value->IsUndefined()) { 5254 bool has_exception; 5255 Handle<Object> number = 5256 Execution::ToNumber(isolate, value, &has_exception); 5257 if (has_exception) return Handle<Object>(); // exception 5258 value = number; 5259 } 5260 } 5261 return JSObject::SetElement(js_object, index, value, attr, strict_mode, 5262 true, 5263 set_mode); 5264 } else { 5265 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5266 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); 5267 } 5268 } 5269 5270 // Call-back into JavaScript to convert the key to a string. 5271 bool has_pending_exception = false; 5272 Handle<Object> converted = 5273 Execution::ToString(isolate, key, &has_pending_exception); 5274 if (has_pending_exception) return Handle<Object>(); // exception 5275 Handle<String> name = Handle<String>::cast(converted); 5276 5277 if (name->AsArrayIndex(&index)) { 5278 return JSObject::SetElement(js_object, index, value, attr, strict_mode, 5279 true, 5280 set_mode); 5281 } else { 5282 return JSReceiver::SetProperty(js_object, name, value, attr, strict_mode); 5283 } 5284 } 5285 5286 5287 Handle<Object> Runtime::ForceSetObjectProperty(Isolate* isolate, 5288 Handle<JSObject> js_object, 5289 Handle<Object> key, 5290 Handle<Object> value, 5291 PropertyAttributes attr) { 5292 // Check if the given key is an array index. 5293 uint32_t index; 5294 if (key->ToArrayIndex(&index)) { 5295 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 5296 // of a string using [] notation. We need to support this too in 5297 // JavaScript. 5298 // In the case of a String object we just need to redirect the assignment to 5299 // the underlying string if the index is in range. Since the underlying 5300 // string does nothing with the assignment then we can ignore such 5301 // assignments. 5302 if (js_object->IsStringObjectWithCharacterAt(index)) { 5303 return value; 5304 } 5305 5306 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, 5307 false, 5308 DEFINE_PROPERTY); 5309 } 5310 5311 if (key->IsName()) { 5312 Handle<Name> name = Handle<Name>::cast(key); 5313 if (name->AsArrayIndex(&index)) { 5314 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, 5315 false, 5316 DEFINE_PROPERTY); 5317 } else { 5318 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5319 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, 5320 value, attr); 5321 } 5322 } 5323 5324 // Call-back into JavaScript to convert the key to a string. 5325 bool has_pending_exception = false; 5326 Handle<Object> converted = 5327 Execution::ToString(isolate, key, &has_pending_exception); 5328 if (has_pending_exception) return Handle<Object>(); // exception 5329 Handle<String> name = Handle<String>::cast(converted); 5330 5331 if (name->AsArrayIndex(&index)) { 5332 return JSObject::SetElement(js_object, index, value, attr, kNonStrictMode, 5333 false, 5334 DEFINE_PROPERTY); 5335 } else { 5336 return JSObject::SetLocalPropertyIgnoreAttributes(js_object, name, value, 5337 attr); 5338 } 5339 } 5340 5341 5342 MaybeObject* Runtime::DeleteObjectProperty(Isolate* isolate, 5343 Handle<JSReceiver> receiver, 5344 Handle<Object> key, 5345 JSReceiver::DeleteMode mode) { 5346 HandleScope scope(isolate); 5347 5348 // Check if the given key is an array index. 5349 uint32_t index; 5350 if (key->ToArrayIndex(&index)) { 5351 // In Firefox/SpiderMonkey, Safari and Opera you can access the 5352 // characters of a string using [] notation. In the case of a 5353 // String object we just need to redirect the deletion to the 5354 // underlying string if the index is in range. Since the 5355 // underlying string does nothing with the deletion, we can ignore 5356 // such deletions. 5357 if (receiver->IsStringObjectWithCharacterAt(index)) { 5358 return isolate->heap()->true_value(); 5359 } 5360 5361 Handle<Object> result = JSReceiver::DeleteElement(receiver, index, mode); 5362 RETURN_IF_EMPTY_HANDLE(isolate, result); 5363 return *result; 5364 } 5365 5366 Handle<Name> name; 5367 if (key->IsName()) { 5368 name = Handle<Name>::cast(key); 5369 } else { 5370 // Call-back into JavaScript to convert the key to a string. 5371 bool has_pending_exception = false; 5372 Handle<Object> converted = Execution::ToString( 5373 isolate, key, &has_pending_exception); 5374 if (has_pending_exception) return Failure::Exception(); 5375 name = Handle<String>::cast(converted); 5376 } 5377 5378 if (name->IsString()) Handle<String>::cast(name)->TryFlatten(); 5379 Handle<Object> result = JSReceiver::DeleteProperty(receiver, name, mode); 5380 RETURN_IF_EMPTY_HANDLE(isolate, result); 5381 return *result; 5382 } 5383 5384 5385 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) { 5386 HandleScope scope(isolate); 5387 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5); 5388 5389 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 5390 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); 5391 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5392 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3); 5393 RUNTIME_ASSERT( 5394 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5395 // Compute attributes. 5396 PropertyAttributes attributes = 5397 static_cast<PropertyAttributes>(unchecked_attributes); 5398 5399 StrictModeFlag strict_mode = kNonStrictMode; 5400 if (args.length() == 5) { 5401 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4); 5402 strict_mode = strict_mode_flag; 5403 } 5404 5405 Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key, 5406 value, 5407 attributes, 5408 strict_mode); 5409 RETURN_IF_EMPTY_HANDLE(isolate, result); 5410 return *result; 5411 } 5412 5413 5414 RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsKind) { 5415 HandleScope scope(isolate); 5416 RUNTIME_ASSERT(args.length() == 2); 5417 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 5418 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1); 5419 JSObject::TransitionElementsKind(array, map->elements_kind()); 5420 return *array; 5421 } 5422 5423 5424 // Set the native flag on the function. 5425 // This is used to decide if we should transform null and undefined 5426 // into the global object when doing call and apply. 5427 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) { 5428 SealHandleScope shs(isolate); 5429 RUNTIME_ASSERT(args.length() == 1); 5430 5431 CONVERT_ARG_CHECKED(Object, object, 0); 5432 5433 if (object->IsJSFunction()) { 5434 JSFunction* func = JSFunction::cast(object); 5435 func->shared()->set_native(true); 5436 } 5437 return isolate->heap()->undefined_value(); 5438 } 5439 5440 5441 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInlineBuiltinFlag) { 5442 SealHandleScope shs(isolate); 5443 RUNTIME_ASSERT(args.length() == 1); 5444 5445 Handle<Object> object = args.at<Object>(0); 5446 5447 if (object->IsJSFunction()) { 5448 JSFunction* func = JSFunction::cast(*object); 5449 func->shared()->set_inline_builtin(true); 5450 } 5451 return isolate->heap()->undefined_value(); 5452 } 5453 5454 5455 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) { 5456 HandleScope scope(isolate); 5457 RUNTIME_ASSERT(args.length() == 5); 5458 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5459 CONVERT_SMI_ARG_CHECKED(store_index, 1); 5460 Handle<Object> value = args.at<Object>(2); 5461 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3); 5462 CONVERT_SMI_ARG_CHECKED(literal_index, 4); 5463 5464 Object* raw_literal_cell = literals->get(literal_index); 5465 JSArray* boilerplate = NULL; 5466 if (raw_literal_cell->IsAllocationSite()) { 5467 AllocationSite* site = AllocationSite::cast(raw_literal_cell); 5468 boilerplate = JSArray::cast(site->transition_info()); 5469 } else { 5470 boilerplate = JSArray::cast(raw_literal_cell); 5471 } 5472 Handle<JSArray> boilerplate_object(boilerplate); 5473 ElementsKind elements_kind = object->GetElementsKind(); 5474 ASSERT(IsFastElementsKind(elements_kind)); 5475 // Smis should never trigger transitions. 5476 ASSERT(!value->IsSmi()); 5477 5478 if (value->IsNumber()) { 5479 ASSERT(IsFastSmiElementsKind(elements_kind)); 5480 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5481 ? FAST_HOLEY_DOUBLE_ELEMENTS 5482 : FAST_DOUBLE_ELEMENTS; 5483 if (IsMoreGeneralElementsKindTransition( 5484 boilerplate_object->GetElementsKind(), 5485 transitioned_kind)) { 5486 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5487 } 5488 JSObject::TransitionElementsKind(object, transitioned_kind); 5489 ASSERT(IsFastDoubleElementsKind(object->GetElementsKind())); 5490 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements()); 5491 HeapNumber* number = HeapNumber::cast(*value); 5492 double_array->set(store_index, number->Number()); 5493 } else { 5494 ASSERT(IsFastSmiElementsKind(elements_kind) || 5495 IsFastDoubleElementsKind(elements_kind)); 5496 ElementsKind transitioned_kind = IsFastHoleyElementsKind(elements_kind) 5497 ? FAST_HOLEY_ELEMENTS 5498 : FAST_ELEMENTS; 5499 JSObject::TransitionElementsKind(object, transitioned_kind); 5500 if (IsMoreGeneralElementsKindTransition( 5501 boilerplate_object->GetElementsKind(), 5502 transitioned_kind)) { 5503 JSObject::TransitionElementsKind(boilerplate_object, transitioned_kind); 5504 } 5505 FixedArray* object_array = FixedArray::cast(object->elements()); 5506 object_array->set(store_index, *value); 5507 } 5508 return *object; 5509 } 5510 5511 5512 // Check whether debugger and is about to step into the callback that is passed 5513 // to a built-in function such as Array.forEach. 5514 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) { 5515 SealHandleScope shs(isolate); 5516 #ifdef ENABLE_DEBUGGER_SUPPORT 5517 if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) { 5518 return isolate->heap()->false_value(); 5519 } 5520 CONVERT_ARG_CHECKED(Object, callback, 0); 5521 // We do not step into the callback if it's a builtin or not even a function. 5522 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) { 5523 return isolate->heap()->false_value(); 5524 } 5525 return isolate->heap()->true_value(); 5526 #else 5527 return isolate->heap()->false_value(); 5528 #endif // ENABLE_DEBUGGER_SUPPORT 5529 } 5530 5531 5532 // Set one shot breakpoints for the callback function that is passed to a 5533 // built-in function such as Array.forEach to enable stepping into the callback. 5534 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) { 5535 SealHandleScope shs(isolate); 5536 #ifdef ENABLE_DEBUGGER_SUPPORT 5537 Debug* debug = isolate->debug(); 5538 if (!debug->IsStepping()) return isolate->heap()->undefined_value(); 5539 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callback, 0); 5540 HandleScope scope(isolate); 5541 // When leaving the callback, step out has been activated, but not performed 5542 // if we do not leave the builtin. To be able to step into the callback 5543 // again, we need to clear the step out at this point. 5544 debug->ClearStepOut(); 5545 debug->FloodWithOneShot(callback); 5546 #endif // ENABLE_DEBUGGER_SUPPORT 5547 return isolate->heap()->undefined_value(); 5548 } 5549 5550 5551 // Set a local property, even if it is READ_ONLY. If the property does not 5552 // exist, it will be added with attributes NONE. 5553 RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) { 5554 HandleScope scope(isolate); 5555 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); 5556 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 5557 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 5558 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); 5559 // Compute attributes. 5560 PropertyAttributes attributes = NONE; 5561 if (args.length() == 4) { 5562 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3); 5563 // Only attribute bits should be set. 5564 RUNTIME_ASSERT( 5565 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); 5566 attributes = static_cast<PropertyAttributes>(unchecked_value); 5567 } 5568 Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes( 5569 object, name, value, attributes); 5570 RETURN_IF_EMPTY_HANDLE(isolate, result); 5571 return *result; 5572 } 5573 5574 5575 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) { 5576 HandleScope scope(isolate); 5577 ASSERT(args.length() == 3); 5578 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5579 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5580 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2); 5581 JSReceiver::DeleteMode delete_mode = (strict_mode == kStrictMode) 5582 ? JSReceiver::STRICT_DELETION : JSReceiver::NORMAL_DELETION; 5583 Handle<Object> result = JSReceiver::DeleteProperty(object, key, delete_mode); 5584 RETURN_IF_EMPTY_HANDLE(isolate, result); 5585 return *result; 5586 } 5587 5588 5589 static MaybeObject* HasLocalPropertyImplementation(Isolate* isolate, 5590 Handle<JSObject> object, 5591 Handle<Name> key) { 5592 if (JSReceiver::HasLocalProperty(object, key)) { 5593 return isolate->heap()->true_value(); 5594 } 5595 // Handle hidden prototypes. If there's a hidden prototype above this thing 5596 // then we have to check it for properties, because they are supposed to 5597 // look like they are on this object. 5598 Handle<Object> proto(object->GetPrototype(), isolate); 5599 if (proto->IsJSObject() && 5600 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) { 5601 return HasLocalPropertyImplementation(isolate, 5602 Handle<JSObject>::cast(proto), 5603 key); 5604 } 5605 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5606 return isolate->heap()->false_value(); 5607 } 5608 5609 5610 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) { 5611 HandleScope scope(isolate); 5612 ASSERT(args.length() == 2); 5613 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5614 Handle<Object> object = args.at<Object>(0); 5615 5616 uint32_t index; 5617 const bool key_is_array_index = key->AsArrayIndex(&index); 5618 5619 // Only JS objects can have properties. 5620 if (object->IsJSObject()) { 5621 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); 5622 // Fast case: either the key is a real named property or it is not 5623 // an array index and there are no interceptors or hidden 5624 // prototypes. 5625 if (JSObject::HasRealNamedProperty(js_obj, key)) { 5626 ASSERT(!isolate->has_scheduled_exception()); 5627 return isolate->heap()->true_value(); 5628 } else { 5629 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5630 } 5631 Map* map = js_obj->map(); 5632 if (!key_is_array_index && 5633 !map->has_named_interceptor() && 5634 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) { 5635 return isolate->heap()->false_value(); 5636 } 5637 // Slow case. 5638 return HasLocalPropertyImplementation(isolate, 5639 Handle<JSObject>(js_obj), 5640 Handle<Name>(key)); 5641 } else if (object->IsString() && key_is_array_index) { 5642 // Well, there is one exception: Handle [] on strings. 5643 Handle<String> string = Handle<String>::cast(object); 5644 if (index < static_cast<uint32_t>(string->length())) { 5645 return isolate->heap()->true_value(); 5646 } 5647 } 5648 return isolate->heap()->false_value(); 5649 } 5650 5651 5652 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) { 5653 HandleScope scope(isolate); 5654 ASSERT(args.length() == 2); 5655 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 5656 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1); 5657 5658 bool result = JSReceiver::HasProperty(receiver, key); 5659 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5660 if (isolate->has_pending_exception()) return Failure::Exception(); 5661 return isolate->heap()->ToBoolean(result); 5662 } 5663 5664 5665 RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) { 5666 HandleScope scope(isolate); 5667 ASSERT(args.length() == 2); 5668 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 5669 CONVERT_SMI_ARG_CHECKED(index, 1); 5670 5671 bool result = JSReceiver::HasElement(receiver, index); 5672 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5673 if (isolate->has_pending_exception()) return Failure::Exception(); 5674 return isolate->heap()->ToBoolean(result); 5675 } 5676 5677 5678 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) { 5679 SealHandleScope shs(isolate); 5680 ASSERT(args.length() == 2); 5681 5682 CONVERT_ARG_CHECKED(JSObject, object, 0); 5683 CONVERT_ARG_CHECKED(Name, key, 1); 5684 5685 PropertyAttributes att = object->GetLocalPropertyAttribute(key); 5686 if (att == ABSENT || (att & DONT_ENUM) != 0) { 5687 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5688 return isolate->heap()->false_value(); 5689 } 5690 ASSERT(!isolate->has_scheduled_exception()); 5691 return isolate->heap()->true_value(); 5692 } 5693 5694 5695 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) { 5696 HandleScope scope(isolate); 5697 ASSERT(args.length() == 1); 5698 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0); 5699 bool threw = false; 5700 Handle<JSArray> result = GetKeysFor(object, &threw); 5701 if (threw) return Failure::Exception(); 5702 return *result; 5703 } 5704 5705 5706 // Returns either a FixedArray as Runtime_GetPropertyNames, 5707 // or, if the given object has an enum cache that contains 5708 // all enumerable properties of the object and its prototypes 5709 // have none, the map of the object. This is used to speed up 5710 // the check for deletions during a for-in. 5711 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) { 5712 SealHandleScope shs(isolate); 5713 ASSERT(args.length() == 1); 5714 5715 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0); 5716 5717 if (raw_object->IsSimpleEnum()) return raw_object->map(); 5718 5719 HandleScope scope(isolate); 5720 Handle<JSReceiver> object(raw_object); 5721 bool threw = false; 5722 Handle<FixedArray> content = 5723 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw); 5724 if (threw) return Failure::Exception(); 5725 5726 // Test again, since cache may have been built by preceding call. 5727 if (object->IsSimpleEnum()) return object->map(); 5728 5729 return *content; 5730 } 5731 5732 5733 // Find the length of the prototype chain that is to to handled as one. If a 5734 // prototype object is hidden it is to be viewed as part of the the object it 5735 // is prototype for. 5736 static int LocalPrototypeChainLength(JSObject* obj) { 5737 int count = 1; 5738 Object* proto = obj->GetPrototype(); 5739 while (proto->IsJSObject() && 5740 JSObject::cast(proto)->map()->is_hidden_prototype()) { 5741 count++; 5742 proto = JSObject::cast(proto)->GetPrototype(); 5743 } 5744 return count; 5745 } 5746 5747 5748 // Return the names of the local named properties. 5749 // args[0]: object 5750 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) { 5751 HandleScope scope(isolate); 5752 ASSERT(args.length() == 2); 5753 if (!args[0]->IsJSObject()) { 5754 return isolate->heap()->undefined_value(); 5755 } 5756 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5757 CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1); 5758 PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC; 5759 5760 // Skip the global proxy as it has no properties and always delegates to the 5761 // real global object. 5762 if (obj->IsJSGlobalProxy()) { 5763 // Only collect names if access is permitted. 5764 if (obj->IsAccessCheckNeeded() && 5765 !isolate->MayNamedAccess(*obj, 5766 isolate->heap()->undefined_value(), 5767 v8::ACCESS_KEYS)) { 5768 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS); 5769 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5770 return *isolate->factory()->NewJSArray(0); 5771 } 5772 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 5773 } 5774 5775 // Find the number of objects making up this. 5776 int length = LocalPrototypeChainLength(*obj); 5777 5778 // Find the number of local properties for each of the objects. 5779 ScopedVector<int> local_property_count(length); 5780 int total_property_count = 0; 5781 Handle<JSObject> jsproto = obj; 5782 for (int i = 0; i < length; i++) { 5783 // Only collect names if access is permitted. 5784 if (jsproto->IsAccessCheckNeeded() && 5785 !isolate->MayNamedAccess(*jsproto, 5786 isolate->heap()->undefined_value(), 5787 v8::ACCESS_KEYS)) { 5788 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS); 5789 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5790 return *isolate->factory()->NewJSArray(0); 5791 } 5792 int n; 5793 n = jsproto->NumberOfLocalProperties(filter); 5794 local_property_count[i] = n; 5795 total_property_count += n; 5796 if (i < length - 1) { 5797 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5798 } 5799 } 5800 5801 // Allocate an array with storage for all the property names. 5802 Handle<FixedArray> names = 5803 isolate->factory()->NewFixedArray(total_property_count); 5804 5805 // Get the property names. 5806 jsproto = obj; 5807 int proto_with_hidden_properties = 0; 5808 int next_copy_index = 0; 5809 for (int i = 0; i < length; i++) { 5810 jsproto->GetLocalPropertyNames(*names, next_copy_index, filter); 5811 next_copy_index += local_property_count[i]; 5812 if (jsproto->HasHiddenProperties()) { 5813 proto_with_hidden_properties++; 5814 } 5815 if (i < length - 1) { 5816 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 5817 } 5818 } 5819 5820 // Filter out name of hidden properties object. 5821 if (proto_with_hidden_properties > 0) { 5822 Handle<FixedArray> old_names = names; 5823 names = isolate->factory()->NewFixedArray( 5824 names->length() - proto_with_hidden_properties); 5825 int dest_pos = 0; 5826 for (int i = 0; i < total_property_count; i++) { 5827 Object* name = old_names->get(i); 5828 if (name == isolate->heap()->hidden_string()) { 5829 continue; 5830 } 5831 names->set(dest_pos++, name); 5832 } 5833 } 5834 5835 return *isolate->factory()->NewJSArrayWithElements(names); 5836 } 5837 5838 5839 // Return the names of the local indexed properties. 5840 // args[0]: object 5841 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) { 5842 HandleScope scope(isolate); 5843 ASSERT(args.length() == 1); 5844 if (!args[0]->IsJSObject()) { 5845 return isolate->heap()->undefined_value(); 5846 } 5847 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5848 5849 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE)); 5850 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n); 5851 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE)); 5852 return *isolate->factory()->NewJSArrayWithElements(names); 5853 } 5854 5855 5856 // Return information on whether an object has a named or indexed interceptor. 5857 // args[0]: object 5858 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) { 5859 HandleScope scope(isolate); 5860 ASSERT(args.length() == 1); 5861 if (!args[0]->IsJSObject()) { 5862 return Smi::FromInt(0); 5863 } 5864 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5865 5866 int result = 0; 5867 if (obj->HasNamedInterceptor()) result |= 2; 5868 if (obj->HasIndexedInterceptor()) result |= 1; 5869 5870 return Smi::FromInt(result); 5871 } 5872 5873 5874 // Return property names from named interceptor. 5875 // args[0]: object 5876 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) { 5877 HandleScope scope(isolate); 5878 ASSERT(args.length() == 1); 5879 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5880 5881 if (obj->HasNamedInterceptor()) { 5882 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj); 5883 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5884 } 5885 return isolate->heap()->undefined_value(); 5886 } 5887 5888 5889 // Return element names from indexed interceptor. 5890 // args[0]: object 5891 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) { 5892 HandleScope scope(isolate); 5893 ASSERT(args.length() == 1); 5894 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 5895 5896 if (obj->HasIndexedInterceptor()) { 5897 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj); 5898 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); 5899 } 5900 return isolate->heap()->undefined_value(); 5901 } 5902 5903 5904 RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) { 5905 HandleScope scope(isolate); 5906 ASSERT_EQ(args.length(), 1); 5907 CONVERT_ARG_CHECKED(JSObject, raw_object, 0); 5908 Handle<JSObject> object(raw_object); 5909 5910 if (object->IsJSGlobalProxy()) { 5911 // Do access checks before going to the global object. 5912 if (object->IsAccessCheckNeeded() && 5913 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), 5914 v8::ACCESS_KEYS)) { 5915 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS); 5916 RETURN_IF_SCHEDULED_EXCEPTION(isolate); 5917 return *isolate->factory()->NewJSArray(0); 5918 } 5919 5920 Handle<Object> proto(object->GetPrototype(), isolate); 5921 // If proxy is detached we simply return an empty array. 5922 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0); 5923 object = Handle<JSObject>::cast(proto); 5924 } 5925 5926 bool threw = false; 5927 Handle<FixedArray> contents = 5928 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw); 5929 if (threw) return Failure::Exception(); 5930 5931 // Some fast paths through GetKeysInFixedArrayFor reuse a cached 5932 // property array and since the result is mutable we have to create 5933 // a fresh clone on each invocation. 5934 int length = contents->length(); 5935 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length); 5936 for (int i = 0; i < length; i++) { 5937 Object* entry = contents->get(i); 5938 if (entry->IsString()) { 5939 copy->set(i, entry); 5940 } else { 5941 ASSERT(entry->IsNumber()); 5942 HandleScope scope(isolate); 5943 Handle<Object> entry_handle(entry, isolate); 5944 Handle<Object> entry_str = 5945 isolate->factory()->NumberToString(entry_handle); 5946 copy->set(i, *entry_str); 5947 } 5948 } 5949 return *isolate->factory()->NewJSArrayWithElements(copy); 5950 } 5951 5952 5953 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) { 5954 SealHandleScope shs(isolate); 5955 ASSERT(args.length() == 1); 5956 5957 // Compute the frame holding the arguments. 5958 JavaScriptFrameIterator it(isolate); 5959 it.AdvanceToArgumentsFrame(); 5960 JavaScriptFrame* frame = it.frame(); 5961 5962 // Get the actual number of provided arguments. 5963 const uint32_t n = frame->ComputeParametersCount(); 5964 5965 // Try to convert the key to an index. If successful and within 5966 // index return the the argument from the frame. 5967 uint32_t index; 5968 if (args[0]->ToArrayIndex(&index) && index < n) { 5969 return frame->GetParameter(index); 5970 } 5971 5972 if (args[0]->IsSymbol()) { 5973 // Lookup in the initial Object.prototype object. 5974 return isolate->initial_object_prototype()->GetProperty( 5975 Symbol::cast(args[0])); 5976 } 5977 5978 // Convert the key to a string. 5979 HandleScope scope(isolate); 5980 bool exception = false; 5981 Handle<Object> converted = 5982 Execution::ToString(isolate, args.at<Object>(0), &exception); 5983 if (exception) return Failure::Exception(); 5984 Handle<String> key = Handle<String>::cast(converted); 5985 5986 // Try to convert the string key into an array index. 5987 if (key->AsArrayIndex(&index)) { 5988 if (index < n) { 5989 return frame->GetParameter(index); 5990 } else { 5991 return isolate->initial_object_prototype()->GetElement(isolate, index); 5992 } 5993 } 5994 5995 // Handle special arguments properties. 5996 if (key->Equals(isolate->heap()->length_string())) return Smi::FromInt(n); 5997 if (key->Equals(isolate->heap()->callee_string())) { 5998 JSFunction* function = frame->function(); 5999 if (!function->shared()->is_classic_mode()) { 6000 return isolate->Throw(*isolate->factory()->NewTypeError( 6001 "strict_arguments_callee", HandleVector<Object>(NULL, 0))); 6002 } 6003 return function; 6004 } 6005 6006 // Lookup in the initial Object.prototype object. 6007 return isolate->initial_object_prototype()->GetProperty(*key); 6008 } 6009 6010 6011 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) { 6012 HandleScope scope(isolate); 6013 ASSERT(args.length() == 1); 6014 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 6015 if (object->IsJSObject() && !object->IsGlobalObject()) { 6016 JSObject::TransformToFastProperties(Handle<JSObject>::cast(object), 0); 6017 } 6018 return *object; 6019 } 6020 6021 6022 RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) { 6023 SealHandleScope shs(isolate); 6024 ASSERT(args.length() == 1); 6025 6026 return isolate->heap()->ToBoolean(args[0]->BooleanValue()); 6027 } 6028 6029 6030 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47). 6031 // Possible optimizations: put the type string into the oddballs. 6032 RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) { 6033 SealHandleScope shs(isolate); 6034 6035 Object* obj = args[0]; 6036 if (obj->IsNumber()) return isolate->heap()->number_string(); 6037 HeapObject* heap_obj = HeapObject::cast(obj); 6038 6039 // typeof an undetectable object is 'undefined' 6040 if (heap_obj->map()->is_undetectable()) { 6041 return isolate->heap()->undefined_string(); 6042 } 6043 6044 InstanceType instance_type = heap_obj->map()->instance_type(); 6045 if (instance_type < FIRST_NONSTRING_TYPE) { 6046 return isolate->heap()->string_string(); 6047 } 6048 6049 switch (instance_type) { 6050 case ODDBALL_TYPE: 6051 if (heap_obj->IsTrue() || heap_obj->IsFalse()) { 6052 return isolate->heap()->boolean_string(); 6053 } 6054 if (heap_obj->IsNull()) { 6055 return FLAG_harmony_typeof 6056 ? isolate->heap()->null_string() 6057 : isolate->heap()->object_string(); 6058 } 6059 ASSERT(heap_obj->IsUndefined()); 6060 return isolate->heap()->undefined_string(); 6061 case SYMBOL_TYPE: 6062 return isolate->heap()->symbol_string(); 6063 case JS_FUNCTION_TYPE: 6064 case JS_FUNCTION_PROXY_TYPE: 6065 return isolate->heap()->function_string(); 6066 default: 6067 // For any kind of object not handled above, the spec rule for 6068 // host objects gives that it is okay to return "object" 6069 return isolate->heap()->object_string(); 6070 } 6071 } 6072 6073 6074 static bool AreDigits(const uint8_t*s, int from, int to) { 6075 for (int i = from; i < to; i++) { 6076 if (s[i] < '0' || s[i] > '9') return false; 6077 } 6078 6079 return true; 6080 } 6081 6082 6083 static int ParseDecimalInteger(const uint8_t*s, int from, int to) { 6084 ASSERT(to - from < 10); // Overflow is not possible. 6085 ASSERT(from < to); 6086 int d = s[from] - '0'; 6087 6088 for (int i = from + 1; i < to; i++) { 6089 d = 10 * d + (s[i] - '0'); 6090 } 6091 6092 return d; 6093 } 6094 6095 6096 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { 6097 SealHandleScope shs(isolate); 6098 ASSERT(args.length() == 1); 6099 CONVERT_ARG_CHECKED(String, subject, 0); 6100 subject->TryFlatten(); 6101 6102 // Fast case: short integer or some sorts of junk values. 6103 int len = subject->length(); 6104 if (subject->IsSeqOneByteString()) { 6105 if (len == 0) return Smi::FromInt(0); 6106 6107 uint8_t const* data = SeqOneByteString::cast(subject)->GetChars(); 6108 bool minus = (data[0] == '-'); 6109 int start_pos = (minus ? 1 : 0); 6110 6111 if (start_pos == len) { 6112 return isolate->heap()->nan_value(); 6113 } else if (data[start_pos] > '9') { 6114 // Fast check for a junk value. A valid string may start from a 6115 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or 6116 // the 'I' character ('Infinity'). All of that have codes not greater than 6117 // '9' except 'I' and . 6118 if (data[start_pos] != 'I' && data[start_pos] != 0xa0) { 6119 return isolate->heap()->nan_value(); 6120 } 6121 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) { 6122 // The maximal/minimal smi has 10 digits. If the string has less digits we 6123 // know it will fit into the smi-data type. 6124 int d = ParseDecimalInteger(data, start_pos, len); 6125 if (minus) { 6126 if (d == 0) return isolate->heap()->minus_zero_value(); 6127 d = -d; 6128 } else if (!subject->HasHashCode() && 6129 len <= String::kMaxArrayIndexSize && 6130 (len == 1 || data[0] != '0')) { 6131 // String hash is not calculated yet but all the data are present. 6132 // Update the hash field to speed up sequential convertions. 6133 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len); 6134 #ifdef DEBUG 6135 subject->Hash(); // Force hash calculation. 6136 ASSERT_EQ(static_cast<int>(subject->hash_field()), 6137 static_cast<int>(hash)); 6138 #endif 6139 subject->set_hash_field(hash); 6140 } 6141 return Smi::FromInt(d); 6142 } 6143 } 6144 6145 // Slower case. 6146 int flags = ALLOW_HEX; 6147 if (FLAG_harmony_numeric_literals) { 6148 // The current spec draft has not updated "ToNumber Applied to the String 6149 // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 6150 flags |= ALLOW_OCTAL | ALLOW_BINARY; 6151 } 6152 return isolate->heap()->NumberFromDouble( 6153 StringToDouble(isolate->unicode_cache(), subject, flags)); 6154 } 6155 6156 6157 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewString) { 6158 SealHandleScope shs(isolate); 6159 CONVERT_SMI_ARG_CHECKED(length, 0); 6160 CONVERT_BOOLEAN_ARG_CHECKED(is_one_byte, 1); 6161 if (length == 0) return isolate->heap()->empty_string(); 6162 if (is_one_byte) { 6163 return isolate->heap()->AllocateRawOneByteString(length); 6164 } else { 6165 return isolate->heap()->AllocateRawTwoByteString(length); 6166 } 6167 } 6168 6169 6170 RUNTIME_FUNCTION(MaybeObject*, Runtime_TruncateString) { 6171 HandleScope scope(isolate); 6172 CONVERT_ARG_HANDLE_CHECKED(SeqString, string, 0); 6173 CONVERT_SMI_ARG_CHECKED(new_length, 1); 6174 return *SeqString::Truncate(string, new_length); 6175 } 6176 6177 6178 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) { 6179 HandleScope scope(isolate); 6180 ASSERT(args.length() == 1); 6181 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6182 Handle<String> string = FlattenGetString(source); 6183 ASSERT(string->IsFlat()); 6184 Handle<String> result = string->IsOneByteRepresentationUnderneath() 6185 ? URIEscape::Escape<uint8_t>(isolate, source) 6186 : URIEscape::Escape<uc16>(isolate, source); 6187 if (result.is_null()) return Failure::OutOfMemoryException(0x12); 6188 return *result; 6189 } 6190 6191 6192 RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) { 6193 HandleScope scope(isolate); 6194 ASSERT(args.length() == 1); 6195 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 6196 Handle<String> string = FlattenGetString(source); 6197 ASSERT(string->IsFlat()); 6198 return string->IsOneByteRepresentationUnderneath() 6199 ? *URIUnescape::Unescape<uint8_t>(isolate, source) 6200 : *URIUnescape::Unescape<uc16>(isolate, source); 6201 } 6202 6203 6204 RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) { 6205 HandleScope scope(isolate); 6206 CONVERT_ARG_HANDLE_CHECKED(String, string, 0); 6207 ASSERT(args.length() == 1); 6208 return BasicJsonStringifier::StringifyString(isolate, string); 6209 } 6210 6211 6212 RUNTIME_FUNCTION(MaybeObject*, Runtime_BasicJSONStringify) { 6213 HandleScope scope(isolate); 6214 ASSERT(args.length() == 1); 6215 BasicJsonStringifier stringifier(isolate); 6216 return stringifier.Stringify(Handle<Object>(args[0], isolate)); 6217 } 6218 6219 6220 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) { 6221 SealHandleScope shs(isolate); 6222 6223 CONVERT_ARG_CHECKED(String, s, 0); 6224 CONVERT_SMI_ARG_CHECKED(radix, 1); 6225 6226 s->TryFlatten(); 6227 6228 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36)); 6229 double value = StringToInt(isolate->unicode_cache(), s, radix); 6230 return isolate->heap()->NumberFromDouble(value); 6231 } 6232 6233 6234 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) { 6235 SealHandleScope shs(isolate); 6236 CONVERT_ARG_CHECKED(String, str, 0); 6237 6238 // ECMA-262 section 15.1.2.3, empty string is NaN 6239 double value = StringToDouble(isolate->unicode_cache(), 6240 str, ALLOW_TRAILING_JUNK, OS::nan_value()); 6241 6242 // Create a number object from the value. 6243 return isolate->heap()->NumberFromDouble(value); 6244 } 6245 6246 6247 template <class Converter> 6248 MUST_USE_RESULT static MaybeObject* ConvertCaseHelper( 6249 Isolate* isolate, 6250 String* s, 6251 String::Encoding result_encoding, 6252 int length, 6253 int input_string_length, 6254 unibrow::Mapping<Converter, 128>* mapping) { 6255 // We try this twice, once with the assumption that the result is no longer 6256 // than the input and, if that assumption breaks, again with the exact 6257 // length. This may not be pretty, but it is nicer than what was here before 6258 // and I hereby claim my vaffel-is. 6259 // 6260 // Allocate the resulting string. 6261 // 6262 // NOTE: This assumes that the upper/lower case of an ASCII 6263 // character is also ASCII. This is currently the case, but it 6264 // might break in the future if we implement more context and locale 6265 // dependent upper/lower conversions. 6266 Object* o; 6267 { MaybeObject* maybe_o = result_encoding == String::ONE_BYTE_ENCODING 6268 ? isolate->heap()->AllocateRawOneByteString(length) 6269 : isolate->heap()->AllocateRawTwoByteString(length); 6270 if (!maybe_o->ToObject(&o)) return maybe_o; 6271 } 6272 String* result = String::cast(o); 6273 bool has_changed_character = false; 6274 6275 DisallowHeapAllocation no_gc; 6276 6277 // Convert all characters to upper case, assuming that they will fit 6278 // in the buffer 6279 Access<ConsStringIteratorOp> op( 6280 isolate->runtime_state()->string_iterator()); 6281 StringCharacterStream stream(s, op.value()); 6282 unibrow::uchar chars[Converter::kMaxWidth]; 6283 // We can assume that the string is not empty 6284 uc32 current = stream.GetNext(); 6285 // y with umlauts is the only character that stops fitting into one-byte 6286 // when converting to uppercase. 6287 static const uc32 yuml_code = 0xff; 6288 bool ignore_yuml = result->IsSeqTwoByteString() || Converter::kIsToLower; 6289 for (int i = 0; i < length;) { 6290 bool has_next = stream.HasMore(); 6291 uc32 next = has_next ? stream.GetNext() : 0; 6292 int char_length = mapping->get(current, next, chars); 6293 if (char_length == 0) { 6294 // The case conversion of this character is the character itself. 6295 result->Set(i, current); 6296 i++; 6297 } else if (char_length == 1 && (ignore_yuml || current != yuml_code)) { 6298 // Common case: converting the letter resulted in one character. 6299 ASSERT(static_cast<uc32>(chars[0]) != current); 6300 result->Set(i, chars[0]); 6301 has_changed_character = true; 6302 i++; 6303 } else if (length == input_string_length) { 6304 bool found_yuml = (current == yuml_code); 6305 // We've assumed that the result would be as long as the 6306 // input but here is a character that converts to several 6307 // characters. No matter, we calculate the exact length 6308 // of the result and try the whole thing again. 6309 // 6310 // Note that this leaves room for optimization. We could just 6311 // memcpy what we already have to the result string. Also, 6312 // the result string is the last object allocated we could 6313 // "realloc" it and probably, in the vast majority of cases, 6314 // extend the existing string to be able to hold the full 6315 // result. 6316 int next_length = 0; 6317 if (has_next) { 6318 next_length = mapping->get(next, 0, chars); 6319 if (next_length == 0) next_length = 1; 6320 } 6321 int current_length = i + char_length + next_length; 6322 while (stream.HasMore()) { 6323 current = stream.GetNext(); 6324 found_yuml |= (current == yuml_code); 6325 // NOTE: we use 0 as the next character here because, while 6326 // the next character may affect what a character converts to, 6327 // it does not in any case affect the length of what it convert 6328 // to. 6329 int char_length = mapping->get(current, 0, chars); 6330 if (char_length == 0) char_length = 1; 6331 current_length += char_length; 6332 if (current_length > Smi::kMaxValue) { 6333 isolate->context()->mark_out_of_memory(); 6334 return Failure::OutOfMemoryException(0x13); 6335 } 6336 } 6337 // Try again with the real length. Return signed if we need 6338 // to allocate a two-byte string for y-umlaut to uppercase. 6339 return (found_yuml && !ignore_yuml) ? Smi::FromInt(-current_length) 6340 : Smi::FromInt(current_length); 6341 } else { 6342 for (int j = 0; j < char_length; j++) { 6343 result->Set(i, chars[j]); 6344 i++; 6345 } 6346 has_changed_character = true; 6347 } 6348 current = next; 6349 } 6350 if (has_changed_character) { 6351 return result; 6352 } else { 6353 // If we didn't actually change anything in doing the conversion 6354 // we simple return the result and let the converted string 6355 // become garbage; there is no reason to keep two identical strings 6356 // alive. 6357 return s; 6358 } 6359 } 6360 6361 6362 namespace { 6363 6364 static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF; 6365 static const uintptr_t kAsciiMask = kOneInEveryByte << 7; 6366 6367 // Given a word and two range boundaries returns a word with high bit 6368 // set in every byte iff the corresponding input byte was strictly in 6369 // the range (m, n). All the other bits in the result are cleared. 6370 // This function is only useful when it can be inlined and the 6371 // boundaries are statically known. 6372 // Requires: all bytes in the input word and the boundaries must be 6373 // ASCII (less than 0x7F). 6374 static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) { 6375 // Use strict inequalities since in edge cases the function could be 6376 // further simplified. 6377 ASSERT(0 < m && m < n); 6378 // Has high bit set in every w byte less than n. 6379 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w; 6380 // Has high bit set in every w byte greater than m. 6381 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m); 6382 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80)); 6383 } 6384 6385 6386 #ifdef DEBUG 6387 static bool CheckFastAsciiConvert(char* dst, 6388 char* src, 6389 int length, 6390 bool changed, 6391 bool is_to_lower) { 6392 bool expected_changed = false; 6393 for (int i = 0; i < length; i++) { 6394 if (dst[i] == src[i]) continue; 6395 expected_changed = true; 6396 if (is_to_lower) { 6397 ASSERT('A' <= src[i] && src[i] <= 'Z'); 6398 ASSERT(dst[i] == src[i] + ('a' - 'A')); 6399 } else { 6400 ASSERT('a' <= src[i] && src[i] <= 'z'); 6401 ASSERT(dst[i] == src[i] - ('a' - 'A')); 6402 } 6403 } 6404 return (expected_changed == changed); 6405 } 6406 #endif 6407 6408 6409 template<class Converter> 6410 static bool FastAsciiConvert(char* dst, 6411 char* src, 6412 int length, 6413 bool* changed_out) { 6414 #ifdef DEBUG 6415 char* saved_dst = dst; 6416 char* saved_src = src; 6417 #endif 6418 DisallowHeapAllocation no_gc; 6419 // We rely on the distance between upper and lower case letters 6420 // being a known power of 2. 6421 ASSERT('a' - 'A' == (1 << 5)); 6422 // Boundaries for the range of input characters than require conversion. 6423 static const char lo = Converter::kIsToLower ? 'A' - 1 : 'a' - 1; 6424 static const char hi = Converter::kIsToLower ? 'Z' + 1 : 'z' + 1; 6425 bool changed = false; 6426 uintptr_t or_acc = 0; 6427 char* const limit = src + length; 6428 #ifdef V8_HOST_CAN_READ_UNALIGNED 6429 // Process the prefix of the input that requires no conversion one 6430 // (machine) word at a time. 6431 while (src <= limit - sizeof(uintptr_t)) { 6432 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6433 or_acc |= w; 6434 if (AsciiRangeMask(w, lo, hi) != 0) { 6435 changed = true; 6436 break; 6437 } 6438 *reinterpret_cast<uintptr_t*>(dst) = w; 6439 src += sizeof(uintptr_t); 6440 dst += sizeof(uintptr_t); 6441 } 6442 // Process the remainder of the input performing conversion when 6443 // required one word at a time. 6444 while (src <= limit - sizeof(uintptr_t)) { 6445 uintptr_t w = *reinterpret_cast<uintptr_t*>(src); 6446 or_acc |= w; 6447 uintptr_t m = AsciiRangeMask(w, lo, hi); 6448 // The mask has high (7th) bit set in every byte that needs 6449 // conversion and we know that the distance between cases is 6450 // 1 << 5. 6451 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2); 6452 src += sizeof(uintptr_t); 6453 dst += sizeof(uintptr_t); 6454 } 6455 #endif 6456 // Process the last few bytes of the input (or the whole input if 6457 // unaligned access is not supported). 6458 while (src < limit) { 6459 char c = *src; 6460 or_acc |= c; 6461 if (lo < c && c < hi) { 6462 c ^= (1 << 5); 6463 changed = true; 6464 } 6465 *dst = c; 6466 ++src; 6467 ++dst; 6468 } 6469 if ((or_acc & kAsciiMask) != 0) { 6470 return false; 6471 } 6472 6473 ASSERT(CheckFastAsciiConvert( 6474 saved_dst, saved_src, length, changed, Converter::kIsToLower)); 6475 6476 *changed_out = changed; 6477 return true; 6478 } 6479 6480 } // namespace 6481 6482 6483 template <class Converter> 6484 MUST_USE_RESULT static MaybeObject* ConvertCase( 6485 Arguments args, 6486 Isolate* isolate, 6487 unibrow::Mapping<Converter, 128>* mapping) { 6488 SealHandleScope shs(isolate); 6489 CONVERT_ARG_CHECKED(String, s, 0); 6490 s = s->TryFlattenGetString(); 6491 6492 const int length = s->length(); 6493 // Assume that the string is not empty; we need this assumption later 6494 if (length == 0) return s; 6495 6496 // Simpler handling of ASCII strings. 6497 // 6498 // NOTE: This assumes that the upper/lower case of an ASCII 6499 // character is also ASCII. This is currently the case, but it 6500 // might break in the future if we implement more context and locale 6501 // dependent upper/lower conversions. 6502 if (s->IsSeqOneByteString()) { 6503 Object* o; 6504 { MaybeObject* maybe_o = isolate->heap()->AllocateRawOneByteString(length); 6505 if (!maybe_o->ToObject(&o)) return maybe_o; 6506 } 6507 SeqOneByteString* result = SeqOneByteString::cast(o); 6508 bool has_changed_character; 6509 bool is_ascii = FastAsciiConvert<Converter>( 6510 reinterpret_cast<char*>(result->GetChars()), 6511 reinterpret_cast<char*>(SeqOneByteString::cast(s)->GetChars()), 6512 length, 6513 &has_changed_character); 6514 // If not ASCII, we discard the result and take the 2 byte path. 6515 if (is_ascii) { 6516 return has_changed_character ? result : s; 6517 } 6518 } 6519 6520 String::Encoding result_encoding = s->IsOneByteRepresentation() 6521 ? String::ONE_BYTE_ENCODING : String::TWO_BYTE_ENCODING; 6522 Object* answer; 6523 { MaybeObject* maybe_answer = ConvertCaseHelper( 6524 isolate, s, result_encoding, length, length, mapping); 6525 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6526 } 6527 if (answer->IsSmi()) { 6528 int new_length = Smi::cast(answer)->value(); 6529 if (new_length < 0) { 6530 result_encoding = String::TWO_BYTE_ENCODING; 6531 new_length = -new_length; 6532 } 6533 MaybeObject* maybe_answer = ConvertCaseHelper( 6534 isolate, s, result_encoding, new_length, length, mapping); 6535 if (!maybe_answer->ToObject(&answer)) return maybe_answer; 6536 } 6537 return answer; 6538 } 6539 6540 6541 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) { 6542 return ConvertCase( 6543 args, isolate, isolate->runtime_state()->to_lower_mapping()); 6544 } 6545 6546 6547 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) { 6548 return ConvertCase( 6549 args, isolate, isolate->runtime_state()->to_upper_mapping()); 6550 } 6551 6552 6553 static inline bool IsTrimWhiteSpace(unibrow::uchar c) { 6554 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff; 6555 } 6556 6557 6558 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) { 6559 SealHandleScope shs(isolate); 6560 ASSERT(args.length() == 3); 6561 6562 CONVERT_ARG_CHECKED(String, s, 0); 6563 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1); 6564 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2); 6565 6566 s->TryFlatten(); 6567 int length = s->length(); 6568 6569 int left = 0; 6570 if (trimLeft) { 6571 while (left < length && IsTrimWhiteSpace(s->Get(left))) { 6572 left++; 6573 } 6574 } 6575 6576 int right = length; 6577 if (trimRight) { 6578 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) { 6579 right--; 6580 } 6581 } 6582 return s->SubString(left, right); 6583 } 6584 6585 6586 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) { 6587 HandleScope handle_scope(isolate); 6588 ASSERT(args.length() == 3); 6589 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0); 6590 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1); 6591 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]); 6592 6593 int subject_length = subject->length(); 6594 int pattern_length = pattern->length(); 6595 RUNTIME_ASSERT(pattern_length > 0); 6596 6597 if (limit == 0xffffffffu) { 6598 Handle<Object> cached_answer( 6599 RegExpResultsCache::Lookup(isolate->heap(), 6600 *subject, 6601 *pattern, 6602 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS), 6603 isolate); 6604 if (*cached_answer != Smi::FromInt(0)) { 6605 // The cache FixedArray is a COW-array and can therefore be reused. 6606 Handle<JSArray> result = 6607 isolate->factory()->NewJSArrayWithElements( 6608 Handle<FixedArray>::cast(cached_answer)); 6609 return *result; 6610 } 6611 } 6612 6613 // The limit can be very large (0xffffffffu), but since the pattern 6614 // isn't empty, we can never create more parts than ~half the length 6615 // of the subject. 6616 6617 if (!subject->IsFlat()) FlattenString(subject); 6618 6619 static const int kMaxInitialListCapacity = 16; 6620 6621 ZoneScope zone_scope(isolate->runtime_zone()); 6622 6623 // Find (up to limit) indices of separator and end-of-string in subject 6624 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit); 6625 ZoneList<int> indices(initial_capacity, zone_scope.zone()); 6626 if (!pattern->IsFlat()) FlattenString(pattern); 6627 6628 FindStringIndicesDispatch(isolate, *subject, *pattern, 6629 &indices, limit, zone_scope.zone()); 6630 6631 if (static_cast<uint32_t>(indices.length()) < limit) { 6632 indices.Add(subject_length, zone_scope.zone()); 6633 } 6634 6635 // The list indices now contains the end of each part to create. 6636 6637 // Create JSArray of substrings separated by separator. 6638 int part_count = indices.length(); 6639 6640 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count); 6641 JSObject::EnsureCanContainHeapObjectElements(result); 6642 result->set_length(Smi::FromInt(part_count)); 6643 6644 ASSERT(result->HasFastObjectElements()); 6645 6646 if (part_count == 1 && indices.at(0) == subject_length) { 6647 FixedArray::cast(result->elements())->set(0, *subject); 6648 return *result; 6649 } 6650 6651 Handle<FixedArray> elements(FixedArray::cast(result->elements())); 6652 int part_start = 0; 6653 for (int i = 0; i < part_count; i++) { 6654 HandleScope local_loop_handle(isolate); 6655 int part_end = indices.at(i); 6656 Handle<String> substring = 6657 isolate->factory()->NewProperSubString(subject, part_start, part_end); 6658 elements->set(i, *substring); 6659 part_start = part_end + pattern_length; 6660 } 6661 6662 if (limit == 0xffffffffu) { 6663 if (result->HasFastObjectElements()) { 6664 RegExpResultsCache::Enter(isolate->heap(), 6665 *subject, 6666 *pattern, 6667 *elements, 6668 RegExpResultsCache::STRING_SPLIT_SUBSTRINGS); 6669 } 6670 } 6671 6672 return *result; 6673 } 6674 6675 6676 // Copies ASCII characters to the given fixed array looking up 6677 // one-char strings in the cache. Gives up on the first char that is 6678 // not in the cache and fills the remainder with smi zeros. Returns 6679 // the length of the successfully copied prefix. 6680 static int CopyCachedAsciiCharsToArray(Heap* heap, 6681 const uint8_t* chars, 6682 FixedArray* elements, 6683 int length) { 6684 DisallowHeapAllocation no_gc; 6685 FixedArray* ascii_cache = heap->single_character_string_cache(); 6686 Object* undefined = heap->undefined_value(); 6687 int i; 6688 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc); 6689 for (i = 0; i < length; ++i) { 6690 Object* value = ascii_cache->get(chars[i]); 6691 if (value == undefined) break; 6692 elements->set(i, value, mode); 6693 } 6694 if (i < length) { 6695 ASSERT(Smi::FromInt(0) == 0); 6696 memset(elements->data_start() + i, 0, kPointerSize * (length - i)); 6697 } 6698 #ifdef DEBUG 6699 for (int j = 0; j < length; ++j) { 6700 Object* element = elements->get(j); 6701 ASSERT(element == Smi::FromInt(0) || 6702 (element->IsString() && String::cast(element)->LooksValid())); 6703 } 6704 #endif 6705 return i; 6706 } 6707 6708 6709 // Converts a String to JSArray. 6710 // For example, "foo" => ["f", "o", "o"]. 6711 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) { 6712 HandleScope scope(isolate); 6713 ASSERT(args.length() == 2); 6714 CONVERT_ARG_HANDLE_CHECKED(String, s, 0); 6715 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 6716 6717 s = FlattenGetString(s); 6718 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit)); 6719 6720 Handle<FixedArray> elements; 6721 int position = 0; 6722 if (s->IsFlat() && s->IsOneByteRepresentation()) { 6723 // Try using cached chars where possible. 6724 Object* obj; 6725 { MaybeObject* maybe_obj = 6726 isolate->heap()->AllocateUninitializedFixedArray(length); 6727 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 6728 } 6729 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate); 6730 DisallowHeapAllocation no_gc; 6731 String::FlatContent content = s->GetFlatContent(); 6732 if (content.IsAscii()) { 6733 Vector<const uint8_t> chars = content.ToOneByteVector(); 6734 // Note, this will initialize all elements (not only the prefix) 6735 // to prevent GC from seeing partially initialized array. 6736 position = CopyCachedAsciiCharsToArray(isolate->heap(), 6737 chars.start(), 6738 *elements, 6739 length); 6740 } else { 6741 MemsetPointer(elements->data_start(), 6742 isolate->heap()->undefined_value(), 6743 length); 6744 } 6745 } else { 6746 elements = isolate->factory()->NewFixedArray(length); 6747 } 6748 for (int i = position; i < length; ++i) { 6749 Handle<Object> str = 6750 LookupSingleCharacterStringFromCode(isolate, s->Get(i)); 6751 elements->set(i, *str); 6752 } 6753 6754 #ifdef DEBUG 6755 for (int i = 0; i < length; ++i) { 6756 ASSERT(String::cast(elements->get(i))->length() == 1); 6757 } 6758 #endif 6759 6760 return *isolate->factory()->NewJSArrayWithElements(elements); 6761 } 6762 6763 6764 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) { 6765 SealHandleScope shs(isolate); 6766 ASSERT(args.length() == 1); 6767 CONVERT_ARG_CHECKED(String, value, 0); 6768 return value->ToObject(isolate); 6769 } 6770 6771 6772 bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) { 6773 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth]; 6774 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars); 6775 return char_length == 0; 6776 } 6777 6778 6779 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) { 6780 SealHandleScope shs(isolate); 6781 ASSERT(args.length() == 1); 6782 6783 Object* number = args[0]; 6784 RUNTIME_ASSERT(number->IsNumber()); 6785 6786 return isolate->heap()->NumberToString(number); 6787 } 6788 6789 6790 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) { 6791 SealHandleScope shs(isolate); 6792 ASSERT(args.length() == 1); 6793 6794 Object* number = args[0]; 6795 RUNTIME_ASSERT(number->IsNumber()); 6796 6797 return isolate->heap()->NumberToString( 6798 number, false, isolate->heap()->GetPretenureMode()); 6799 } 6800 6801 6802 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { 6803 SealHandleScope shs(isolate); 6804 ASSERT(args.length() == 1); 6805 6806 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6807 6808 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6809 if (number > 0 && number <= Smi::kMaxValue) { 6810 return Smi::FromInt(static_cast<int>(number)); 6811 } 6812 return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); 6813 } 6814 6815 6816 // ES6 draft 9.1.11 6817 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) { 6818 SealHandleScope shs(isolate); 6819 ASSERT(args.length() == 1); 6820 6821 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6822 6823 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6824 if (number > 0 && number <= Smi::kMaxValue) { 6825 return Smi::FromInt(static_cast<int>(number)); 6826 } 6827 if (number <= 0) { 6828 return Smi::FromInt(0); 6829 } 6830 return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); 6831 } 6832 6833 6834 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { 6835 SealHandleScope shs(isolate); 6836 ASSERT(args.length() == 1); 6837 6838 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6839 6840 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6841 if (number > 0 && number <= Smi::kMaxValue) { 6842 return Smi::FromInt(static_cast<int>(number)); 6843 } 6844 6845 double double_value = DoubleToInteger(number); 6846 // Map both -0 and +0 to +0. 6847 if (double_value == 0) double_value = 0; 6848 6849 return isolate->heap()->NumberFromDouble(double_value); 6850 } 6851 6852 6853 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) { 6854 SealHandleScope shs(isolate); 6855 ASSERT(args.length() == 1); 6856 6857 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]); 6858 return isolate->heap()->NumberFromUint32(number); 6859 } 6860 6861 6862 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) { 6863 SealHandleScope shs(isolate); 6864 ASSERT(args.length() == 1); 6865 6866 CONVERT_DOUBLE_ARG_CHECKED(number, 0); 6867 6868 // We do not include 0 so that we don't have to treat +0 / -0 cases. 6869 if (number > 0 && number <= Smi::kMaxValue) { 6870 return Smi::FromInt(static_cast<int>(number)); 6871 } 6872 return isolate->heap()->NumberFromInt32(DoubleToInt32(number)); 6873 } 6874 6875 6876 // Converts a Number to a Smi, if possible. Returns NaN if the number is not 6877 // a small integer. 6878 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) { 6879 SealHandleScope shs(isolate); 6880 ASSERT(args.length() == 1); 6881 6882 Object* obj = args[0]; 6883 if (obj->IsSmi()) { 6884 return obj; 6885 } 6886 if (obj->IsHeapNumber()) { 6887 double value = HeapNumber::cast(obj)->value(); 6888 int int_value = FastD2I(value); 6889 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) { 6890 return Smi::FromInt(int_value); 6891 } 6892 } 6893 return isolate->heap()->nan_value(); 6894 } 6895 6896 6897 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) { 6898 SealHandleScope shs(isolate); 6899 ASSERT(args.length() == 0); 6900 return isolate->heap()->AllocateHeapNumber(0); 6901 } 6902 6903 6904 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) { 6905 SealHandleScope shs(isolate); 6906 ASSERT(args.length() == 2); 6907 6908 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6909 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6910 return isolate->heap()->NumberFromDouble(x + y); 6911 } 6912 6913 6914 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) { 6915 SealHandleScope shs(isolate); 6916 ASSERT(args.length() == 2); 6917 6918 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6919 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6920 return isolate->heap()->NumberFromDouble(x - y); 6921 } 6922 6923 6924 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) { 6925 SealHandleScope shs(isolate); 6926 ASSERT(args.length() == 2); 6927 6928 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6929 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6930 return isolate->heap()->NumberFromDouble(x * y); 6931 } 6932 6933 6934 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) { 6935 SealHandleScope shs(isolate); 6936 ASSERT(args.length() == 1); 6937 6938 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6939 return isolate->heap()->NumberFromDouble(-x); 6940 } 6941 6942 6943 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) { 6944 SealHandleScope shs(isolate); 6945 ASSERT(args.length() == 0); 6946 6947 return isolate->heap()->NumberFromDouble(9876543210.0); 6948 } 6949 6950 6951 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) { 6952 SealHandleScope shs(isolate); 6953 ASSERT(args.length() == 2); 6954 6955 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6956 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6957 return isolate->heap()->NumberFromDouble(x / y); 6958 } 6959 6960 6961 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) { 6962 SealHandleScope shs(isolate); 6963 ASSERT(args.length() == 2); 6964 6965 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 6966 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 6967 6968 x = modulo(x, y); 6969 // NumberFromDouble may return a Smi instead of a Number object 6970 return isolate->heap()->NumberFromDouble(x); 6971 } 6972 6973 6974 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberImul) { 6975 SealHandleScope shs(isolate); 6976 ASSERT(args.length() == 2); 6977 6978 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 6979 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 6980 return isolate->heap()->NumberFromInt32(x * y); 6981 } 6982 6983 6984 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) { 6985 SealHandleScope shs(isolate); 6986 ASSERT(args.length() == 2); 6987 CONVERT_ARG_CHECKED(String, str1, 0); 6988 CONVERT_ARG_CHECKED(String, str2, 1); 6989 isolate->counters()->string_add_runtime()->Increment(); 6990 return isolate->heap()->AllocateConsString(str1, str2); 6991 } 6992 6993 6994 template <typename sinkchar> 6995 static inline void StringBuilderConcatHelper(String* special, 6996 sinkchar* sink, 6997 FixedArray* fixed_array, 6998 int array_length) { 6999 int position = 0; 7000 for (int i = 0; i < array_length; i++) { 7001 Object* element = fixed_array->get(i); 7002 if (element->IsSmi()) { 7003 // Smi encoding of position and length. 7004 int encoded_slice = Smi::cast(element)->value(); 7005 int pos; 7006 int len; 7007 if (encoded_slice > 0) { 7008 // Position and length encoded in one smi. 7009 pos = StringBuilderSubstringPosition::decode(encoded_slice); 7010 len = StringBuilderSubstringLength::decode(encoded_slice); 7011 } else { 7012 // Position and length encoded in two smis. 7013 Object* obj = fixed_array->get(++i); 7014 ASSERT(obj->IsSmi()); 7015 pos = Smi::cast(obj)->value(); 7016 len = -encoded_slice; 7017 } 7018 String::WriteToFlat(special, 7019 sink + position, 7020 pos, 7021 pos + len); 7022 position += len; 7023 } else { 7024 String* string = String::cast(element); 7025 int element_length = string->length(); 7026 String::WriteToFlat(string, sink + position, 0, element_length); 7027 position += element_length; 7028 } 7029 } 7030 } 7031 7032 7033 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) { 7034 HandleScope scope(isolate); 7035 ASSERT(args.length() == 3); 7036 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 7037 if (!args[1]->IsSmi()) { 7038 isolate->context()->mark_out_of_memory(); 7039 return Failure::OutOfMemoryException(0x14); 7040 } 7041 int array_length = args.smi_at(1); 7042 CONVERT_ARG_HANDLE_CHECKED(String, special, 2); 7043 7044 // This assumption is used by the slice encoding in one or two smis. 7045 ASSERT(Smi::kMaxValue >= String::kMaxLength); 7046 7047 JSObject::EnsureCanContainHeapObjectElements(array); 7048 7049 int special_length = special->length(); 7050 if (!array->HasFastObjectElements()) { 7051 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7052 } 7053 FixedArray* fixed_array = FixedArray::cast(array->elements()); 7054 if (fixed_array->length() < array_length) { 7055 array_length = fixed_array->length(); 7056 } 7057 7058 if (array_length == 0) { 7059 return isolate->heap()->empty_string(); 7060 } else if (array_length == 1) { 7061 Object* first = fixed_array->get(0); 7062 if (first->IsString()) return first; 7063 } 7064 7065 bool one_byte = special->HasOnlyOneByteChars(); 7066 int position = 0; 7067 for (int i = 0; i < array_length; i++) { 7068 int increment = 0; 7069 Object* elt = fixed_array->get(i); 7070 if (elt->IsSmi()) { 7071 // Smi encoding of position and length. 7072 int smi_value = Smi::cast(elt)->value(); 7073 int pos; 7074 int len; 7075 if (smi_value > 0) { 7076 // Position and length encoded in one smi. 7077 pos = StringBuilderSubstringPosition::decode(smi_value); 7078 len = StringBuilderSubstringLength::decode(smi_value); 7079 } else { 7080 // Position and length encoded in two smis. 7081 len = -smi_value; 7082 // Get the position and check that it is a positive smi. 7083 i++; 7084 if (i >= array_length) { 7085 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7086 } 7087 Object* next_smi = fixed_array->get(i); 7088 if (!next_smi->IsSmi()) { 7089 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7090 } 7091 pos = Smi::cast(next_smi)->value(); 7092 if (pos < 0) { 7093 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7094 } 7095 } 7096 ASSERT(pos >= 0); 7097 ASSERT(len >= 0); 7098 if (pos > special_length || len > special_length - pos) { 7099 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7100 } 7101 increment = len; 7102 } else if (elt->IsString()) { 7103 String* element = String::cast(elt); 7104 int element_length = element->length(); 7105 increment = element_length; 7106 if (one_byte && !element->HasOnlyOneByteChars()) { 7107 one_byte = false; 7108 } 7109 } else { 7110 ASSERT(!elt->IsTheHole()); 7111 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7112 } 7113 if (increment > String::kMaxLength - position) { 7114 isolate->context()->mark_out_of_memory(); 7115 return Failure::OutOfMemoryException(0x15); 7116 } 7117 position += increment; 7118 } 7119 7120 int length = position; 7121 Object* object; 7122 7123 if (one_byte) { 7124 { MaybeObject* maybe_object = 7125 isolate->heap()->AllocateRawOneByteString(length); 7126 if (!maybe_object->ToObject(&object)) return maybe_object; 7127 } 7128 SeqOneByteString* answer = SeqOneByteString::cast(object); 7129 StringBuilderConcatHelper(*special, 7130 answer->GetChars(), 7131 fixed_array, 7132 array_length); 7133 return answer; 7134 } else { 7135 { MaybeObject* maybe_object = 7136 isolate->heap()->AllocateRawTwoByteString(length); 7137 if (!maybe_object->ToObject(&object)) return maybe_object; 7138 } 7139 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 7140 StringBuilderConcatHelper(*special, 7141 answer->GetChars(), 7142 fixed_array, 7143 array_length); 7144 return answer; 7145 } 7146 } 7147 7148 7149 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) { 7150 SealHandleScope shs(isolate); 7151 ASSERT(args.length() == 3); 7152 CONVERT_ARG_CHECKED(JSArray, array, 0); 7153 if (!args[1]->IsSmi()) { 7154 isolate->context()->mark_out_of_memory(); 7155 return Failure::OutOfMemoryException(0x16); 7156 } 7157 int array_length = args.smi_at(1); 7158 CONVERT_ARG_CHECKED(String, separator, 2); 7159 7160 if (!array->HasFastObjectElements()) { 7161 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7162 } 7163 FixedArray* fixed_array = FixedArray::cast(array->elements()); 7164 if (fixed_array->length() < array_length) { 7165 array_length = fixed_array->length(); 7166 } 7167 7168 if (array_length == 0) { 7169 return isolate->heap()->empty_string(); 7170 } else if (array_length == 1) { 7171 Object* first = fixed_array->get(0); 7172 if (first->IsString()) return first; 7173 } 7174 7175 int separator_length = separator->length(); 7176 int max_nof_separators = 7177 (String::kMaxLength + separator_length - 1) / separator_length; 7178 if (max_nof_separators < (array_length - 1)) { 7179 isolate->context()->mark_out_of_memory(); 7180 return Failure::OutOfMemoryException(0x17); 7181 } 7182 int length = (array_length - 1) * separator_length; 7183 for (int i = 0; i < array_length; i++) { 7184 Object* element_obj = fixed_array->get(i); 7185 if (!element_obj->IsString()) { 7186 // TODO(1161): handle this case. 7187 return isolate->Throw(isolate->heap()->illegal_argument_string()); 7188 } 7189 String* element = String::cast(element_obj); 7190 int increment = element->length(); 7191 if (increment > String::kMaxLength - length) { 7192 isolate->context()->mark_out_of_memory(); 7193 return Failure::OutOfMemoryException(0x18); 7194 } 7195 length += increment; 7196 } 7197 7198 Object* object; 7199 { MaybeObject* maybe_object = 7200 isolate->heap()->AllocateRawTwoByteString(length); 7201 if (!maybe_object->ToObject(&object)) return maybe_object; 7202 } 7203 SeqTwoByteString* answer = SeqTwoByteString::cast(object); 7204 7205 uc16* sink = answer->GetChars(); 7206 #ifdef DEBUG 7207 uc16* end = sink + length; 7208 #endif 7209 7210 String* first = String::cast(fixed_array->get(0)); 7211 int first_length = first->length(); 7212 String::WriteToFlat(first, sink, 0, first_length); 7213 sink += first_length; 7214 7215 for (int i = 1; i < array_length; i++) { 7216 ASSERT(sink + separator_length <= end); 7217 String::WriteToFlat(separator, sink, 0, separator_length); 7218 sink += separator_length; 7219 7220 String* element = String::cast(fixed_array->get(i)); 7221 int element_length = element->length(); 7222 ASSERT(sink + element_length <= end); 7223 String::WriteToFlat(element, sink, 0, element_length); 7224 sink += element_length; 7225 } 7226 ASSERT(sink == end); 7227 7228 // Use %_FastAsciiArrayJoin instead. 7229 ASSERT(!answer->IsOneByteRepresentation()); 7230 return answer; 7231 } 7232 7233 template <typename Char> 7234 static void JoinSparseArrayWithSeparator(FixedArray* elements, 7235 int elements_length, 7236 uint32_t array_length, 7237 String* separator, 7238 Vector<Char> buffer) { 7239 int previous_separator_position = 0; 7240 int separator_length = separator->length(); 7241 int cursor = 0; 7242 for (int i = 0; i < elements_length; i += 2) { 7243 int position = NumberToInt32(elements->get(i)); 7244 String* string = String::cast(elements->get(i + 1)); 7245 int string_length = string->length(); 7246 if (string->length() > 0) { 7247 while (previous_separator_position < position) { 7248 String::WriteToFlat<Char>(separator, &buffer[cursor], 7249 0, separator_length); 7250 cursor += separator_length; 7251 previous_separator_position++; 7252 } 7253 String::WriteToFlat<Char>(string, &buffer[cursor], 7254 0, string_length); 7255 cursor += string->length(); 7256 } 7257 } 7258 if (separator_length > 0) { 7259 // Array length must be representable as a signed 32-bit number, 7260 // otherwise the total string length would have been too large. 7261 ASSERT(array_length <= 0x7fffffff); // Is int32_t. 7262 int last_array_index = static_cast<int>(array_length - 1); 7263 while (previous_separator_position < last_array_index) { 7264 String::WriteToFlat<Char>(separator, &buffer[cursor], 7265 0, separator_length); 7266 cursor += separator_length; 7267 previous_separator_position++; 7268 } 7269 } 7270 ASSERT(cursor <= buffer.length()); 7271 } 7272 7273 7274 RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) { 7275 SealHandleScope shs(isolate); 7276 ASSERT(args.length() == 3); 7277 CONVERT_ARG_CHECKED(JSArray, elements_array, 0); 7278 RUNTIME_ASSERT(elements_array->HasFastSmiOrObjectElements()); 7279 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]); 7280 CONVERT_ARG_CHECKED(String, separator, 2); 7281 // elements_array is fast-mode JSarray of alternating positions 7282 // (increasing order) and strings. 7283 // array_length is length of original array (used to add separators); 7284 // separator is string to put between elements. Assumed to be non-empty. 7285 7286 // Find total length of join result. 7287 int string_length = 0; 7288 bool is_ascii = separator->IsOneByteRepresentation(); 7289 int max_string_length; 7290 if (is_ascii) { 7291 max_string_length = SeqOneByteString::kMaxLength; 7292 } else { 7293 max_string_length = SeqTwoByteString::kMaxLength; 7294 } 7295 bool overflow = false; 7296 CONVERT_NUMBER_CHECKED(int, elements_length, 7297 Int32, elements_array->length()); 7298 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length. 7299 FixedArray* elements = FixedArray::cast(elements_array->elements()); 7300 for (int i = 0; i < elements_length; i += 2) { 7301 RUNTIME_ASSERT(elements->get(i)->IsNumber()); 7302 RUNTIME_ASSERT(elements->get(i + 1)->IsString()); 7303 String* string = String::cast(elements->get(i + 1)); 7304 int length = string->length(); 7305 if (is_ascii && !string->IsOneByteRepresentation()) { 7306 is_ascii = false; 7307 max_string_length = SeqTwoByteString::kMaxLength; 7308 } 7309 if (length > max_string_length || 7310 max_string_length - length < string_length) { 7311 overflow = true; 7312 break; 7313 } 7314 string_length += length; 7315 } 7316 int separator_length = separator->length(); 7317 if (!overflow && separator_length > 0) { 7318 if (array_length <= 0x7fffffffu) { 7319 int separator_count = static_cast<int>(array_length) - 1; 7320 int remaining_length = max_string_length - string_length; 7321 if ((remaining_length / separator_length) >= separator_count) { 7322 string_length += separator_length * (array_length - 1); 7323 } else { 7324 // Not room for the separators within the maximal string length. 7325 overflow = true; 7326 } 7327 } else { 7328 // Nonempty separator and at least 2^31-1 separators necessary 7329 // means that the string is too large to create. 7330 STATIC_ASSERT(String::kMaxLength < 0x7fffffff); 7331 overflow = true; 7332 } 7333 } 7334 if (overflow) { 7335 // Throw OutOfMemory exception for creating too large a string. 7336 V8::FatalProcessOutOfMemory("Array join result too large."); 7337 } 7338 7339 if (is_ascii) { 7340 MaybeObject* result_allocation = 7341 isolate->heap()->AllocateRawOneByteString(string_length); 7342 if (result_allocation->IsFailure()) return result_allocation; 7343 SeqOneByteString* result_string = 7344 SeqOneByteString::cast(result_allocation->ToObjectUnchecked()); 7345 JoinSparseArrayWithSeparator<uint8_t>(elements, 7346 elements_length, 7347 array_length, 7348 separator, 7349 Vector<uint8_t>( 7350 result_string->GetChars(), 7351 string_length)); 7352 return result_string; 7353 } else { 7354 MaybeObject* result_allocation = 7355 isolate->heap()->AllocateRawTwoByteString(string_length); 7356 if (result_allocation->IsFailure()) return result_allocation; 7357 SeqTwoByteString* result_string = 7358 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked()); 7359 JoinSparseArrayWithSeparator<uc16>(elements, 7360 elements_length, 7361 array_length, 7362 separator, 7363 Vector<uc16>(result_string->GetChars(), 7364 string_length)); 7365 return result_string; 7366 } 7367 } 7368 7369 7370 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) { 7371 SealHandleScope shs(isolate); 7372 ASSERT(args.length() == 2); 7373 7374 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7375 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7376 return isolate->heap()->NumberFromInt32(x | y); 7377 } 7378 7379 7380 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) { 7381 SealHandleScope shs(isolate); 7382 ASSERT(args.length() == 2); 7383 7384 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7385 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7386 return isolate->heap()->NumberFromInt32(x & y); 7387 } 7388 7389 7390 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) { 7391 SealHandleScope shs(isolate); 7392 ASSERT(args.length() == 2); 7393 7394 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7395 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7396 return isolate->heap()->NumberFromInt32(x ^ y); 7397 } 7398 7399 7400 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) { 7401 SealHandleScope shs(isolate); 7402 ASSERT(args.length() == 2); 7403 7404 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7405 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7406 return isolate->heap()->NumberFromInt32(x << (y & 0x1f)); 7407 } 7408 7409 7410 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) { 7411 SealHandleScope shs(isolate); 7412 ASSERT(args.length() == 2); 7413 7414 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]); 7415 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7416 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f)); 7417 } 7418 7419 7420 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) { 7421 SealHandleScope shs(isolate); 7422 ASSERT(args.length() == 2); 7423 7424 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]); 7425 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]); 7426 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f)); 7427 } 7428 7429 7430 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) { 7431 SealHandleScope shs(isolate); 7432 ASSERT(args.length() == 2); 7433 7434 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7435 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7436 if (std::isnan(x)) return Smi::FromInt(NOT_EQUAL); 7437 if (std::isnan(y)) return Smi::FromInt(NOT_EQUAL); 7438 if (x == y) return Smi::FromInt(EQUAL); 7439 Object* result; 7440 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) { 7441 result = Smi::FromInt(EQUAL); 7442 } else { 7443 result = Smi::FromInt(NOT_EQUAL); 7444 } 7445 return result; 7446 } 7447 7448 7449 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) { 7450 SealHandleScope shs(isolate); 7451 ASSERT(args.length() == 2); 7452 7453 CONVERT_ARG_CHECKED(String, x, 0); 7454 CONVERT_ARG_CHECKED(String, y, 1); 7455 7456 bool not_equal = !x->Equals(y); 7457 // This is slightly convoluted because the value that signifies 7458 // equality is 0 and inequality is 1 so we have to negate the result 7459 // from String::Equals. 7460 ASSERT(not_equal == 0 || not_equal == 1); 7461 STATIC_CHECK(EQUAL == 0); 7462 STATIC_CHECK(NOT_EQUAL == 1); 7463 return Smi::FromInt(not_equal); 7464 } 7465 7466 7467 RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) { 7468 SealHandleScope shs(isolate); 7469 ASSERT(args.length() == 3); 7470 7471 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7472 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7473 if (std::isnan(x) || std::isnan(y)) return args[2]; 7474 if (x == y) return Smi::FromInt(EQUAL); 7475 if (isless(x, y)) return Smi::FromInt(LESS); 7476 return Smi::FromInt(GREATER); 7477 } 7478 7479 7480 // Compare two Smis as if they were converted to strings and then 7481 // compared lexicographically. 7482 RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) { 7483 SealHandleScope shs(isolate); 7484 ASSERT(args.length() == 2); 7485 CONVERT_SMI_ARG_CHECKED(x_value, 0); 7486 CONVERT_SMI_ARG_CHECKED(y_value, 1); 7487 7488 // If the integers are equal so are the string representations. 7489 if (x_value == y_value) return Smi::FromInt(EQUAL); 7490 7491 // If one of the integers is zero the normal integer order is the 7492 // same as the lexicographic order of the string representations. 7493 if (x_value == 0 || y_value == 0) 7494 return Smi::FromInt(x_value < y_value ? LESS : GREATER); 7495 7496 // If only one of the integers is negative the negative number is 7497 // smallest because the char code of '-' is less than the char code 7498 // of any digit. Otherwise, we make both values positive. 7499 7500 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on 7501 // architectures using 32-bit Smis. 7502 uint32_t x_scaled = x_value; 7503 uint32_t y_scaled = y_value; 7504 if (x_value < 0 || y_value < 0) { 7505 if (y_value >= 0) return Smi::FromInt(LESS); 7506 if (x_value >= 0) return Smi::FromInt(GREATER); 7507 x_scaled = -x_value; 7508 y_scaled = -y_value; 7509 } 7510 7511 static const uint32_t kPowersOf10[] = { 7512 1, 10, 100, 1000, 10*1000, 100*1000, 7513 1000*1000, 10*1000*1000, 100*1000*1000, 7514 1000*1000*1000 7515 }; 7516 7517 // If the integers have the same number of decimal digits they can be 7518 // compared directly as the numeric order is the same as the 7519 // lexicographic order. If one integer has fewer digits, it is scaled 7520 // by some power of 10 to have the same number of digits as the longer 7521 // integer. If the scaled integers are equal it means the shorter 7522 // integer comes first in the lexicographic order. 7523 7524 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 7525 int x_log2 = IntegerLog2(x_scaled); 7526 int x_log10 = ((x_log2 + 1) * 1233) >> 12; 7527 x_log10 -= x_scaled < kPowersOf10[x_log10]; 7528 7529 int y_log2 = IntegerLog2(y_scaled); 7530 int y_log10 = ((y_log2 + 1) * 1233) >> 12; 7531 y_log10 -= y_scaled < kPowersOf10[y_log10]; 7532 7533 int tie = EQUAL; 7534 7535 if (x_log10 < y_log10) { 7536 // X has fewer digits. We would like to simply scale up X but that 7537 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would 7538 // be scaled up to 9_000_000_000. So we scale up by the next 7539 // smallest power and scale down Y to drop one digit. It is OK to 7540 // drop one digit from the longer integer since the final digit is 7541 // past the length of the shorter integer. 7542 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; 7543 y_scaled /= 10; 7544 tie = LESS; 7545 } else if (y_log10 < x_log10) { 7546 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; 7547 x_scaled /= 10; 7548 tie = GREATER; 7549 } 7550 7551 if (x_scaled < y_scaled) return Smi::FromInt(LESS); 7552 if (x_scaled > y_scaled) return Smi::FromInt(GREATER); 7553 return Smi::FromInt(tie); 7554 } 7555 7556 7557 static Object* StringCharacterStreamCompare(RuntimeState* state, 7558 String* x, 7559 String* y) { 7560 StringCharacterStream stream_x(x, state->string_iterator_compare_x()); 7561 StringCharacterStream stream_y(y, state->string_iterator_compare_y()); 7562 while (stream_x.HasMore() && stream_y.HasMore()) { 7563 int d = stream_x.GetNext() - stream_y.GetNext(); 7564 if (d < 0) return Smi::FromInt(LESS); 7565 else if (d > 0) return Smi::FromInt(GREATER); 7566 } 7567 7568 // x is (non-trivial) prefix of y: 7569 if (stream_y.HasMore()) return Smi::FromInt(LESS); 7570 // y is prefix of x: 7571 return Smi::FromInt(stream_x.HasMore() ? GREATER : EQUAL); 7572 } 7573 7574 7575 static Object* FlatStringCompare(String* x, String* y) { 7576 ASSERT(x->IsFlat()); 7577 ASSERT(y->IsFlat()); 7578 Object* equal_prefix_result = Smi::FromInt(EQUAL); 7579 int prefix_length = x->length(); 7580 if (y->length() < prefix_length) { 7581 prefix_length = y->length(); 7582 equal_prefix_result = Smi::FromInt(GREATER); 7583 } else if (y->length() > prefix_length) { 7584 equal_prefix_result = Smi::FromInt(LESS); 7585 } 7586 int r; 7587 DisallowHeapAllocation no_gc; 7588 String::FlatContent x_content = x->GetFlatContent(); 7589 String::FlatContent y_content = y->GetFlatContent(); 7590 if (x_content.IsAscii()) { 7591 Vector<const uint8_t> x_chars = x_content.ToOneByteVector(); 7592 if (y_content.IsAscii()) { 7593 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7594 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7595 } else { 7596 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7597 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7598 } 7599 } else { 7600 Vector<const uc16> x_chars = x_content.ToUC16Vector(); 7601 if (y_content.IsAscii()) { 7602 Vector<const uint8_t> y_chars = y_content.ToOneByteVector(); 7603 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7604 } else { 7605 Vector<const uc16> y_chars = y_content.ToUC16Vector(); 7606 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length); 7607 } 7608 } 7609 Object* result; 7610 if (r == 0) { 7611 result = equal_prefix_result; 7612 } else { 7613 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER); 7614 } 7615 ASSERT(result == 7616 StringCharacterStreamCompare(x->GetIsolate()->runtime_state(), x, y)); 7617 return result; 7618 } 7619 7620 7621 RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) { 7622 SealHandleScope shs(isolate); 7623 ASSERT(args.length() == 2); 7624 7625 CONVERT_ARG_CHECKED(String, x, 0); 7626 CONVERT_ARG_CHECKED(String, y, 1); 7627 7628 isolate->counters()->string_compare_runtime()->Increment(); 7629 7630 // A few fast case tests before we flatten. 7631 if (x == y) return Smi::FromInt(EQUAL); 7632 if (y->length() == 0) { 7633 if (x->length() == 0) return Smi::FromInt(EQUAL); 7634 return Smi::FromInt(GREATER); 7635 } else if (x->length() == 0) { 7636 return Smi::FromInt(LESS); 7637 } 7638 7639 int d = x->Get(0) - y->Get(0); 7640 if (d < 0) return Smi::FromInt(LESS); 7641 else if (d > 0) return Smi::FromInt(GREATER); 7642 7643 Object* obj; 7644 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x); 7645 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7646 } 7647 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y); 7648 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 7649 } 7650 7651 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y) 7652 : StringCharacterStreamCompare(isolate->runtime_state(), x, y); 7653 } 7654 7655 7656 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) { 7657 SealHandleScope shs(isolate); 7658 ASSERT(args.length() == 1); 7659 isolate->counters()->math_acos()->Increment(); 7660 7661 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7662 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x); 7663 } 7664 7665 7666 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) { 7667 SealHandleScope shs(isolate); 7668 ASSERT(args.length() == 1); 7669 isolate->counters()->math_asin()->Increment(); 7670 7671 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7672 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x); 7673 } 7674 7675 7676 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) { 7677 SealHandleScope shs(isolate); 7678 ASSERT(args.length() == 1); 7679 isolate->counters()->math_atan()->Increment(); 7680 7681 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7682 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x); 7683 } 7684 7685 7686 static const double kPiDividedBy4 = 0.78539816339744830962; 7687 7688 7689 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) { 7690 SealHandleScope shs(isolate); 7691 ASSERT(args.length() == 2); 7692 isolate->counters()->math_atan2()->Increment(); 7693 7694 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7695 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7696 double result; 7697 if (std::isinf(x) && std::isinf(y)) { 7698 // Make sure that the result in case of two infinite arguments 7699 // is a multiple of Pi / 4. The sign of the result is determined 7700 // by the first argument (x) and the sign of the second argument 7701 // determines the multiplier: one or three. 7702 int multiplier = (x < 0) ? -1 : 1; 7703 if (y < 0) multiplier *= 3; 7704 result = multiplier * kPiDividedBy4; 7705 } else { 7706 result = atan2(x, y); 7707 } 7708 return isolate->heap()->AllocateHeapNumber(result); 7709 } 7710 7711 7712 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) { 7713 SealHandleScope shs(isolate); 7714 ASSERT(args.length() == 1); 7715 isolate->counters()->math_cos()->Increment(); 7716 7717 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7718 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x); 7719 } 7720 7721 7722 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) { 7723 SealHandleScope shs(isolate); 7724 ASSERT(args.length() == 1); 7725 isolate->counters()->math_exp()->Increment(); 7726 7727 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7728 lazily_initialize_fast_exp(); 7729 return isolate->heap()->NumberFromDouble(fast_exp(x)); 7730 } 7731 7732 7733 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) { 7734 SealHandleScope shs(isolate); 7735 ASSERT(args.length() == 1); 7736 isolate->counters()->math_floor()->Increment(); 7737 7738 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7739 return isolate->heap()->NumberFromDouble(floor(x)); 7740 } 7741 7742 7743 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) { 7744 SealHandleScope shs(isolate); 7745 ASSERT(args.length() == 1); 7746 isolate->counters()->math_log()->Increment(); 7747 7748 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7749 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x); 7750 } 7751 7752 7753 // Slow version of Math.pow. We check for fast paths for special cases. 7754 // Used if SSE2/VFP3 is not available. 7755 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { 7756 SealHandleScope shs(isolate); 7757 ASSERT(args.length() == 2); 7758 isolate->counters()->math_pow()->Increment(); 7759 7760 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7761 7762 // If the second argument is a smi, it is much faster to call the 7763 // custom powi() function than the generic pow(). 7764 if (args[1]->IsSmi()) { 7765 int y = args.smi_at(1); 7766 return isolate->heap()->NumberFromDouble(power_double_int(x, y)); 7767 } 7768 7769 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7770 double result = power_helper(x, y); 7771 if (std::isnan(result)) return isolate->heap()->nan_value(); 7772 return isolate->heap()->AllocateHeapNumber(result); 7773 } 7774 7775 7776 // Fast version of Math.pow if we know that y is not an integer and y is not 7777 // -0.5 or 0.5. Used as slow case from full codegen. 7778 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) { 7779 SealHandleScope shs(isolate); 7780 ASSERT(args.length() == 2); 7781 isolate->counters()->math_pow()->Increment(); 7782 7783 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7784 CONVERT_DOUBLE_ARG_CHECKED(y, 1); 7785 if (y == 0) { 7786 return Smi::FromInt(1); 7787 } else { 7788 double result = power_double_double(x, y); 7789 if (std::isnan(result)) return isolate->heap()->nan_value(); 7790 return isolate->heap()->AllocateHeapNumber(result); 7791 } 7792 } 7793 7794 7795 RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) { 7796 SealHandleScope shs(isolate); 7797 ASSERT(args.length() == 1); 7798 isolate->counters()->math_round()->Increment(); 7799 7800 if (!args[0]->IsHeapNumber()) { 7801 // Must be smi. Return the argument unchanged for all the other types 7802 // to make fuzz-natives test happy. 7803 return args[0]; 7804 } 7805 7806 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]); 7807 7808 double value = number->value(); 7809 int exponent = number->get_exponent(); 7810 int sign = number->get_sign(); 7811 7812 if (exponent < -1) { 7813 // Number in range ]-0.5..0.5[. These always round to +/-zero. 7814 if (sign) return isolate->heap()->minus_zero_value(); 7815 return Smi::FromInt(0); 7816 } 7817 7818 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and 7819 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar 7820 // argument holds for 32-bit smis). 7821 if (!sign && exponent < kSmiValueSize - 2) { 7822 return Smi::FromInt(static_cast<int>(value + 0.5)); 7823 } 7824 7825 // If the magnitude is big enough, there's no place for fraction part. If we 7826 // try to add 0.5 to this number, 1.0 will be added instead. 7827 if (exponent >= 52) { 7828 return number; 7829 } 7830 7831 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value(); 7832 7833 // Do not call NumberFromDouble() to avoid extra checks. 7834 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5)); 7835 } 7836 7837 7838 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) { 7839 SealHandleScope shs(isolate); 7840 ASSERT(args.length() == 1); 7841 isolate->counters()->math_sin()->Increment(); 7842 7843 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7844 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x); 7845 } 7846 7847 7848 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) { 7849 SealHandleScope shs(isolate); 7850 ASSERT(args.length() == 1); 7851 isolate->counters()->math_sqrt()->Increment(); 7852 7853 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7854 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x)); 7855 } 7856 7857 7858 RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) { 7859 SealHandleScope shs(isolate); 7860 ASSERT(args.length() == 1); 7861 isolate->counters()->math_tan()->Increment(); 7862 7863 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 7864 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x); 7865 } 7866 7867 7868 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) { 7869 SealHandleScope shs(isolate); 7870 ASSERT(args.length() == 2); 7871 7872 CONVERT_SMI_ARG_CHECKED(year, 0); 7873 CONVERT_SMI_ARG_CHECKED(month, 1); 7874 7875 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month)); 7876 } 7877 7878 7879 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) { 7880 HandleScope scope(isolate); 7881 ASSERT(args.length() == 3); 7882 7883 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0); 7884 CONVERT_DOUBLE_ARG_CHECKED(time, 1); 7885 CONVERT_SMI_ARG_CHECKED(is_utc, 2); 7886 7887 DateCache* date_cache = isolate->date_cache(); 7888 7889 Object* value = NULL; 7890 bool is_value_nan = false; 7891 if (std::isnan(time)) { 7892 value = isolate->heap()->nan_value(); 7893 is_value_nan = true; 7894 } else if (!is_utc && 7895 (time < -DateCache::kMaxTimeBeforeUTCInMs || 7896 time > DateCache::kMaxTimeBeforeUTCInMs)) { 7897 value = isolate->heap()->nan_value(); 7898 is_value_nan = true; 7899 } else { 7900 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time)); 7901 if (time < -DateCache::kMaxTimeInMs || 7902 time > DateCache::kMaxTimeInMs) { 7903 value = isolate->heap()->nan_value(); 7904 is_value_nan = true; 7905 } else { 7906 MaybeObject* maybe_result = 7907 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time)); 7908 if (!maybe_result->ToObject(&value)) return maybe_result; 7909 } 7910 } 7911 date->SetValue(value, is_value_nan); 7912 return value; 7913 } 7914 7915 7916 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) { 7917 HandleScope scope(isolate); 7918 ASSERT(args.length() == 3); 7919 7920 Handle<JSFunction> callee = args.at<JSFunction>(0); 7921 Object** parameters = reinterpret_cast<Object**>(args[1]); 7922 const int argument_count = Smi::cast(args[2])->value(); 7923 7924 Handle<JSObject> result = 7925 isolate->factory()->NewArgumentsObject(callee, argument_count); 7926 // Allocate the elements if needed. 7927 int parameter_count = callee->shared()->formal_parameter_count(); 7928 if (argument_count > 0) { 7929 if (parameter_count > 0) { 7930 int mapped_count = Min(argument_count, parameter_count); 7931 Handle<FixedArray> parameter_map = 7932 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED); 7933 parameter_map->set_map( 7934 isolate->heap()->non_strict_arguments_elements_map()); 7935 7936 Handle<Map> old_map(result->map()); 7937 Handle<Map> new_map = isolate->factory()->CopyMap(old_map); 7938 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS); 7939 7940 result->set_map(*new_map); 7941 result->set_elements(*parameter_map); 7942 7943 // Store the context and the arguments array at the beginning of the 7944 // parameter map. 7945 Handle<Context> context(isolate->context()); 7946 Handle<FixedArray> arguments = 7947 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 7948 parameter_map->set(0, *context); 7949 parameter_map->set(1, *arguments); 7950 7951 // Loop over the actual parameters backwards. 7952 int index = argument_count - 1; 7953 while (index >= mapped_count) { 7954 // These go directly in the arguments array and have no 7955 // corresponding slot in the parameter map. 7956 arguments->set(index, *(parameters - index - 1)); 7957 --index; 7958 } 7959 7960 Handle<ScopeInfo> scope_info(callee->shared()->scope_info()); 7961 while (index >= 0) { 7962 // Detect duplicate names to the right in the parameter list. 7963 Handle<String> name(scope_info->ParameterName(index)); 7964 int context_local_count = scope_info->ContextLocalCount(); 7965 bool duplicate = false; 7966 for (int j = index + 1; j < parameter_count; ++j) { 7967 if (scope_info->ParameterName(j) == *name) { 7968 duplicate = true; 7969 break; 7970 } 7971 } 7972 7973 if (duplicate) { 7974 // This goes directly in the arguments array with a hole in the 7975 // parameter map. 7976 arguments->set(index, *(parameters - index - 1)); 7977 parameter_map->set_the_hole(index + 2); 7978 } else { 7979 // The context index goes in the parameter map with a hole in the 7980 // arguments array. 7981 int context_index = -1; 7982 for (int j = 0; j < context_local_count; ++j) { 7983 if (scope_info->ContextLocalName(j) == *name) { 7984 context_index = j; 7985 break; 7986 } 7987 } 7988 ASSERT(context_index >= 0); 7989 arguments->set_the_hole(index); 7990 parameter_map->set(index + 2, Smi::FromInt( 7991 Context::MIN_CONTEXT_SLOTS + context_index)); 7992 } 7993 7994 --index; 7995 } 7996 } else { 7997 // If there is no aliasing, the arguments object elements are not 7998 // special in any way. 7999 Handle<FixedArray> elements = 8000 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED); 8001 result->set_elements(*elements); 8002 for (int i = 0; i < argument_count; ++i) { 8003 elements->set(i, *(parameters - i - 1)); 8004 } 8005 } 8006 } 8007 return *result; 8008 } 8009 8010 8011 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) { 8012 SealHandleScope shs(isolate); 8013 ASSERT(args.length() == 3); 8014 8015 JSFunction* callee = JSFunction::cast(args[0]); 8016 Object** parameters = reinterpret_cast<Object**>(args[1]); 8017 const int length = args.smi_at(2); 8018 8019 Object* result; 8020 { MaybeObject* maybe_result = 8021 isolate->heap()->AllocateArgumentsObject(callee, length); 8022 if (!maybe_result->ToObject(&result)) return maybe_result; 8023 } 8024 // Allocate the elements if needed. 8025 if (length > 0) { 8026 // Allocate the fixed array. 8027 FixedArray* array; 8028 { MaybeObject* maybe_obj = 8029 isolate->heap()->AllocateUninitializedFixedArray(length); 8030 if (!maybe_obj->To(&array)) return maybe_obj; 8031 } 8032 8033 DisallowHeapAllocation no_gc; 8034 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc); 8035 for (int i = 0; i < length; i++) { 8036 array->set(i, *--parameters, mode); 8037 } 8038 JSObject::cast(result)->set_elements(array); 8039 } 8040 return result; 8041 } 8042 8043 8044 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosureFromStubFailure) { 8045 HandleScope scope(isolate); 8046 ASSERT(args.length() == 1); 8047 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0); 8048 Handle<Context> context(isolate->context()); 8049 PretenureFlag pretenure_flag = NOT_TENURED; 8050 Handle<JSFunction> result = 8051 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 8052 context, 8053 pretenure_flag); 8054 return *result; 8055 } 8056 8057 8058 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) { 8059 HandleScope scope(isolate); 8060 ASSERT(args.length() == 3); 8061 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 8062 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1); 8063 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2); 8064 8065 // The caller ensures that we pretenure closures that are assigned 8066 // directly to properties. 8067 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED; 8068 Handle<JSFunction> result = 8069 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 8070 context, 8071 pretenure_flag); 8072 return *result; 8073 } 8074 8075 8076 // Find the arguments of the JavaScript function invocation that called 8077 // into C++ code. Collect these in a newly allocated array of handles (possibly 8078 // prefixed by a number of empty handles). 8079 static SmartArrayPointer<Handle<Object> > GetCallerArguments( 8080 Isolate* isolate, 8081 int prefix_argc, 8082 int* total_argc) { 8083 // Find frame containing arguments passed to the caller. 8084 JavaScriptFrameIterator it(isolate); 8085 JavaScriptFrame* frame = it.frame(); 8086 List<JSFunction*> functions(2); 8087 frame->GetFunctions(&functions); 8088 if (functions.length() > 1) { 8089 int inlined_jsframe_index = functions.length() - 1; 8090 JSFunction* inlined_function = functions[inlined_jsframe_index]; 8091 Vector<SlotRef> args_slots = 8092 SlotRef::ComputeSlotMappingForArguments( 8093 frame, 8094 inlined_jsframe_index, 8095 inlined_function->shared()->formal_parameter_count()); 8096 8097 int args_count = args_slots.length(); 8098 8099 *total_argc = prefix_argc + args_count; 8100 SmartArrayPointer<Handle<Object> > param_data( 8101 NewArray<Handle<Object> >(*total_argc)); 8102 for (int i = 0; i < args_count; i++) { 8103 Handle<Object> val = args_slots[i].GetValue(isolate); 8104 param_data[prefix_argc + i] = val; 8105 } 8106 8107 args_slots.Dispose(); 8108 8109 return param_data; 8110 } else { 8111 it.AdvanceToArgumentsFrame(); 8112 frame = it.frame(); 8113 int args_count = frame->ComputeParametersCount(); 8114 8115 *total_argc = prefix_argc + args_count; 8116 SmartArrayPointer<Handle<Object> > param_data( 8117 NewArray<Handle<Object> >(*total_argc)); 8118 for (int i = 0; i < args_count; i++) { 8119 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate); 8120 param_data[prefix_argc + i] = val; 8121 } 8122 return param_data; 8123 } 8124 } 8125 8126 8127 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) { 8128 HandleScope scope(isolate); 8129 ASSERT(args.length() == 4); 8130 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0); 8131 RUNTIME_ASSERT(args[3]->IsNumber()); 8132 Handle<Object> bindee = args.at<Object>(1); 8133 8134 // TODO(lrn): Create bound function in C++ code from premade shared info. 8135 bound_function->shared()->set_bound(true); 8136 // Get all arguments of calling function (Function.prototype.bind). 8137 int argc = 0; 8138 SmartArrayPointer<Handle<Object> > arguments = 8139 GetCallerArguments(isolate, 0, &argc); 8140 // Don't count the this-arg. 8141 if (argc > 0) { 8142 ASSERT(*arguments[0] == args[2]); 8143 argc--; 8144 } else { 8145 ASSERT(args[2]->IsUndefined()); 8146 } 8147 // Initialize array of bindings (function, this, and any existing arguments 8148 // if the function was already bound). 8149 Handle<FixedArray> new_bindings; 8150 int i; 8151 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) { 8152 Handle<FixedArray> old_bindings( 8153 JSFunction::cast(*bindee)->function_bindings()); 8154 new_bindings = 8155 isolate->factory()->NewFixedArray(old_bindings->length() + argc); 8156 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex), 8157 isolate); 8158 i = 0; 8159 for (int n = old_bindings->length(); i < n; i++) { 8160 new_bindings->set(i, old_bindings->get(i)); 8161 } 8162 } else { 8163 int array_size = JSFunction::kBoundArgumentsStartIndex + argc; 8164 new_bindings = isolate->factory()->NewFixedArray(array_size); 8165 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee); 8166 new_bindings->set(JSFunction::kBoundThisIndex, args[2]); 8167 i = 2; 8168 } 8169 // Copy arguments, skipping the first which is "this_arg". 8170 for (int j = 0; j < argc; j++, i++) { 8171 new_bindings->set(i, *arguments[j + 1]); 8172 } 8173 new_bindings->set_map_no_write_barrier( 8174 isolate->heap()->fixed_cow_array_map()); 8175 bound_function->set_function_bindings(*new_bindings); 8176 8177 // Update length. 8178 Handle<String> length_string = isolate->factory()->length_string(); 8179 Handle<Object> new_length(args.at<Object>(3)); 8180 PropertyAttributes attr = 8181 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY); 8182 ForceSetProperty(bound_function, length_string, new_length, attr); 8183 return *bound_function; 8184 } 8185 8186 8187 RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) { 8188 HandleScope handles(isolate); 8189 ASSERT(args.length() == 1); 8190 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0); 8191 if (callable->IsJSFunction()) { 8192 Handle<JSFunction> function = Handle<JSFunction>::cast(callable); 8193 if (function->shared()->bound()) { 8194 Handle<FixedArray> bindings(function->function_bindings()); 8195 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map()); 8196 return *isolate->factory()->NewJSArrayWithElements(bindings); 8197 } 8198 } 8199 return isolate->heap()->undefined_value(); 8200 } 8201 8202 8203 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) { 8204 HandleScope scope(isolate); 8205 ASSERT(args.length() == 1); 8206 // First argument is a function to use as a constructor. 8207 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8208 RUNTIME_ASSERT(function->shared()->bound()); 8209 8210 // The argument is a bound function. Extract its bound arguments 8211 // and callable. 8212 Handle<FixedArray> bound_args = 8213 Handle<FixedArray>(FixedArray::cast(function->function_bindings())); 8214 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex; 8215 Handle<Object> bound_function( 8216 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)), 8217 isolate); 8218 ASSERT(!bound_function->IsJSFunction() || 8219 !Handle<JSFunction>::cast(bound_function)->shared()->bound()); 8220 8221 int total_argc = 0; 8222 SmartArrayPointer<Handle<Object> > param_data = 8223 GetCallerArguments(isolate, bound_argc, &total_argc); 8224 for (int i = 0; i < bound_argc; i++) { 8225 param_data[i] = Handle<Object>(bound_args->get( 8226 JSFunction::kBoundArgumentsStartIndex + i), isolate); 8227 } 8228 8229 if (!bound_function->IsJSFunction()) { 8230 bool exception_thrown; 8231 bound_function = Execution::TryGetConstructorDelegate(isolate, 8232 bound_function, 8233 &exception_thrown); 8234 if (exception_thrown) return Failure::Exception(); 8235 } 8236 ASSERT(bound_function->IsJSFunction()); 8237 8238 bool exception = false; 8239 Handle<Object> result = 8240 Execution::New(Handle<JSFunction>::cast(bound_function), 8241 total_argc, *param_data, &exception); 8242 if (exception) { 8243 return Failure::Exception(); 8244 } 8245 ASSERT(!result.is_null()); 8246 return *result; 8247 } 8248 8249 8250 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) { 8251 HandleScope scope(isolate); 8252 ASSERT(args.length() == 1); 8253 8254 Handle<Object> constructor = args.at<Object>(0); 8255 8256 // If the constructor isn't a proper function we throw a type error. 8257 if (!constructor->IsJSFunction()) { 8258 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8259 Handle<Object> type_error = 8260 isolate->factory()->NewTypeError("not_constructor", arguments); 8261 return isolate->Throw(*type_error); 8262 } 8263 8264 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor); 8265 8266 // If function should not have prototype, construction is not allowed. In this 8267 // case generated code bailouts here, since function has no initial_map. 8268 if (!function->should_have_prototype() && !function->shared()->bound()) { 8269 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1); 8270 Handle<Object> type_error = 8271 isolate->factory()->NewTypeError("not_constructor", arguments); 8272 return isolate->Throw(*type_error); 8273 } 8274 8275 #ifdef ENABLE_DEBUGGER_SUPPORT 8276 Debug* debug = isolate->debug(); 8277 // Handle stepping into constructors if step into is active. 8278 if (debug->StepInActive()) { 8279 debug->HandleStepIn(function, Handle<Object>::null(), 0, true); 8280 } 8281 #endif 8282 8283 if (function->has_initial_map()) { 8284 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) { 8285 // The 'Function' function ignores the receiver object when 8286 // called using 'new' and creates a new JSFunction object that 8287 // is returned. The receiver object is only used for error 8288 // reporting if an error occurs when constructing the new 8289 // JSFunction. Factory::NewJSObject() should not be used to 8290 // allocate JSFunctions since it does not properly initialize 8291 // the shared part of the function. Since the receiver is 8292 // ignored anyway, we use the global object as the receiver 8293 // instead of a new JSFunction object. This way, errors are 8294 // reported the same way whether or not 'Function' is called 8295 // using 'new'. 8296 return isolate->context()->global_object(); 8297 } 8298 } 8299 8300 // The function should be compiled for the optimization hints to be 8301 // available. 8302 JSFunction::EnsureCompiled(function, CLEAR_EXCEPTION); 8303 8304 Handle<SharedFunctionInfo> shared(function->shared(), isolate); 8305 if (!function->has_initial_map() && 8306 shared->IsInobjectSlackTrackingInProgress()) { 8307 // The tracking is already in progress for another function. We can only 8308 // track one initial_map at a time, so we force the completion before the 8309 // function is called as a constructor for the first time. 8310 shared->CompleteInobjectSlackTracking(); 8311 } 8312 8313 Handle<JSObject> result = isolate->factory()->NewJSObject(function); 8314 RETURN_IF_EMPTY_HANDLE(isolate, result); 8315 8316 isolate->counters()->constructed_objects()->Increment(); 8317 isolate->counters()->constructed_objects_runtime()->Increment(); 8318 8319 return *result; 8320 } 8321 8322 8323 RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) { 8324 HandleScope scope(isolate); 8325 ASSERT(args.length() == 1); 8326 8327 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8328 function->shared()->CompleteInobjectSlackTracking(); 8329 8330 return isolate->heap()->undefined_value(); 8331 } 8332 8333 8334 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) { 8335 HandleScope scope(isolate); 8336 ASSERT(args.length() == 1); 8337 8338 Handle<JSFunction> function = args.at<JSFunction>(0); 8339 #ifdef DEBUG 8340 if (FLAG_trace_lazy && !function->shared()->is_compiled()) { 8341 PrintF("[lazy: "); 8342 function->PrintName(); 8343 PrintF("]\n"); 8344 } 8345 #endif 8346 8347 // Compile the target function. 8348 ASSERT(!function->is_compiled()); 8349 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) { 8350 return Failure::Exception(); 8351 } 8352 8353 // All done. Return the compiled code. 8354 ASSERT(function->is_compiled()); 8355 return function->code(); 8356 } 8357 8358 8359 bool AllowOptimization(Isolate* isolate, Handle<JSFunction> function) { 8360 // If the function is not compiled ignore the lazy 8361 // recompilation. This can happen if the debugger is activated and 8362 // the function is returned to the not compiled state. 8363 if (!function->shared()->is_compiled()) return false; 8364 8365 // If the function is not optimizable or debugger is active continue using the 8366 // code from the full compiler. 8367 if (!isolate->use_crankshaft() || 8368 function->shared()->optimization_disabled() || 8369 isolate->DebuggerHasBreakPoints()) { 8370 if (FLAG_trace_opt) { 8371 PrintF("[failed to optimize "); 8372 function->PrintName(); 8373 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", 8374 function->shared()->optimization_disabled() ? "F" : "T", 8375 isolate->DebuggerHasBreakPoints() ? "T" : "F"); 8376 } 8377 return false; 8378 } 8379 return true; 8380 } 8381 8382 8383 RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) { 8384 HandleScope scope(isolate); 8385 ASSERT(args.length() == 1); 8386 Handle<JSFunction> function = args.at<JSFunction>(0); 8387 8388 if (!AllowOptimization(isolate, function)) { 8389 function->ReplaceCode(function->shared()->code()); 8390 return function->code(); 8391 } 8392 function->shared()->code()->set_profiler_ticks(0); 8393 if (JSFunction::CompileOptimized(function, CLEAR_EXCEPTION)) { 8394 return function->code(); 8395 } 8396 if (FLAG_trace_opt) { 8397 PrintF("[failed to optimize "); 8398 function->PrintName(); 8399 PrintF(": optimized compilation failed]\n"); 8400 } 8401 function->ReplaceCode(function->shared()->code()); 8402 return function->code(); 8403 } 8404 8405 8406 RUNTIME_FUNCTION(MaybeObject*, Runtime_ConcurrentRecompile) { 8407 HandleScope handle_scope(isolate); 8408 ASSERT(args.length() == 1); 8409 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8410 if (!AllowOptimization(isolate, function)) { 8411 function->ReplaceCode(function->shared()->code()); 8412 return isolate->heap()->undefined_value(); 8413 } 8414 function->shared()->code()->set_profiler_ticks(0); 8415 ASSERT(isolate->concurrent_recompilation_enabled()); 8416 if (!Compiler::RecompileConcurrent(function)) { 8417 function->ReplaceCode(function->shared()->code()); 8418 } 8419 return isolate->heap()->undefined_value(); 8420 } 8421 8422 8423 class ActivationsFinder : public ThreadVisitor { 8424 public: 8425 Code* code_; 8426 bool has_code_activations_; 8427 8428 explicit ActivationsFinder(Code* code) 8429 : code_(code), 8430 has_code_activations_(false) { } 8431 8432 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 8433 JavaScriptFrameIterator it(isolate, top); 8434 VisitFrames(&it); 8435 } 8436 8437 void VisitFrames(JavaScriptFrameIterator* it) { 8438 for (; !it->done(); it->Advance()) { 8439 JavaScriptFrame* frame = it->frame(); 8440 if (code_->contains(frame->pc())) has_code_activations_ = true; 8441 } 8442 } 8443 }; 8444 8445 8446 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyStubFailure) { 8447 HandleScope scope(isolate); 8448 ASSERT(args.length() == 0); 8449 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8450 ASSERT(AllowHeapAllocation::IsAllowed()); 8451 delete deoptimizer; 8452 return isolate->heap()->undefined_value(); 8453 } 8454 8455 8456 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) { 8457 HandleScope scope(isolate); 8458 ASSERT(args.length() == 1); 8459 RUNTIME_ASSERT(args[0]->IsSmi()); 8460 Deoptimizer::BailoutType type = 8461 static_cast<Deoptimizer::BailoutType>(args.smi_at(0)); 8462 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate); 8463 ASSERT(AllowHeapAllocation::IsAllowed()); 8464 8465 Handle<JSFunction> function = deoptimizer->function(); 8466 Handle<Code> optimized_code = deoptimizer->compiled_code(); 8467 8468 ASSERT(optimized_code->kind() == Code::OPTIMIZED_FUNCTION); 8469 ASSERT(type == deoptimizer->bailout_type()); 8470 8471 // Make sure to materialize objects before causing any allocation. 8472 JavaScriptFrameIterator it(isolate); 8473 deoptimizer->MaterializeHeapObjects(&it); 8474 delete deoptimizer; 8475 8476 JavaScriptFrame* frame = it.frame(); 8477 RUNTIME_ASSERT(frame->function()->IsJSFunction()); 8478 ASSERT(frame->function() == *function); 8479 8480 // Avoid doing too much work when running with --always-opt and keep 8481 // the optimized code around. 8482 if (FLAG_always_opt || type == Deoptimizer::LAZY) { 8483 return isolate->heap()->undefined_value(); 8484 } 8485 8486 // Search for other activations of the same function and code. 8487 ActivationsFinder activations_finder(*optimized_code); 8488 activations_finder.VisitFrames(&it); 8489 isolate->thread_manager()->IterateArchivedThreads(&activations_finder); 8490 8491 if (!activations_finder.has_code_activations_) { 8492 if (function->code() == *optimized_code) { 8493 if (FLAG_trace_deopt) { 8494 PrintF("[removing optimized code for: "); 8495 function->PrintName(); 8496 PrintF("]\n"); 8497 } 8498 function->ReplaceCode(function->shared()->code()); 8499 } 8500 } else { 8501 // TODO(titzer): we should probably do DeoptimizeCodeList(code) 8502 // unconditionally if the code is not already marked for deoptimization. 8503 // If there is an index by shared function info, all the better. 8504 Deoptimizer::DeoptimizeFunction(*function); 8505 } 8506 // Evict optimized code for this function from the cache so that it doesn't 8507 // get used for new closures. 8508 function->shared()->EvictFromOptimizedCodeMap(*optimized_code, 8509 "notify deoptimized"); 8510 8511 return isolate->heap()->undefined_value(); 8512 } 8513 8514 8515 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) { 8516 HandleScope scope(isolate); 8517 ASSERT(args.length() == 1); 8518 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8519 if (!function->IsOptimized()) return isolate->heap()->undefined_value(); 8520 8521 Deoptimizer::DeoptimizeFunction(*function); 8522 8523 return isolate->heap()->undefined_value(); 8524 } 8525 8526 8527 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearFunctionTypeFeedback) { 8528 HandleScope scope(isolate); 8529 ASSERT(args.length() == 1); 8530 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8531 Code* unoptimized = function->shared()->code(); 8532 if (unoptimized->kind() == Code::FUNCTION) { 8533 unoptimized->ClearInlineCaches(); 8534 unoptimized->ClearTypeFeedbackCells(isolate->heap()); 8535 } 8536 return isolate->heap()->undefined_value(); 8537 } 8538 8539 8540 RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) { 8541 SealHandleScope shs(isolate); 8542 #if defined(USE_SIMULATOR) 8543 return isolate->heap()->true_value(); 8544 #else 8545 return isolate->heap()->false_value(); 8546 #endif 8547 } 8548 8549 8550 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConcurrentRecompilationSupported) { 8551 HandleScope scope(isolate); 8552 return isolate->concurrent_recompilation_enabled() 8553 ? isolate->heap()->true_value() : isolate->heap()->false_value(); 8554 } 8555 8556 8557 RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { 8558 HandleScope scope(isolate); 8559 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8560 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8561 8562 if (!function->IsOptimizable()) return isolate->heap()->undefined_value(); 8563 function->MarkForLazyRecompilation(); 8564 8565 Code* unoptimized = function->shared()->code(); 8566 if (args.length() == 2 && 8567 unoptimized->kind() == Code::FUNCTION) { 8568 CONVERT_ARG_HANDLE_CHECKED(String, type, 1); 8569 if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("osr"))) { 8570 // Start patching from the currently patched loop nesting level. 8571 int current_level = unoptimized->allow_osr_at_loop_nesting_level(); 8572 ASSERT(BackEdgeTable::Verify(isolate, unoptimized, current_level)); 8573 for (int i = current_level + 1; i <= Code::kMaxLoopNestingMarker; i++) { 8574 unoptimized->set_allow_osr_at_loop_nesting_level(i); 8575 isolate->runtime_profiler()->AttemptOnStackReplacement(*function); 8576 } 8577 } else if (type->IsOneByteEqualTo(STATIC_ASCII_VECTOR("concurrent"))) { 8578 function->MarkForConcurrentRecompilation(); 8579 } 8580 } 8581 8582 return isolate->heap()->undefined_value(); 8583 } 8584 8585 8586 RUNTIME_FUNCTION(MaybeObject*, Runtime_NeverOptimizeFunction) { 8587 HandleScope scope(isolate); 8588 ASSERT(args.length() == 1); 8589 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8590 ASSERT(!function->IsOptimized()); 8591 function->shared()->set_optimization_disabled(true); 8592 return isolate->heap()->undefined_value(); 8593 } 8594 8595 8596 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { 8597 HandleScope scope(isolate); 8598 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2); 8599 if (!isolate->use_crankshaft()) { 8600 return Smi::FromInt(4); // 4 == "never". 8601 } 8602 bool sync_with_compiler_thread = true; 8603 if (args.length() == 2) { 8604 CONVERT_ARG_HANDLE_CHECKED(String, sync, 1); 8605 if (sync->IsOneByteEqualTo(STATIC_ASCII_VECTOR("no sync"))) { 8606 sync_with_compiler_thread = false; 8607 } 8608 } 8609 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8610 if (isolate->concurrent_recompilation_enabled() && 8611 sync_with_compiler_thread) { 8612 while (function->IsInRecompileQueue()) { 8613 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 8614 OS::Sleep(50); 8615 } 8616 } 8617 if (FLAG_always_opt) { 8618 // We may have always opt, but that is more best-effort than a real 8619 // promise, so we still say "no" if it is not optimized. 8620 return function->IsOptimized() ? Smi::FromInt(3) // 3 == "always". 8621 : Smi::FromInt(2); // 2 == "no". 8622 } 8623 if (FLAG_deopt_every_n_times) { 8624 return Smi::FromInt(6); // 6 == "maybe deopted". 8625 } 8626 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". 8627 : Smi::FromInt(2); // 2 == "no". 8628 } 8629 8630 8631 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnblockConcurrentRecompilation) { 8632 RUNTIME_ASSERT(FLAG_block_concurrent_recompilation); 8633 isolate->optimizing_compiler_thread()->Unblock(); 8634 return isolate->heap()->undefined_value(); 8635 } 8636 8637 8638 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { 8639 HandleScope scope(isolate); 8640 ASSERT(args.length() == 1); 8641 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8642 return Smi::FromInt(function->shared()->opt_count()); 8643 } 8644 8645 8646 static bool IsSuitableForOnStackReplacement(Isolate* isolate, 8647 Handle<JSFunction> function, 8648 Handle<Code> unoptimized) { 8649 // Keep track of whether we've succeeded in optimizing. 8650 if (!isolate->use_crankshaft() || !unoptimized->optimizable()) return false; 8651 // If we are trying to do OSR when there are already optimized 8652 // activations of the function, it means (a) the function is directly or 8653 // indirectly recursive and (b) an optimized invocation has been 8654 // deoptimized so that we are currently in an unoptimized activation. 8655 // Check for optimized activations of this function. 8656 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) { 8657 JavaScriptFrame* frame = it.frame(); 8658 if (frame->is_optimized() && frame->function() == *function) return false; 8659 } 8660 8661 return true; 8662 } 8663 8664 8665 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { 8666 HandleScope scope(isolate); 8667 ASSERT(args.length() == 2); 8668 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 8669 CONVERT_NUMBER_CHECKED(uint32_t, pc_offset, Uint32, args[1]); 8670 Handle<Code> unoptimized(function->shared()->code(), isolate); 8671 8672 #ifdef DEBUG 8673 JavaScriptFrameIterator it(isolate); 8674 JavaScriptFrame* frame = it.frame(); 8675 ASSERT_EQ(frame->function(), *function); 8676 ASSERT_EQ(frame->LookupCode(), *unoptimized); 8677 ASSERT(unoptimized->contains(frame->pc())); 8678 8679 ASSERT(pc_offset == 8680 static_cast<uint32_t>(frame->pc() - unoptimized->instruction_start())); 8681 #endif // DEBUG 8682 8683 // We're not prepared to handle a function with arguments object. 8684 ASSERT(!function->shared()->uses_arguments()); 8685 8686 Handle<Code> result = Handle<Code>::null(); 8687 BailoutId ast_id = BailoutId::None(); 8688 8689 if (isolate->concurrent_osr_enabled()) { 8690 if (isolate->optimizing_compiler_thread()-> 8691 IsQueuedForOSR(function, pc_offset)) { 8692 // Still waiting for the optimizing compiler thread to finish. Carry on. 8693 if (FLAG_trace_osr) { 8694 PrintF("[COSR - polling recompile tasks for "); 8695 function->PrintName(); 8696 PrintF("]\n"); 8697 } 8698 return NULL; 8699 } 8700 8701 RecompileJob* job = isolate->optimizing_compiler_thread()-> 8702 FindReadyOSRCandidate(function, pc_offset); 8703 8704 if (job == NULL) { 8705 if (IsSuitableForOnStackReplacement(isolate, function, unoptimized) && 8706 Compiler::RecompileConcurrent(function, pc_offset)) { 8707 if (function->IsMarkedForLazyRecompilation() || 8708 function->IsMarkedForConcurrentRecompilation()) { 8709 // Prevent regular recompilation if we queue this for OSR. 8710 // TODO(yangguo): remove this as soon as OSR becomes one-shot. 8711 function->ReplaceCode(*unoptimized); 8712 } 8713 return NULL; 8714 } 8715 // Fall through to the end in case of failure. 8716 } else { 8717 // TODO(titzer): don't install the OSR code into the function. 8718 ast_id = job->info()->osr_ast_id(); 8719 result = Compiler::InstallOptimizedCode(job); 8720 } 8721 } else if (IsSuitableForOnStackReplacement(isolate, function, unoptimized)) { 8722 ast_id = unoptimized->TranslatePcOffsetToAstId(pc_offset); 8723 ASSERT(!ast_id.IsNone()); 8724 if (FLAG_trace_osr) { 8725 PrintF("[OSR - replacing at AST id %d in ", ast_id.ToInt()); 8726 function->PrintName(); 8727 PrintF("]\n"); 8728 } 8729 // Attempt OSR compilation. 8730 result = JSFunction::CompileOsr(function, ast_id, CLEAR_EXCEPTION); 8731 } 8732 8733 // Revert the patched back edge table, regardless of whether OSR succeeds. 8734 BackEdgeTable::Revert(isolate, *unoptimized); 8735 8736 // Check whether we ended up with usable optimized code. 8737 if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) { 8738 DeoptimizationInputData* data = 8739 DeoptimizationInputData::cast(result->deoptimization_data()); 8740 8741 if (data->OsrPcOffset()->value() >= 0) { 8742 ASSERT(BailoutId(data->OsrAstId()->value()) == ast_id); 8743 if (FLAG_trace_osr) { 8744 PrintF("[OSR - entry at AST id %d, offset %d in optimized code]\n", 8745 ast_id.ToInt(), data->OsrPcOffset()->value()); 8746 } 8747 // TODO(titzer): this is a massive hack to make the deopt counts 8748 // match. Fix heuristics for reenabling optimizations! 8749 function->shared()->increment_deopt_count(); 8750 return *result; 8751 } 8752 } 8753 8754 if (FLAG_trace_osr) { 8755 PrintF("[OSR - optimization failed for "); 8756 function->PrintName(); 8757 PrintF("]\n"); 8758 } 8759 8760 if (function->IsMarkedForLazyRecompilation() || 8761 function->IsMarkedForConcurrentRecompilation()) { 8762 function->ReplaceCode(function->shared()->code()); 8763 } 8764 return NULL; 8765 } 8766 8767 8768 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAllocationTimeout) { 8769 SealHandleScope shs(isolate); 8770 ASSERT(args.length() == 2); 8771 #ifdef DEBUG 8772 CONVERT_SMI_ARG_CHECKED(interval, 0); 8773 CONVERT_SMI_ARG_CHECKED(timeout, 1); 8774 isolate->heap()->set_allocation_timeout(timeout); 8775 FLAG_gc_interval = interval; 8776 #endif 8777 return isolate->heap()->undefined_value(); 8778 } 8779 8780 8781 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) { 8782 SealHandleScope shs(isolate); 8783 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8784 return isolate->heap()->undefined_value(); 8785 } 8786 8787 8788 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) { 8789 SealHandleScope shs(isolate); 8790 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive()); 8791 return isolate->heap()->nan_value(); 8792 } 8793 8794 8795 RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) { 8796 HandleScope scope(isolate); 8797 ASSERT(args.length() >= 2); 8798 int argc = args.length() - 2; 8799 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1); 8800 Object* receiver = args[0]; 8801 8802 // If there are too many arguments, allocate argv via malloc. 8803 const int argv_small_size = 10; 8804 Handle<Object> argv_small_buffer[argv_small_size]; 8805 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8806 Handle<Object>* argv = argv_small_buffer; 8807 if (argc > argv_small_size) { 8808 argv = new Handle<Object>[argc]; 8809 if (argv == NULL) return isolate->StackOverflow(); 8810 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8811 } 8812 8813 for (int i = 0; i < argc; ++i) { 8814 MaybeObject* maybe = args[1 + i]; 8815 Object* object; 8816 if (!maybe->To<Object>(&object)) return maybe; 8817 argv[i] = Handle<Object>(object, isolate); 8818 } 8819 8820 bool threw; 8821 Handle<JSReceiver> hfun(fun); 8822 Handle<Object> hreceiver(receiver, isolate); 8823 Handle<Object> result = Execution::Call( 8824 isolate, hfun, hreceiver, argc, argv, &threw, true); 8825 8826 if (threw) return Failure::Exception(); 8827 return *result; 8828 } 8829 8830 8831 RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) { 8832 HandleScope scope(isolate); 8833 ASSERT(args.length() == 5); 8834 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); 8835 Handle<Object> receiver = args.at<Object>(1); 8836 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); 8837 CONVERT_SMI_ARG_CHECKED(offset, 3); 8838 CONVERT_SMI_ARG_CHECKED(argc, 4); 8839 RUNTIME_ASSERT(offset >= 0); 8840 RUNTIME_ASSERT(argc >= 0); 8841 8842 // If there are too many arguments, allocate argv via malloc. 8843 const int argv_small_size = 10; 8844 Handle<Object> argv_small_buffer[argv_small_size]; 8845 SmartArrayPointer<Handle<Object> > argv_large_buffer; 8846 Handle<Object>* argv = argv_small_buffer; 8847 if (argc > argv_small_size) { 8848 argv = new Handle<Object>[argc]; 8849 if (argv == NULL) return isolate->StackOverflow(); 8850 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv); 8851 } 8852 8853 for (int i = 0; i < argc; ++i) { 8854 argv[i] = Object::GetElement(isolate, arguments, offset + i); 8855 } 8856 8857 bool threw; 8858 Handle<Object> result = Execution::Call( 8859 isolate, fun, receiver, argc, argv, &threw, true); 8860 8861 if (threw) return Failure::Exception(); 8862 return *result; 8863 } 8864 8865 8866 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) { 8867 HandleScope scope(isolate); 8868 ASSERT(args.length() == 1); 8869 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8870 return *Execution::GetFunctionDelegate(isolate, args.at<Object>(0)); 8871 } 8872 8873 8874 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) { 8875 HandleScope scope(isolate); 8876 ASSERT(args.length() == 1); 8877 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 8878 return *Execution::GetConstructorDelegate(isolate, args.at<Object>(0)); 8879 } 8880 8881 8882 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewGlobalContext) { 8883 SealHandleScope shs(isolate); 8884 ASSERT(args.length() == 2); 8885 8886 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8887 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 1); 8888 Context* result; 8889 MaybeObject* maybe_result = 8890 isolate->heap()->AllocateGlobalContext(function, scope_info); 8891 if (!maybe_result->To(&result)) return maybe_result; 8892 8893 ASSERT(function->context() == isolate->context()); 8894 ASSERT(function->context()->global_object() == result->global_object()); 8895 isolate->set_context(result); 8896 result->global_object()->set_global_context(result); 8897 8898 return result; // non-failure 8899 } 8900 8901 8902 RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) { 8903 SealHandleScope shs(isolate); 8904 ASSERT(args.length() == 1); 8905 8906 CONVERT_ARG_CHECKED(JSFunction, function, 0); 8907 int length = function->shared()->scope_info()->ContextLength(); 8908 Context* result; 8909 MaybeObject* maybe_result = 8910 isolate->heap()->AllocateFunctionContext(length, function); 8911 if (!maybe_result->To(&result)) return maybe_result; 8912 8913 isolate->set_context(result); 8914 8915 return result; // non-failure 8916 } 8917 8918 8919 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) { 8920 SealHandleScope shs(isolate); 8921 ASSERT(args.length() == 2); 8922 JSReceiver* extension_object; 8923 if (args[0]->IsJSReceiver()) { 8924 extension_object = JSReceiver::cast(args[0]); 8925 } else { 8926 // Convert the object to a proper JavaScript object. 8927 MaybeObject* maybe_js_object = args[0]->ToObject(isolate); 8928 if (!maybe_js_object->To(&extension_object)) { 8929 if (Failure::cast(maybe_js_object)->IsInternalError()) { 8930 HandleScope scope(isolate); 8931 Handle<Object> handle = args.at<Object>(0); 8932 Handle<Object> result = 8933 isolate->factory()->NewTypeError("with_expression", 8934 HandleVector(&handle, 1)); 8935 return isolate->Throw(*result); 8936 } else { 8937 return maybe_js_object; 8938 } 8939 } 8940 } 8941 8942 JSFunction* function; 8943 if (args[1]->IsSmi()) { 8944 // A smi sentinel indicates a context nested inside global code rather 8945 // than some function. There is a canonical empty function that can be 8946 // gotten from the native context. 8947 function = isolate->context()->native_context()->closure(); 8948 } else { 8949 function = JSFunction::cast(args[1]); 8950 } 8951 8952 Context* context; 8953 MaybeObject* maybe_context = 8954 isolate->heap()->AllocateWithContext(function, 8955 isolate->context(), 8956 extension_object); 8957 if (!maybe_context->To(&context)) return maybe_context; 8958 isolate->set_context(context); 8959 return context; 8960 } 8961 8962 8963 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) { 8964 SealHandleScope shs(isolate); 8965 ASSERT(args.length() == 3); 8966 String* name = String::cast(args[0]); 8967 Object* thrown_object = args[1]; 8968 JSFunction* function; 8969 if (args[2]->IsSmi()) { 8970 // A smi sentinel indicates a context nested inside global code rather 8971 // than some function. There is a canonical empty function that can be 8972 // gotten from the native context. 8973 function = isolate->context()->native_context()->closure(); 8974 } else { 8975 function = JSFunction::cast(args[2]); 8976 } 8977 Context* context; 8978 MaybeObject* maybe_context = 8979 isolate->heap()->AllocateCatchContext(function, 8980 isolate->context(), 8981 name, 8982 thrown_object); 8983 if (!maybe_context->To(&context)) return maybe_context; 8984 isolate->set_context(context); 8985 return context; 8986 } 8987 8988 8989 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) { 8990 SealHandleScope shs(isolate); 8991 ASSERT(args.length() == 2); 8992 ScopeInfo* scope_info = ScopeInfo::cast(args[0]); 8993 JSFunction* function; 8994 if (args[1]->IsSmi()) { 8995 // A smi sentinel indicates a context nested inside global code rather 8996 // than some function. There is a canonical empty function that can be 8997 // gotten from the native context. 8998 function = isolate->context()->native_context()->closure(); 8999 } else { 9000 function = JSFunction::cast(args[1]); 9001 } 9002 Context* context; 9003 MaybeObject* maybe_context = 9004 isolate->heap()->AllocateBlockContext(function, 9005 isolate->context(), 9006 scope_info); 9007 if (!maybe_context->To(&context)) return maybe_context; 9008 isolate->set_context(context); 9009 return context; 9010 } 9011 9012 9013 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSModule) { 9014 SealHandleScope shs(isolate); 9015 ASSERT(args.length() == 1); 9016 Object* obj = args[0]; 9017 return isolate->heap()->ToBoolean(obj->IsJSModule()); 9018 } 9019 9020 9021 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) { 9022 SealHandleScope shs(isolate); 9023 ASSERT(args.length() == 2); 9024 CONVERT_SMI_ARG_CHECKED(index, 0); 9025 9026 if (!args[1]->IsScopeInfo()) { 9027 // Module already initialized. Find hosting context and retrieve context. 9028 Context* host = Context::cast(isolate->context())->global_context(); 9029 Context* context = Context::cast(host->get(index)); 9030 ASSERT(context->previous() == isolate->context()); 9031 isolate->set_context(context); 9032 return context; 9033 } 9034 9035 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1); 9036 9037 // Allocate module context. 9038 HandleScope scope(isolate); 9039 Factory* factory = isolate->factory(); 9040 Handle<Context> context = factory->NewModuleContext(scope_info); 9041 Handle<JSModule> module = factory->NewJSModule(context, scope_info); 9042 context->set_module(*module); 9043 Context* previous = isolate->context(); 9044 context->set_previous(previous); 9045 context->set_closure(previous->closure()); 9046 context->set_global_object(previous->global_object()); 9047 isolate->set_context(*context); 9048 9049 // Find hosting scope and initialize internal variable holding module there. 9050 previous->global_context()->set(index, *context); 9051 9052 return *context; 9053 } 9054 9055 9056 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareModules) { 9057 HandleScope scope(isolate); 9058 ASSERT(args.length() == 1); 9059 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0); 9060 Context* host_context = isolate->context(); 9061 9062 for (int i = 0; i < descriptions->length(); ++i) { 9063 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i))); 9064 int host_index = description->host_index(); 9065 Handle<Context> context(Context::cast(host_context->get(host_index))); 9066 Handle<JSModule> module(context->module()); 9067 9068 for (int j = 0; j < description->length(); ++j) { 9069 Handle<String> name(description->name(j)); 9070 VariableMode mode = description->mode(j); 9071 int index = description->index(j); 9072 switch (mode) { 9073 case VAR: 9074 case LET: 9075 case CONST: 9076 case CONST_HARMONY: { 9077 PropertyAttributes attr = 9078 IsImmutableVariableMode(mode) ? FROZEN : SEALED; 9079 Handle<AccessorInfo> info = 9080 Accessors::MakeModuleExport(name, index, attr); 9081 Handle<Object> result = JSObject::SetAccessor(module, info); 9082 ASSERT(!(result.is_null() || result->IsUndefined())); 9083 USE(result); 9084 break; 9085 } 9086 case MODULE: { 9087 Object* referenced_context = Context::cast(host_context)->get(index); 9088 Handle<JSModule> value(Context::cast(referenced_context)->module()); 9089 JSReceiver::SetProperty(module, name, value, FROZEN, kStrictMode); 9090 break; 9091 } 9092 case INTERNAL: 9093 case TEMPORARY: 9094 case DYNAMIC: 9095 case DYNAMIC_GLOBAL: 9096 case DYNAMIC_LOCAL: 9097 UNREACHABLE(); 9098 } 9099 } 9100 9101 JSObject::PreventExtensions(module); 9102 } 9103 9104 ASSERT(!isolate->has_pending_exception()); 9105 return isolate->heap()->undefined_value(); 9106 } 9107 9108 9109 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) { 9110 HandleScope scope(isolate); 9111 ASSERT(args.length() == 2); 9112 9113 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0); 9114 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); 9115 9116 int index; 9117 PropertyAttributes attributes; 9118 ContextLookupFlags flags = FOLLOW_CHAINS; 9119 BindingFlags binding_flags; 9120 Handle<Object> holder = context->Lookup(name, 9121 flags, 9122 &index, 9123 &attributes, 9124 &binding_flags); 9125 9126 // If the slot was not found the result is true. 9127 if (holder.is_null()) { 9128 return isolate->heap()->true_value(); 9129 } 9130 9131 // If the slot was found in a context, it should be DONT_DELETE. 9132 if (holder->IsContext()) { 9133 return isolate->heap()->false_value(); 9134 } 9135 9136 // The slot was found in a JSObject, either a context extension object, 9137 // the global object, or the subject of a with. Try to delete it 9138 // (respecting DONT_DELETE). 9139 Handle<JSObject> object = Handle<JSObject>::cast(holder); 9140 Handle<Object> result = JSReceiver::DeleteProperty(object, name); 9141 RETURN_IF_EMPTY_HANDLE(isolate, result); 9142 return *result; 9143 } 9144 9145 9146 // A mechanism to return a pair of Object pointers in registers (if possible). 9147 // How this is achieved is calling convention-dependent. 9148 // All currently supported x86 compiles uses calling conventions that are cdecl 9149 // variants where a 64-bit value is returned in two 32-bit registers 9150 // (edx:eax on ia32, r1:r0 on ARM). 9151 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 9152 // In Win64 calling convention, a struct of two pointers is returned in memory, 9153 // allocated by the caller, and passed as a pointer in a hidden first parameter. 9154 #ifdef V8_HOST_ARCH_64_BIT 9155 struct ObjectPair { 9156 MaybeObject* x; 9157 MaybeObject* y; 9158 }; 9159 9160 9161 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 9162 ObjectPair result = {x, y}; 9163 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 9164 // In Win64 they are assigned to a hidden first argument. 9165 return result; 9166 } 9167 #else 9168 typedef uint64_t ObjectPair; 9169 static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) { 9170 return reinterpret_cast<uint32_t>(x) | 9171 (reinterpret_cast<ObjectPair>(y) << 32); 9172 } 9173 #endif 9174 9175 9176 static inline MaybeObject* Unhole(Heap* heap, 9177 MaybeObject* x, 9178 PropertyAttributes attributes) { 9179 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0); 9180 USE(attributes); 9181 return x->IsTheHole() ? heap->undefined_value() : x; 9182 } 9183 9184 9185 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, 9186 JSObject* holder) { 9187 ASSERT(!holder->IsGlobalObject()); 9188 Context* top = isolate->context(); 9189 // Get the context extension function. 9190 JSFunction* context_extension_function = 9191 top->native_context()->context_extension_function(); 9192 // If the holder isn't a context extension object, we just return it 9193 // as the receiver. This allows arguments objects to be used as 9194 // receivers, but only if they are put in the context scope chain 9195 // explicitly via a with-statement. 9196 Object* constructor = holder->map()->constructor(); 9197 if (constructor != context_extension_function) return holder; 9198 // Fall back to using the global object as the implicit receiver if 9199 // the property turns out to be a local variable allocated in a 9200 // context extension object - introduced via eval. Implicit global 9201 // receivers are indicated with the hole value. 9202 return isolate->heap()->the_hole_value(); 9203 } 9204 9205 9206 static ObjectPair LoadContextSlotHelper(Arguments args, 9207 Isolate* isolate, 9208 bool throw_error) { 9209 HandleScope scope(isolate); 9210 ASSERT_EQ(2, args.length()); 9211 9212 if (!args[0]->IsContext() || !args[1]->IsString()) { 9213 return MakePair(isolate->ThrowIllegalOperation(), NULL); 9214 } 9215 Handle<Context> context = args.at<Context>(0); 9216 Handle<String> name = args.at<String>(1); 9217 9218 int index; 9219 PropertyAttributes attributes; 9220 ContextLookupFlags flags = FOLLOW_CHAINS; 9221 BindingFlags binding_flags; 9222 Handle<Object> holder = context->Lookup(name, 9223 flags, 9224 &index, 9225 &attributes, 9226 &binding_flags); 9227 if (isolate->has_pending_exception()) { 9228 return MakePair(Failure::Exception(), NULL); 9229 } 9230 9231 // If the index is non-negative, the slot has been found in a context. 9232 if (index >= 0) { 9233 ASSERT(holder->IsContext()); 9234 // If the "property" we were looking for is a local variable, the 9235 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3. 9236 // 9237 // Use the hole as the receiver to signal that the receiver is implicit 9238 // and that the global receiver should be used (as distinguished from an 9239 // explicit receiver that happens to be a global object). 9240 Handle<Object> receiver = isolate->factory()->the_hole_value(); 9241 Object* value = Context::cast(*holder)->get(index); 9242 // Check for uninitialized bindings. 9243 switch (binding_flags) { 9244 case MUTABLE_CHECK_INITIALIZED: 9245 case IMMUTABLE_CHECK_INITIALIZED_HARMONY: 9246 if (value->IsTheHole()) { 9247 Handle<Object> reference_error = 9248 isolate->factory()->NewReferenceError("not_defined", 9249 HandleVector(&name, 1)); 9250 return MakePair(isolate->Throw(*reference_error), NULL); 9251 } 9252 // FALLTHROUGH 9253 case MUTABLE_IS_INITIALIZED: 9254 case IMMUTABLE_IS_INITIALIZED: 9255 case IMMUTABLE_IS_INITIALIZED_HARMONY: 9256 ASSERT(!value->IsTheHole()); 9257 return MakePair(value, *receiver); 9258 case IMMUTABLE_CHECK_INITIALIZED: 9259 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver); 9260 case MISSING_BINDING: 9261 UNREACHABLE(); 9262 return MakePair(NULL, NULL); 9263 } 9264 } 9265 9266 // Otherwise, if the slot was found the holder is a context extension 9267 // object, subject of a with, or a global object. We read the named 9268 // property from it. 9269 if (!holder.is_null()) { 9270 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder); 9271 ASSERT(object->IsJSProxy() || JSReceiver::HasProperty(object, name)); 9272 // GetProperty below can cause GC. 9273 Handle<Object> receiver_handle( 9274 object->IsGlobalObject() 9275 ? GlobalObject::cast(*object)->global_receiver() 9276 : object->IsJSProxy() ? static_cast<Object*>(*object) 9277 : ComputeReceiverForNonGlobal(isolate, JSObject::cast(*object)), 9278 isolate); 9279 9280 // No need to unhole the value here. This is taken care of by the 9281 // GetProperty function. 9282 MaybeObject* value = object->GetProperty(*name); 9283 return MakePair(value, *receiver_handle); 9284 } 9285 9286 if (throw_error) { 9287 // The property doesn't exist - throw exception. 9288 Handle<Object> reference_error = 9289 isolate->factory()->NewReferenceError("not_defined", 9290 HandleVector(&name, 1)); 9291 return MakePair(isolate->Throw(*reference_error), NULL); 9292 } else { 9293 // The property doesn't exist - return undefined. 9294 return MakePair(isolate->heap()->undefined_value(), 9295 isolate->heap()->undefined_value()); 9296 } 9297 } 9298 9299 9300 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) { 9301 return LoadContextSlotHelper(args, isolate, true); 9302 } 9303 9304 9305 RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) { 9306 return LoadContextSlotHelper(args, isolate, false); 9307 } 9308 9309 9310 RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) { 9311 HandleScope scope(isolate); 9312 ASSERT(args.length() == 4); 9313 9314 Handle<Object> value(args[0], isolate); 9315 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1); 9316 CONVERT_ARG_HANDLE_CHECKED(String, name, 2); 9317 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 9318 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE) 9319 ? kNonStrictMode : kStrictMode; 9320 9321 int index; 9322 PropertyAttributes attributes; 9323 ContextLookupFlags flags = FOLLOW_CHAINS; 9324 BindingFlags binding_flags; 9325 Handle<Object> holder = context->Lookup(name, 9326 flags, 9327 &index, 9328 &attributes, 9329 &binding_flags); 9330 if (isolate->has_pending_exception()) return Failure::Exception(); 9331 9332 if (index >= 0) { 9333 // The property was found in a context slot. 9334 Handle<Context> context = Handle<Context>::cast(holder); 9335 if (binding_flags == MUTABLE_CHECK_INITIALIZED && 9336 context->get(index)->IsTheHole()) { 9337 Handle<Object> error = 9338 isolate->factory()->NewReferenceError("not_defined", 9339 HandleVector(&name, 1)); 9340 return isolate->Throw(*error); 9341 } 9342 // Ignore if read_only variable. 9343 if ((attributes & READ_ONLY) == 0) { 9344 // Context is a fixed array and set cannot fail. 9345 context->set(index, *value); 9346 } else if (strict_mode == kStrictMode) { 9347 // Setting read only property in strict mode. 9348 Handle<Object> error = 9349 isolate->factory()->NewTypeError("strict_cannot_assign", 9350 HandleVector(&name, 1)); 9351 return isolate->Throw(*error); 9352 } 9353 return *value; 9354 } 9355 9356 // Slow case: The property is not in a context slot. It is either in a 9357 // context extension object, a property of the subject of a with, or a 9358 // property of the global object. 9359 Handle<JSReceiver> object; 9360 9361 if (!holder.is_null()) { 9362 // The property exists on the holder. 9363 object = Handle<JSReceiver>::cast(holder); 9364 } else { 9365 // The property was not found. 9366 ASSERT(attributes == ABSENT); 9367 9368 if (strict_mode == kStrictMode) { 9369 // Throw in strict mode (assignment to undefined variable). 9370 Handle<Object> error = 9371 isolate->factory()->NewReferenceError( 9372 "not_defined", HandleVector(&name, 1)); 9373 return isolate->Throw(*error); 9374 } 9375 // In non-strict mode, the property is added to the global object. 9376 attributes = NONE; 9377 object = Handle<JSReceiver>(isolate->context()->global_object()); 9378 } 9379 9380 // Set the property if it's not read only or doesn't yet exist. 9381 if ((attributes & READ_ONLY) == 0 || 9382 (object->GetLocalPropertyAttribute(*name) == ABSENT)) { 9383 RETURN_IF_EMPTY_HANDLE( 9384 isolate, 9385 JSReceiver::SetProperty(object, name, value, NONE, strict_mode)); 9386 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) { 9387 // Setting read only property in strict mode. 9388 Handle<Object> error = 9389 isolate->factory()->NewTypeError( 9390 "strict_cannot_assign", HandleVector(&name, 1)); 9391 return isolate->Throw(*error); 9392 } 9393 return *value; 9394 } 9395 9396 9397 RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) { 9398 HandleScope scope(isolate); 9399 ASSERT(args.length() == 1); 9400 9401 return isolate->Throw(args[0]); 9402 } 9403 9404 9405 RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) { 9406 HandleScope scope(isolate); 9407 ASSERT(args.length() == 1); 9408 9409 return isolate->ReThrow(args[0]); 9410 } 9411 9412 9413 RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) { 9414 SealHandleScope shs(isolate); 9415 ASSERT_EQ(0, args.length()); 9416 return isolate->PromoteScheduledException(); 9417 } 9418 9419 9420 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) { 9421 HandleScope scope(isolate); 9422 ASSERT(args.length() == 1); 9423 9424 Handle<Object> name(args[0], isolate); 9425 Handle<Object> reference_error = 9426 isolate->factory()->NewReferenceError("not_defined", 9427 HandleVector(&name, 1)); 9428 return isolate->Throw(*reference_error); 9429 } 9430 9431 9432 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowNotDateError) { 9433 HandleScope scope(isolate); 9434 ASSERT(args.length() == 0); 9435 return isolate->Throw(*isolate->factory()->NewTypeError( 9436 "not_date_object", HandleVector<Object>(NULL, 0))); 9437 } 9438 9439 9440 RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowMessage) { 9441 HandleScope scope(isolate); 9442 ASSERT(args.length() == 1); 9443 CONVERT_SMI_ARG_CHECKED(message_id, 0); 9444 const char* message = GetBailoutReason( 9445 static_cast<BailoutReason>(message_id)); 9446 Handle<Name> message_handle = 9447 isolate->factory()->NewStringFromAscii(CStrVector(message)); 9448 return isolate->Throw(*message_handle); 9449 } 9450 9451 9452 RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) { 9453 SealHandleScope shs(isolate); 9454 ASSERT(args.length() == 0); 9455 9456 // First check if this is a real stack overflow. 9457 if (isolate->stack_guard()->IsStackOverflow()) { 9458 return isolate->StackOverflow(); 9459 } 9460 9461 return Execution::HandleStackGuardInterrupt(isolate); 9462 } 9463 9464 9465 RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) { 9466 HandleScope scope(isolate); 9467 ASSERT(args.length() == 1); 9468 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 9469 9470 // First check if this is a real stack overflow. 9471 if (isolate->stack_guard()->IsStackOverflow()) { 9472 SealHandleScope shs(isolate); 9473 return isolate->StackOverflow(); 9474 } 9475 9476 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 9477 return (function->IsOptimized()) ? function->code() 9478 : function->shared()->code(); 9479 } 9480 9481 9482 RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) { 9483 SealHandleScope shs(isolate); 9484 ASSERT(args.length() == 0); 9485 return Execution::HandleStackGuardInterrupt(isolate); 9486 } 9487 9488 9489 static int StackSize(Isolate* isolate) { 9490 int n = 0; 9491 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) n++; 9492 return n; 9493 } 9494 9495 9496 static void PrintTransition(Isolate* isolate, Object* result) { 9497 // indentation 9498 { const int nmax = 80; 9499 int n = StackSize(isolate); 9500 if (n <= nmax) 9501 PrintF("%4d:%*s", n, n, ""); 9502 else 9503 PrintF("%4d:%*s", n, nmax, "..."); 9504 } 9505 9506 if (result == NULL) { 9507 JavaScriptFrame::PrintTop(isolate, stdout, true, false); 9508 PrintF(" {\n"); 9509 } else { 9510 // function result 9511 PrintF("} -> "); 9512 result->ShortPrint(); 9513 PrintF("\n"); 9514 } 9515 } 9516 9517 9518 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) { 9519 SealHandleScope shs(isolate); 9520 ASSERT(args.length() == 0); 9521 PrintTransition(isolate, NULL); 9522 return isolate->heap()->undefined_value(); 9523 } 9524 9525 9526 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) { 9527 SealHandleScope shs(isolate); 9528 PrintTransition(isolate, args[0]); 9529 return args[0]; // return TOS 9530 } 9531 9532 9533 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) { 9534 SealHandleScope shs(isolate); 9535 ASSERT(args.length() == 1); 9536 9537 #ifdef DEBUG 9538 if (args[0]->IsString()) { 9539 // If we have a string, assume it's a code "marker" 9540 // and print some interesting cpu debugging info. 9541 JavaScriptFrameIterator it(isolate); 9542 JavaScriptFrame* frame = it.frame(); 9543 PrintF("fp = %p, sp = %p, caller_sp = %p: ", 9544 frame->fp(), frame->sp(), frame->caller_sp()); 9545 } else { 9546 PrintF("DebugPrint: "); 9547 } 9548 args[0]->Print(); 9549 if (args[0]->IsHeapObject()) { 9550 PrintF("\n"); 9551 HeapObject::cast(args[0])->map()->Print(); 9552 } 9553 #else 9554 // ShortPrint is available in release mode. Print is not. 9555 args[0]->ShortPrint(); 9556 #endif 9557 PrintF("\n"); 9558 Flush(); 9559 9560 return args[0]; // return TOS 9561 } 9562 9563 9564 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) { 9565 SealHandleScope shs(isolate); 9566 ASSERT(args.length() == 0); 9567 isolate->PrintStack(stdout); 9568 return isolate->heap()->undefined_value(); 9569 } 9570 9571 9572 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) { 9573 SealHandleScope shs(isolate); 9574 ASSERT(args.length() == 0); 9575 9576 // According to ECMA-262, section 15.9.1, page 117, the precision of 9577 // the number in a Date object representing a particular instant in 9578 // time is milliseconds. Therefore, we floor the result of getting 9579 // the OS time. 9580 double millis = floor(OS::TimeCurrentMillis()); 9581 return isolate->heap()->NumberFromDouble(millis); 9582 } 9583 9584 9585 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) { 9586 HandleScope scope(isolate); 9587 ASSERT(args.length() == 2); 9588 9589 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 9590 FlattenString(str); 9591 9592 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1); 9593 9594 JSObject::EnsureCanContainHeapObjectElements(output); 9595 RUNTIME_ASSERT(output->HasFastObjectElements()); 9596 9597 DisallowHeapAllocation no_gc; 9598 9599 FixedArray* output_array = FixedArray::cast(output->elements()); 9600 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE); 9601 bool result; 9602 String::FlatContent str_content = str->GetFlatContent(); 9603 if (str_content.IsAscii()) { 9604 result = DateParser::Parse(str_content.ToOneByteVector(), 9605 output_array, 9606 isolate->unicode_cache()); 9607 } else { 9608 ASSERT(str_content.IsTwoByte()); 9609 result = DateParser::Parse(str_content.ToUC16Vector(), 9610 output_array, 9611 isolate->unicode_cache()); 9612 } 9613 9614 if (result) { 9615 return *output; 9616 } else { 9617 return isolate->heap()->null_value(); 9618 } 9619 } 9620 9621 9622 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) { 9623 SealHandleScope shs(isolate); 9624 ASSERT(args.length() == 1); 9625 9626 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9627 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x)); 9628 const char* zone = OS::LocalTimezone(static_cast<double>(time)); 9629 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone)); 9630 } 9631 9632 9633 RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) { 9634 SealHandleScope shs(isolate); 9635 ASSERT(args.length() == 1); 9636 9637 CONVERT_DOUBLE_ARG_CHECKED(x, 0); 9638 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x)); 9639 9640 return isolate->heap()->NumberFromDouble(static_cast<double>(time)); 9641 } 9642 9643 9644 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) { 9645 SealHandleScope shs(isolate); 9646 ASSERT(args.length() == 1); 9647 Object* global = args[0]; 9648 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value(); 9649 return JSGlobalObject::cast(global)->global_receiver(); 9650 } 9651 9652 9653 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAttachedGlobal) { 9654 SealHandleScope shs(isolate); 9655 ASSERT(args.length() == 1); 9656 Object* global = args[0]; 9657 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value(); 9658 return isolate->heap()->ToBoolean( 9659 !JSGlobalObject::cast(global)->IsDetached()); 9660 } 9661 9662 9663 RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) { 9664 HandleScope scope(isolate); 9665 ASSERT_EQ(1, args.length()); 9666 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9667 9668 source = Handle<String>(FlattenGetString(source)); 9669 // Optimized fast case where we only have ASCII characters. 9670 Handle<Object> result; 9671 if (source->IsSeqOneByteString()) { 9672 result = JsonParser<true>::Parse(source); 9673 } else { 9674 result = JsonParser<false>::Parse(source); 9675 } 9676 if (result.is_null()) { 9677 // Syntax error or stack overflow in scanner. 9678 ASSERT(isolate->has_pending_exception()); 9679 return Failure::Exception(); 9680 } 9681 return *result; 9682 } 9683 9684 9685 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 9686 Handle<Context> context) { 9687 ASSERT(context->allow_code_gen_from_strings()->IsFalse()); 9688 // Check with callback if set. 9689 AllowCodeGenerationFromStringsCallback callback = 9690 isolate->allow_code_gen_callback(); 9691 if (callback == NULL) { 9692 // No callback set and code generation disallowed. 9693 return false; 9694 } else { 9695 // Callback set. Let it decide if code generation is allowed. 9696 VMState<EXTERNAL> state(isolate); 9697 return callback(v8::Utils::ToLocal(context)); 9698 } 9699 } 9700 9701 9702 RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { 9703 HandleScope scope(isolate); 9704 ASSERT_EQ(2, args.length()); 9705 CONVERT_ARG_HANDLE_CHECKED(String, source, 0); 9706 CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1); 9707 9708 // Extract native context. 9709 Handle<Context> context(isolate->context()->native_context()); 9710 9711 // Check if native context allows code generation from 9712 // strings. Throw an exception if it doesn't. 9713 if (context->allow_code_gen_from_strings()->IsFalse() && 9714 !CodeGenerationFromStringsAllowed(isolate, context)) { 9715 Handle<Object> error_message = 9716 context->ErrorMessageForCodeGenerationFromStrings(); 9717 return isolate->Throw(*isolate->factory()->NewEvalError( 9718 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9719 } 9720 9721 // Compile source string in the native context. 9722 ParseRestriction restriction = function_literal_only 9723 ? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION; 9724 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9725 source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition); 9726 RETURN_IF_EMPTY_HANDLE(isolate, shared); 9727 Handle<JSFunction> fun = 9728 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 9729 context, 9730 NOT_TENURED); 9731 return *fun; 9732 } 9733 9734 9735 static ObjectPair CompileGlobalEval(Isolate* isolate, 9736 Handle<String> source, 9737 Handle<Object> receiver, 9738 LanguageMode language_mode, 9739 int scope_position) { 9740 Handle<Context> context = Handle<Context>(isolate->context()); 9741 Handle<Context> native_context = Handle<Context>(context->native_context()); 9742 9743 // Check if native context allows code generation from 9744 // strings. Throw an exception if it doesn't. 9745 if (native_context->allow_code_gen_from_strings()->IsFalse() && 9746 !CodeGenerationFromStringsAllowed(isolate, native_context)) { 9747 Handle<Object> error_message = 9748 native_context->ErrorMessageForCodeGenerationFromStrings(); 9749 isolate->Throw(*isolate->factory()->NewEvalError( 9750 "code_gen_from_strings", HandleVector<Object>(&error_message, 1))); 9751 return MakePair(Failure::Exception(), NULL); 9752 } 9753 9754 // Deal with a normal eval call with a string argument. Compile it 9755 // and return the compiled function bound in the local context. 9756 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 9757 source, 9758 context, 9759 context->IsNativeContext(), 9760 language_mode, 9761 NO_PARSE_RESTRICTION, 9762 scope_position); 9763 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared, 9764 MakePair(Failure::Exception(), NULL)); 9765 Handle<JSFunction> compiled = 9766 isolate->factory()->NewFunctionFromSharedFunctionInfo( 9767 shared, context, NOT_TENURED); 9768 return MakePair(*compiled, *receiver); 9769 } 9770 9771 9772 RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { 9773 HandleScope scope(isolate); 9774 ASSERT(args.length() == 5); 9775 9776 Handle<Object> callee = args.at<Object>(0); 9777 9778 // If "eval" didn't refer to the original GlobalEval, it's not a 9779 // direct call to eval. 9780 // (And even if it is, but the first argument isn't a string, just let 9781 // execution default to an indirect call to eval, which will also return 9782 // the first argument without doing anything). 9783 if (*callee != isolate->native_context()->global_eval_fun() || 9784 !args[1]->IsString()) { 9785 return MakePair(*callee, isolate->heap()->the_hole_value()); 9786 } 9787 9788 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3); 9789 ASSERT(args[4]->IsSmi()); 9790 return CompileGlobalEval(isolate, 9791 args.at<String>(1), 9792 args.at<Object>(2), 9793 language_mode, 9794 args.smi_at(4)); 9795 } 9796 9797 9798 // Allocate a block of memory in the given space (filled with a filler). 9799 // Used as a fall-back for generated code when the space is full. 9800 static MaybeObject* Allocate(Isolate* isolate, 9801 int size, 9802 bool double_align, 9803 AllocationSpace space) { 9804 Heap* heap = isolate->heap(); 9805 RUNTIME_ASSERT(IsAligned(size, kPointerSize)); 9806 RUNTIME_ASSERT(size > 0); 9807 RUNTIME_ASSERT(size <= heap->MaxRegularSpaceAllocationSize()); 9808 HeapObject* allocation; 9809 { MaybeObject* maybe_allocation = heap->AllocateRaw(size, space, space); 9810 if (!maybe_allocation->To(&allocation)) return maybe_allocation; 9811 } 9812 #ifdef DEBUG 9813 MemoryChunk* chunk = MemoryChunk::FromAddress(allocation->address()); 9814 ASSERT(chunk->owner()->identity() == space); 9815 #endif 9816 heap->CreateFillerObjectAt(allocation->address(), size); 9817 return allocation; 9818 } 9819 9820 9821 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) { 9822 SealHandleScope shs(isolate); 9823 ASSERT(args.length() == 1); 9824 CONVERT_SMI_ARG_CHECKED(size, 0); 9825 return Allocate(isolate, size, false, NEW_SPACE); 9826 } 9827 9828 9829 RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInTargetSpace) { 9830 SealHandleScope shs(isolate); 9831 ASSERT(args.length() == 2); 9832 CONVERT_SMI_ARG_CHECKED(size, 0); 9833 CONVERT_SMI_ARG_CHECKED(flags, 1); 9834 bool double_align = AllocateDoubleAlignFlag::decode(flags); 9835 AllocationSpace space = AllocateTargetSpace::decode(flags); 9836 return Allocate(isolate, size, double_align, space); 9837 } 9838 9839 9840 // Push an object unto an array of objects if it is not already in the 9841 // array. Returns true if the element was pushed on the stack and 9842 // false otherwise. 9843 RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) { 9844 HandleScope scope(isolate); 9845 ASSERT(args.length() == 2); 9846 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0); 9847 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1); 9848 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements()); 9849 int length = Smi::cast(array->length())->value(); 9850 FixedArray* elements = FixedArray::cast(array->elements()); 9851 for (int i = 0; i < length; i++) { 9852 if (elements->get(i) == *element) return isolate->heap()->false_value(); 9853 } 9854 9855 // Strict not needed. Used for cycle detection in Array join implementation. 9856 RETURN_IF_EMPTY_HANDLE(isolate, JSObject::SetFastElement(array, length, 9857 element, 9858 kNonStrictMode, 9859 true)); 9860 return isolate->heap()->true_value(); 9861 } 9862 9863 9864 /** 9865 * A simple visitor visits every element of Array's. 9866 * The backend storage can be a fixed array for fast elements case, 9867 * or a dictionary for sparse array. Since Dictionary is a subtype 9868 * of FixedArray, the class can be used by both fast and slow cases. 9869 * The second parameter of the constructor, fast_elements, specifies 9870 * whether the storage is a FixedArray or Dictionary. 9871 * 9872 * An index limit is used to deal with the situation that a result array 9873 * length overflows 32-bit non-negative integer. 9874 */ 9875 class ArrayConcatVisitor { 9876 public: 9877 ArrayConcatVisitor(Isolate* isolate, 9878 Handle<FixedArray> storage, 9879 bool fast_elements) : 9880 isolate_(isolate), 9881 storage_(Handle<FixedArray>::cast( 9882 isolate->global_handles()->Create(*storage))), 9883 index_offset_(0u), 9884 fast_elements_(fast_elements), 9885 exceeds_array_limit_(false) { } 9886 9887 ~ArrayConcatVisitor() { 9888 clear_storage(); 9889 } 9890 9891 void visit(uint32_t i, Handle<Object> elm) { 9892 if (i > JSObject::kMaxElementCount - index_offset_) { 9893 exceeds_array_limit_ = true; 9894 return; 9895 } 9896 uint32_t index = index_offset_ + i; 9897 9898 if (fast_elements_) { 9899 if (index < static_cast<uint32_t>(storage_->length())) { 9900 storage_->set(index, *elm); 9901 return; 9902 } 9903 // Our initial estimate of length was foiled, possibly by 9904 // getters on the arrays increasing the length of later arrays 9905 // during iteration. 9906 // This shouldn't happen in anything but pathological cases. 9907 SetDictionaryMode(index); 9908 // Fall-through to dictionary mode. 9909 } 9910 ASSERT(!fast_elements_); 9911 Handle<SeededNumberDictionary> dict( 9912 SeededNumberDictionary::cast(*storage_)); 9913 Handle<SeededNumberDictionary> result = 9914 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm); 9915 if (!result.is_identical_to(dict)) { 9916 // Dictionary needed to grow. 9917 clear_storage(); 9918 set_storage(*result); 9919 } 9920 } 9921 9922 void increase_index_offset(uint32_t delta) { 9923 if (JSObject::kMaxElementCount - index_offset_ < delta) { 9924 index_offset_ = JSObject::kMaxElementCount; 9925 } else { 9926 index_offset_ += delta; 9927 } 9928 } 9929 9930 bool exceeds_array_limit() { 9931 return exceeds_array_limit_; 9932 } 9933 9934 Handle<JSArray> ToArray() { 9935 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 9936 Handle<Object> length = 9937 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 9938 Handle<Map> map; 9939 if (fast_elements_) { 9940 map = isolate_->factory()->GetElementsTransitionMap(array, 9941 FAST_HOLEY_ELEMENTS); 9942 } else { 9943 map = isolate_->factory()->GetElementsTransitionMap(array, 9944 DICTIONARY_ELEMENTS); 9945 } 9946 array->set_map(*map); 9947 array->set_length(*length); 9948 array->set_elements(*storage_); 9949 return array; 9950 } 9951 9952 private: 9953 // Convert storage to dictionary mode. 9954 void SetDictionaryMode(uint32_t index) { 9955 ASSERT(fast_elements_); 9956 Handle<FixedArray> current_storage(*storage_); 9957 Handle<SeededNumberDictionary> slow_storage( 9958 isolate_->factory()->NewSeededNumberDictionary( 9959 current_storage->length())); 9960 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 9961 for (uint32_t i = 0; i < current_length; i++) { 9962 HandleScope loop_scope(isolate_); 9963 Handle<Object> element(current_storage->get(i), isolate_); 9964 if (!element->IsTheHole()) { 9965 Handle<SeededNumberDictionary> new_storage = 9966 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element); 9967 if (!new_storage.is_identical_to(slow_storage)) { 9968 slow_storage = loop_scope.CloseAndEscape(new_storage); 9969 } 9970 } 9971 } 9972 clear_storage(); 9973 set_storage(*slow_storage); 9974 fast_elements_ = false; 9975 } 9976 9977 inline void clear_storage() { 9978 isolate_->global_handles()->Destroy( 9979 Handle<Object>::cast(storage_).location()); 9980 } 9981 9982 inline void set_storage(FixedArray* storage) { 9983 storage_ = Handle<FixedArray>::cast( 9984 isolate_->global_handles()->Create(storage)); 9985 } 9986 9987 Isolate* isolate_; 9988 Handle<FixedArray> storage_; // Always a global handle. 9989 // Index after last seen index. Always less than or equal to 9990 // JSObject::kMaxElementCount. 9991 uint32_t index_offset_; 9992 bool fast_elements_ : 1; 9993 bool exceeds_array_limit_ : 1; 9994 }; 9995 9996 9997 static uint32_t EstimateElementCount(Handle<JSArray> array) { 9998 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 9999 int element_count = 0; 10000 switch (array->GetElementsKind()) { 10001 case FAST_SMI_ELEMENTS: 10002 case FAST_HOLEY_SMI_ELEMENTS: 10003 case FAST_ELEMENTS: 10004 case FAST_HOLEY_ELEMENTS: { 10005 // Fast elements can't have lengths that are not representable by 10006 // a 32-bit signed integer. 10007 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); 10008 int fast_length = static_cast<int>(length); 10009 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 10010 for (int i = 0; i < fast_length; i++) { 10011 if (!elements->get(i)->IsTheHole()) element_count++; 10012 } 10013 break; 10014 } 10015 case FAST_DOUBLE_ELEMENTS: 10016 case FAST_HOLEY_DOUBLE_ELEMENTS: { 10017 // Fast elements can't have lengths that are not representable by 10018 // a 32-bit signed integer. 10019 ASSERT(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); 10020 int fast_length = static_cast<int>(length); 10021 if (array->elements()->IsFixedArray()) { 10022 ASSERT(FixedArray::cast(array->elements())->length() == 0); 10023 break; 10024 } 10025 Handle<FixedDoubleArray> elements( 10026 FixedDoubleArray::cast(array->elements())); 10027 for (int i = 0; i < fast_length; i++) { 10028 if (!elements->is_the_hole(i)) element_count++; 10029 } 10030 break; 10031 } 10032 case DICTIONARY_ELEMENTS: { 10033 Handle<SeededNumberDictionary> dictionary( 10034 SeededNumberDictionary::cast(array->elements())); 10035 int capacity = dictionary->Capacity(); 10036 for (int i = 0; i < capacity; i++) { 10037 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate()); 10038 if (dictionary->IsKey(*key)) { 10039 element_count++; 10040 } 10041 } 10042 break; 10043 } 10044 case NON_STRICT_ARGUMENTS_ELEMENTS: 10045 case EXTERNAL_BYTE_ELEMENTS: 10046 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 10047 case EXTERNAL_SHORT_ELEMENTS: 10048 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 10049 case EXTERNAL_INT_ELEMENTS: 10050 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 10051 case EXTERNAL_FLOAT_ELEMENTS: 10052 case EXTERNAL_DOUBLE_ELEMENTS: 10053 case EXTERNAL_PIXEL_ELEMENTS: 10054 // External arrays are always dense. 10055 return length; 10056 } 10057 // As an estimate, we assume that the prototype doesn't contain any 10058 // inherited elements. 10059 return element_count; 10060 } 10061 10062 10063 10064 template<class ExternalArrayClass, class ElementType> 10065 static void IterateExternalArrayElements(Isolate* isolate, 10066 Handle<JSObject> receiver, 10067 bool elements_are_ints, 10068 bool elements_are_guaranteed_smis, 10069 ArrayConcatVisitor* visitor) { 10070 Handle<ExternalArrayClass> array( 10071 ExternalArrayClass::cast(receiver->elements())); 10072 uint32_t len = static_cast<uint32_t>(array->length()); 10073 10074 ASSERT(visitor != NULL); 10075 if (elements_are_ints) { 10076 if (elements_are_guaranteed_smis) { 10077 for (uint32_t j = 0; j < len; j++) { 10078 HandleScope loop_scope(isolate); 10079 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))), 10080 isolate); 10081 visitor->visit(j, e); 10082 } 10083 } else { 10084 for (uint32_t j = 0; j < len; j++) { 10085 HandleScope loop_scope(isolate); 10086 int64_t val = static_cast<int64_t>(array->get_scalar(j)); 10087 if (Smi::IsValid(static_cast<intptr_t>(val))) { 10088 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate); 10089 visitor->visit(j, e); 10090 } else { 10091 Handle<Object> e = 10092 isolate->factory()->NewNumber(static_cast<ElementType>(val)); 10093 visitor->visit(j, e); 10094 } 10095 } 10096 } 10097 } else { 10098 for (uint32_t j = 0; j < len; j++) { 10099 HandleScope loop_scope(isolate); 10100 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j)); 10101 visitor->visit(j, e); 10102 } 10103 } 10104 } 10105 10106 10107 // Used for sorting indices in a List<uint32_t>. 10108 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 10109 uint32_t a = *ap; 10110 uint32_t b = *bp; 10111 return (a == b) ? 0 : (a < b) ? -1 : 1; 10112 } 10113 10114 10115 static void CollectElementIndices(Handle<JSObject> object, 10116 uint32_t range, 10117 List<uint32_t>* indices) { 10118 Isolate* isolate = object->GetIsolate(); 10119 ElementsKind kind = object->GetElementsKind(); 10120 switch (kind) { 10121 case FAST_SMI_ELEMENTS: 10122 case FAST_ELEMENTS: 10123 case FAST_HOLEY_SMI_ELEMENTS: 10124 case FAST_HOLEY_ELEMENTS: { 10125 Handle<FixedArray> elements(FixedArray::cast(object->elements())); 10126 uint32_t length = static_cast<uint32_t>(elements->length()); 10127 if (range < length) length = range; 10128 for (uint32_t i = 0; i < length; i++) { 10129 if (!elements->get(i)->IsTheHole()) { 10130 indices->Add(i); 10131 } 10132 } 10133 break; 10134 } 10135 case FAST_HOLEY_DOUBLE_ELEMENTS: 10136 case FAST_DOUBLE_ELEMENTS: { 10137 // TODO(1810): Decide if it's worthwhile to implement this. 10138 UNREACHABLE(); 10139 break; 10140 } 10141 case DICTIONARY_ELEMENTS: { 10142 Handle<SeededNumberDictionary> dict( 10143 SeededNumberDictionary::cast(object->elements())); 10144 uint32_t capacity = dict->Capacity(); 10145 for (uint32_t j = 0; j < capacity; j++) { 10146 HandleScope loop_scope(isolate); 10147 Handle<Object> k(dict->KeyAt(j), isolate); 10148 if (dict->IsKey(*k)) { 10149 ASSERT(k->IsNumber()); 10150 uint32_t index = static_cast<uint32_t>(k->Number()); 10151 if (index < range) { 10152 indices->Add(index); 10153 } 10154 } 10155 } 10156 break; 10157 } 10158 default: { 10159 int dense_elements_length; 10160 switch (kind) { 10161 case EXTERNAL_PIXEL_ELEMENTS: { 10162 dense_elements_length = 10163 ExternalPixelArray::cast(object->elements())->length(); 10164 break; 10165 } 10166 case EXTERNAL_BYTE_ELEMENTS: { 10167 dense_elements_length = 10168 ExternalByteArray::cast(object->elements())->length(); 10169 break; 10170 } 10171 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 10172 dense_elements_length = 10173 ExternalUnsignedByteArray::cast(object->elements())->length(); 10174 break; 10175 } 10176 case EXTERNAL_SHORT_ELEMENTS: { 10177 dense_elements_length = 10178 ExternalShortArray::cast(object->elements())->length(); 10179 break; 10180 } 10181 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 10182 dense_elements_length = 10183 ExternalUnsignedShortArray::cast(object->elements())->length(); 10184 break; 10185 } 10186 case EXTERNAL_INT_ELEMENTS: { 10187 dense_elements_length = 10188 ExternalIntArray::cast(object->elements())->length(); 10189 break; 10190 } 10191 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 10192 dense_elements_length = 10193 ExternalUnsignedIntArray::cast(object->elements())->length(); 10194 break; 10195 } 10196 case EXTERNAL_FLOAT_ELEMENTS: { 10197 dense_elements_length = 10198 ExternalFloatArray::cast(object->elements())->length(); 10199 break; 10200 } 10201 case EXTERNAL_DOUBLE_ELEMENTS: { 10202 dense_elements_length = 10203 ExternalDoubleArray::cast(object->elements())->length(); 10204 break; 10205 } 10206 default: 10207 UNREACHABLE(); 10208 dense_elements_length = 0; 10209 break; 10210 } 10211 uint32_t length = static_cast<uint32_t>(dense_elements_length); 10212 if (range <= length) { 10213 length = range; 10214 // We will add all indices, so we might as well clear it first 10215 // and avoid duplicates. 10216 indices->Clear(); 10217 } 10218 for (uint32_t i = 0; i < length; i++) { 10219 indices->Add(i); 10220 } 10221 if (length == range) return; // All indices accounted for already. 10222 break; 10223 } 10224 } 10225 10226 Handle<Object> prototype(object->GetPrototype(), isolate); 10227 if (prototype->IsJSObject()) { 10228 // The prototype will usually have no inherited element indices, 10229 // but we have to check. 10230 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices); 10231 } 10232 } 10233 10234 10235 /** 10236 * A helper function that visits elements of a JSArray in numerical 10237 * order. 10238 * 10239 * The visitor argument called for each existing element in the array 10240 * with the element index and the element's value. 10241 * Afterwards it increments the base-index of the visitor by the array 10242 * length. 10243 * Returns false if any access threw an exception, otherwise true. 10244 */ 10245 static bool IterateElements(Isolate* isolate, 10246 Handle<JSArray> receiver, 10247 ArrayConcatVisitor* visitor) { 10248 uint32_t length = static_cast<uint32_t>(receiver->length()->Number()); 10249 switch (receiver->GetElementsKind()) { 10250 case FAST_SMI_ELEMENTS: 10251 case FAST_ELEMENTS: 10252 case FAST_HOLEY_SMI_ELEMENTS: 10253 case FAST_HOLEY_ELEMENTS: { 10254 // Run through the elements FixedArray and use HasElement and GetElement 10255 // to check the prototype for missing elements. 10256 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 10257 int fast_length = static_cast<int>(length); 10258 ASSERT(fast_length <= elements->length()); 10259 for (int j = 0; j < fast_length; j++) { 10260 HandleScope loop_scope(isolate); 10261 Handle<Object> element_value(elements->get(j), isolate); 10262 if (!element_value->IsTheHole()) { 10263 visitor->visit(j, element_value); 10264 } else if (JSReceiver::HasElement(receiver, j)) { 10265 // Call GetElement on receiver, not its prototype, or getters won't 10266 // have the correct receiver. 10267 element_value = Object::GetElement(isolate, receiver, j); 10268 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); 10269 visitor->visit(j, element_value); 10270 } 10271 } 10272 break; 10273 } 10274 case FAST_HOLEY_DOUBLE_ELEMENTS: 10275 case FAST_DOUBLE_ELEMENTS: { 10276 // Run through the elements FixedArray and use HasElement and GetElement 10277 // to check the prototype for missing elements. 10278 Handle<FixedDoubleArray> elements( 10279 FixedDoubleArray::cast(receiver->elements())); 10280 int fast_length = static_cast<int>(length); 10281 ASSERT(fast_length <= elements->length()); 10282 for (int j = 0; j < fast_length; j++) { 10283 HandleScope loop_scope(isolate); 10284 if (!elements->is_the_hole(j)) { 10285 double double_value = elements->get_scalar(j); 10286 Handle<Object> element_value = 10287 isolate->factory()->NewNumber(double_value); 10288 visitor->visit(j, element_value); 10289 } else if (JSReceiver::HasElement(receiver, j)) { 10290 // Call GetElement on receiver, not its prototype, or getters won't 10291 // have the correct receiver. 10292 Handle<Object> element_value = 10293 Object::GetElement(isolate, receiver, j); 10294 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false); 10295 visitor->visit(j, element_value); 10296 } 10297 } 10298 break; 10299 } 10300 case DICTIONARY_ELEMENTS: { 10301 Handle<SeededNumberDictionary> dict(receiver->element_dictionary()); 10302 List<uint32_t> indices(dict->Capacity() / 2); 10303 // Collect all indices in the object and the prototypes less 10304 // than length. This might introduce duplicates in the indices list. 10305 CollectElementIndices(receiver, length, &indices); 10306 indices.Sort(&compareUInt32); 10307 int j = 0; 10308 int n = indices.length(); 10309 while (j < n) { 10310 HandleScope loop_scope(isolate); 10311 uint32_t index = indices[j]; 10312 Handle<Object> element = Object::GetElement(isolate, receiver, index); 10313 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false); 10314 visitor->visit(index, element); 10315 // Skip to next different index (i.e., omit duplicates). 10316 do { 10317 j++; 10318 } while (j < n && indices[j] == index); 10319 } 10320 break; 10321 } 10322 case EXTERNAL_PIXEL_ELEMENTS: { 10323 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast( 10324 receiver->elements())); 10325 for (uint32_t j = 0; j < length; j++) { 10326 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate); 10327 visitor->visit(j, e); 10328 } 10329 break; 10330 } 10331 case EXTERNAL_BYTE_ELEMENTS: { 10332 IterateExternalArrayElements<ExternalByteArray, int8_t>( 10333 isolate, receiver, true, true, visitor); 10334 break; 10335 } 10336 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { 10337 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>( 10338 isolate, receiver, true, true, visitor); 10339 break; 10340 } 10341 case EXTERNAL_SHORT_ELEMENTS: { 10342 IterateExternalArrayElements<ExternalShortArray, int16_t>( 10343 isolate, receiver, true, true, visitor); 10344 break; 10345 } 10346 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: { 10347 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>( 10348 isolate, receiver, true, true, visitor); 10349 break; 10350 } 10351 case EXTERNAL_INT_ELEMENTS: { 10352 IterateExternalArrayElements<ExternalIntArray, int32_t>( 10353 isolate, receiver, true, false, visitor); 10354 break; 10355 } 10356 case EXTERNAL_UNSIGNED_INT_ELEMENTS: { 10357 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>( 10358 isolate, receiver, true, false, visitor); 10359 break; 10360 } 10361 case EXTERNAL_FLOAT_ELEMENTS: { 10362 IterateExternalArrayElements<ExternalFloatArray, float>( 10363 isolate, receiver, false, false, visitor); 10364 break; 10365 } 10366 case EXTERNAL_DOUBLE_ELEMENTS: { 10367 IterateExternalArrayElements<ExternalDoubleArray, double>( 10368 isolate, receiver, false, false, visitor); 10369 break; 10370 } 10371 default: 10372 UNREACHABLE(); 10373 break; 10374 } 10375 visitor->increase_index_offset(length); 10376 return true; 10377 } 10378 10379 10380 /** 10381 * Array::concat implementation. 10382 * See ECMAScript 262, 15.4.4.4. 10383 * TODO(581): Fix non-compliance for very large concatenations and update to 10384 * following the ECMAScript 5 specification. 10385 */ 10386 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) { 10387 HandleScope handle_scope(isolate); 10388 ASSERT(args.length() == 1); 10389 10390 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0); 10391 int argument_count = static_cast<int>(arguments->length()->Number()); 10392 RUNTIME_ASSERT(arguments->HasFastObjectElements()); 10393 Handle<FixedArray> elements(FixedArray::cast(arguments->elements())); 10394 10395 // Pass 1: estimate the length and number of elements of the result. 10396 // The actual length can be larger if any of the arguments have getters 10397 // that mutate other arguments (but will otherwise be precise). 10398 // The number of elements is precise if there are no inherited elements. 10399 10400 ElementsKind kind = FAST_SMI_ELEMENTS; 10401 10402 uint32_t estimate_result_length = 0; 10403 uint32_t estimate_nof_elements = 0; 10404 for (int i = 0; i < argument_count; i++) { 10405 HandleScope loop_scope(isolate); 10406 Handle<Object> obj(elements->get(i), isolate); 10407 uint32_t length_estimate; 10408 uint32_t element_estimate; 10409 if (obj->IsJSArray()) { 10410 Handle<JSArray> array(Handle<JSArray>::cast(obj)); 10411 length_estimate = static_cast<uint32_t>(array->length()->Number()); 10412 if (length_estimate != 0) { 10413 ElementsKind array_kind = 10414 GetPackedElementsKind(array->map()->elements_kind()); 10415 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) { 10416 kind = array_kind; 10417 } 10418 } 10419 element_estimate = EstimateElementCount(array); 10420 } else { 10421 if (obj->IsHeapObject()) { 10422 if (obj->IsNumber()) { 10423 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) { 10424 kind = FAST_DOUBLE_ELEMENTS; 10425 } 10426 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) { 10427 kind = FAST_ELEMENTS; 10428 } 10429 } 10430 length_estimate = 1; 10431 element_estimate = 1; 10432 } 10433 // Avoid overflows by capping at kMaxElementCount. 10434 if (JSObject::kMaxElementCount - estimate_result_length < 10435 length_estimate) { 10436 estimate_result_length = JSObject::kMaxElementCount; 10437 } else { 10438 estimate_result_length += length_estimate; 10439 } 10440 if (JSObject::kMaxElementCount - estimate_nof_elements < 10441 element_estimate) { 10442 estimate_nof_elements = JSObject::kMaxElementCount; 10443 } else { 10444 estimate_nof_elements += element_estimate; 10445 } 10446 } 10447 10448 // If estimated number of elements is more than half of length, a 10449 // fixed array (fast case) is more time and space-efficient than a 10450 // dictionary. 10451 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length; 10452 10453 Handle<FixedArray> storage; 10454 if (fast_case) { 10455 if (kind == FAST_DOUBLE_ELEMENTS) { 10456 Handle<FixedDoubleArray> double_storage = 10457 isolate->factory()->NewFixedDoubleArray(estimate_result_length); 10458 int j = 0; 10459 bool failure = false; 10460 for (int i = 0; i < argument_count; i++) { 10461 Handle<Object> obj(elements->get(i), isolate); 10462 if (obj->IsSmi()) { 10463 double_storage->set(j, Smi::cast(*obj)->value()); 10464 j++; 10465 } else if (obj->IsNumber()) { 10466 double_storage->set(j, obj->Number()); 10467 j++; 10468 } else { 10469 JSArray* array = JSArray::cast(*obj); 10470 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 10471 switch (array->map()->elements_kind()) { 10472 case FAST_HOLEY_DOUBLE_ELEMENTS: 10473 case FAST_DOUBLE_ELEMENTS: { 10474 // Empty fixed array indicates that there are no elements. 10475 if (array->elements()->IsFixedArray()) break; 10476 FixedDoubleArray* elements = 10477 FixedDoubleArray::cast(array->elements()); 10478 for (uint32_t i = 0; i < length; i++) { 10479 if (elements->is_the_hole(i)) { 10480 failure = true; 10481 break; 10482 } 10483 double double_value = elements->get_scalar(i); 10484 double_storage->set(j, double_value); 10485 j++; 10486 } 10487 break; 10488 } 10489 case FAST_HOLEY_SMI_ELEMENTS: 10490 case FAST_SMI_ELEMENTS: { 10491 FixedArray* elements( 10492 FixedArray::cast(array->elements())); 10493 for (uint32_t i = 0; i < length; i++) { 10494 Object* element = elements->get(i); 10495 if (element->IsTheHole()) { 10496 failure = true; 10497 break; 10498 } 10499 int32_t int_value = Smi::cast(element)->value(); 10500 double_storage->set(j, int_value); 10501 j++; 10502 } 10503 break; 10504 } 10505 case FAST_HOLEY_ELEMENTS: 10506 ASSERT_EQ(0, length); 10507 break; 10508 default: 10509 UNREACHABLE(); 10510 } 10511 } 10512 if (failure) break; 10513 } 10514 Handle<JSArray> array = isolate->factory()->NewJSArray(0); 10515 Smi* length = Smi::FromInt(j); 10516 Handle<Map> map; 10517 map = isolate->factory()->GetElementsTransitionMap(array, kind); 10518 array->set_map(*map); 10519 array->set_length(length); 10520 array->set_elements(*double_storage); 10521 return *array; 10522 } 10523 // The backing storage array must have non-existing elements to preserve 10524 // holes across concat operations. 10525 storage = isolate->factory()->NewFixedArrayWithHoles( 10526 estimate_result_length); 10527 } else { 10528 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 10529 uint32_t at_least_space_for = estimate_nof_elements + 10530 (estimate_nof_elements >> 2); 10531 storage = Handle<FixedArray>::cast( 10532 isolate->factory()->NewSeededNumberDictionary(at_least_space_for)); 10533 } 10534 10535 ArrayConcatVisitor visitor(isolate, storage, fast_case); 10536 10537 for (int i = 0; i < argument_count; i++) { 10538 Handle<Object> obj(elements->get(i), isolate); 10539 if (obj->IsJSArray()) { 10540 Handle<JSArray> array = Handle<JSArray>::cast(obj); 10541 if (!IterateElements(isolate, array, &visitor)) { 10542 return Failure::Exception(); 10543 } 10544 } else { 10545 visitor.visit(0, obj); 10546 visitor.increase_index_offset(1); 10547 } 10548 } 10549 10550 if (visitor.exceeds_array_limit()) { 10551 return isolate->Throw( 10552 *isolate->factory()->NewRangeError("invalid_array_length", 10553 HandleVector<Object>(NULL, 0))); 10554 } 10555 return *visitor.ToArray(); 10556 } 10557 10558 10559 // This will not allocate (flatten the string), but it may run 10560 // very slowly for very deeply nested ConsStrings. For debugging use only. 10561 RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) { 10562 SealHandleScope shs(isolate); 10563 ASSERT(args.length() == 1); 10564 10565 CONVERT_ARG_CHECKED(String, string, 0); 10566 ConsStringIteratorOp op; 10567 StringCharacterStream stream(string, &op); 10568 while (stream.HasMore()) { 10569 uint16_t character = stream.GetNext(); 10570 PrintF("%c", character); 10571 } 10572 return string; 10573 } 10574 10575 10576 // Moves all own elements of an object, that are below a limit, to positions 10577 // starting at zero. All undefined values are placed after non-undefined values, 10578 // and are followed by non-existing element. Does not change the length 10579 // property. 10580 // Returns the number of non-undefined elements collected. 10581 RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) { 10582 HandleScope scope(isolate); 10583 ASSERT(args.length() == 2); 10584 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); 10585 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]); 10586 return *JSObject::PrepareElementsForSort(object, limit); 10587 } 10588 10589 10590 // Move contents of argument 0 (an array) to argument 1 (an array) 10591 RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) { 10592 SealHandleScope shs(isolate); 10593 ASSERT(args.length() == 2); 10594 CONVERT_ARG_CHECKED(JSArray, from, 0); 10595 CONVERT_ARG_CHECKED(JSArray, to, 1); 10596 from->ValidateElements(); 10597 to->ValidateElements(); 10598 FixedArrayBase* new_elements = from->elements(); 10599 ElementsKind from_kind = from->GetElementsKind(); 10600 MaybeObject* maybe_new_map; 10601 maybe_new_map = to->GetElementsTransitionMap(isolate, from_kind); 10602 Object* new_map; 10603 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; 10604 to->set_map_and_elements(Map::cast(new_map), new_elements); 10605 to->set_length(from->length()); 10606 Object* obj; 10607 { MaybeObject* maybe_obj = from->ResetElements(); 10608 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 10609 } 10610 from->set_length(Smi::FromInt(0)); 10611 to->ValidateElements(); 10612 return to; 10613 } 10614 10615 10616 // How many elements does this object/array have? 10617 RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) { 10618 SealHandleScope shs(isolate); 10619 ASSERT(args.length() == 1); 10620 CONVERT_ARG_CHECKED(JSObject, object, 0); 10621 HeapObject* elements = object->elements(); 10622 if (elements->IsDictionary()) { 10623 int result = SeededNumberDictionary::cast(elements)->NumberOfElements(); 10624 return Smi::FromInt(result); 10625 } else if (object->IsJSArray()) { 10626 return JSArray::cast(object)->length(); 10627 } else { 10628 return Smi::FromInt(FixedArray::cast(elements)->length()); 10629 } 10630 } 10631 10632 10633 // Returns an array that tells you where in the [0, length) interval an array 10634 // might have elements. Can either return an array of keys (positive integers 10635 // or undefined) or a number representing the positive length of an interval 10636 // starting at index 0. 10637 // Intervals can span over some keys that are not in the object. 10638 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) { 10639 HandleScope scope(isolate); 10640 ASSERT(args.length() == 2); 10641 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); 10642 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]); 10643 if (array->elements()->IsDictionary()) { 10644 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array(); 10645 for (Handle<Object> p = array; 10646 !p->IsNull(); 10647 p = Handle<Object>(p->GetPrototype(isolate), isolate)) { 10648 if (p->IsJSProxy() || JSObject::cast(*p)->HasIndexedInterceptor()) { 10649 // Bail out if we find a proxy or interceptor, likely not worth 10650 // collecting keys in that case. 10651 return *isolate->factory()->NewNumberFromUint(length); 10652 } 10653 Handle<JSObject> current = Handle<JSObject>::cast(p); 10654 Handle<FixedArray> current_keys = 10655 isolate->factory()->NewFixedArray( 10656 current->NumberOfLocalElements(NONE)); 10657 current->GetLocalElementKeys(*current_keys, NONE); 10658 keys = UnionOfKeys(keys, current_keys); 10659 } 10660 // Erase any keys >= length. 10661 // TODO(adamk): Remove this step when the contract of %GetArrayKeys 10662 // is changed to let this happen on the JS side. 10663 for (int i = 0; i < keys->length(); i++) { 10664 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i); 10665 } 10666 return *isolate->factory()->NewJSArrayWithElements(keys); 10667 } else { 10668 ASSERT(array->HasFastSmiOrObjectElements() || 10669 array->HasFastDoubleElements()); 10670 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length()); 10671 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length)); 10672 } 10673 } 10674 10675 10676 RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) { 10677 HandleScope scope(isolate); 10678 ASSERT(args.length() == 3); 10679 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0); 10680 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10681 CONVERT_SMI_ARG_CHECKED(flag, 2); 10682 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER; 10683 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value(); 10684 Handle<Object> result = 10685 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component); 10686 RETURN_IF_EMPTY_HANDLE(isolate, result); 10687 return *result; 10688 } 10689 10690 10691 #ifdef ENABLE_DEBUGGER_SUPPORT 10692 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) { 10693 SealHandleScope shs(isolate); 10694 ASSERT(args.length() == 0); 10695 return Execution::DebugBreakHelper(isolate); 10696 } 10697 10698 10699 // Helper functions for wrapping and unwrapping stack frame ids. 10700 static Smi* WrapFrameId(StackFrame::Id id) { 10701 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4))); 10702 return Smi::FromInt(id >> 2); 10703 } 10704 10705 10706 static StackFrame::Id UnwrapFrameId(int wrapped) { 10707 return static_cast<StackFrame::Id>(wrapped << 2); 10708 } 10709 10710 10711 // Adds a JavaScript function as a debug event listener. 10712 // args[0]: debug event listener function to set or null or undefined for 10713 // clearing the event listener function 10714 // args[1]: object supplied during callback 10715 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) { 10716 SealHandleScope shs(isolate); 10717 ASSERT(args.length() == 2); 10718 RUNTIME_ASSERT(args[0]->IsJSFunction() || 10719 args[0]->IsUndefined() || 10720 args[0]->IsNull()); 10721 Handle<Object> callback = args.at<Object>(0); 10722 Handle<Object> data = args.at<Object>(1); 10723 isolate->debugger()->SetEventListener(callback, data); 10724 10725 return isolate->heap()->undefined_value(); 10726 } 10727 10728 10729 RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) { 10730 SealHandleScope shs(isolate); 10731 ASSERT(args.length() == 0); 10732 isolate->stack_guard()->DebugBreak(); 10733 return isolate->heap()->undefined_value(); 10734 } 10735 10736 10737 static MaybeObject* DebugLookupResultValue(Heap* heap, 10738 Object* receiver, 10739 Name* name, 10740 LookupResult* result, 10741 bool* caught_exception) { 10742 Object* value; 10743 switch (result->type()) { 10744 case NORMAL: 10745 value = result->holder()->GetNormalizedProperty(result); 10746 if (value->IsTheHole()) { 10747 return heap->undefined_value(); 10748 } 10749 return value; 10750 case FIELD: { 10751 Object* value; 10752 MaybeObject* maybe_value = 10753 JSObject::cast(result->holder())->FastPropertyAt( 10754 result->representation(), 10755 result->GetFieldIndex().field_index()); 10756 if (!maybe_value->To(&value)) return maybe_value; 10757 if (value->IsTheHole()) { 10758 return heap->undefined_value(); 10759 } 10760 return value; 10761 } 10762 case CONSTANT: 10763 return result->GetConstant(); 10764 case CALLBACKS: { 10765 Object* structure = result->GetCallbackObject(); 10766 if (structure->IsForeign() || structure->IsAccessorInfo()) { 10767 Isolate* isolate = heap->isolate(); 10768 HandleScope scope(isolate); 10769 Handle<Object> value = JSObject::GetPropertyWithCallback( 10770 handle(result->holder(), isolate), 10771 handle(receiver, isolate), 10772 handle(structure, isolate), 10773 handle(name, isolate)); 10774 if (value.is_null()) { 10775 MaybeObject* exception = heap->isolate()->pending_exception(); 10776 heap->isolate()->clear_pending_exception(); 10777 if (caught_exception != NULL) *caught_exception = true; 10778 return exception; 10779 } 10780 return *value; 10781 } else { 10782 return heap->undefined_value(); 10783 } 10784 } 10785 case INTERCEPTOR: 10786 case TRANSITION: 10787 return heap->undefined_value(); 10788 case HANDLER: 10789 case NONEXISTENT: 10790 UNREACHABLE(); 10791 return heap->undefined_value(); 10792 } 10793 UNREACHABLE(); // keep the compiler happy 10794 return heap->undefined_value(); 10795 } 10796 10797 10798 // Get debugger related details for an object property. 10799 // args[0]: object holding property 10800 // args[1]: name of the property 10801 // 10802 // The array returned contains the following information: 10803 // 0: Property value 10804 // 1: Property details 10805 // 2: Property value is exception 10806 // 3: Getter function if defined 10807 // 4: Setter function if defined 10808 // Items 2-4 are only filled if the property has either a getter or a setter 10809 // defined through __defineGetter__ and/or __defineSetter__. 10810 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) { 10811 HandleScope scope(isolate); 10812 10813 ASSERT(args.length() == 2); 10814 10815 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10816 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10817 10818 // Make sure to set the current context to the context before the debugger was 10819 // entered (if the debugger is entered). The reason for switching context here 10820 // is that for some property lookups (accessors and interceptors) callbacks 10821 // into the embedding application can occour, and the embedding application 10822 // could have the assumption that its own native context is the current 10823 // context and not some internal debugger context. 10824 SaveContext save(isolate); 10825 if (isolate->debug()->InDebugger()) { 10826 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext()); 10827 } 10828 10829 // Skip the global proxy as it has no properties and always delegates to the 10830 // real global object. 10831 if (obj->IsJSGlobalProxy()) { 10832 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype())); 10833 } 10834 10835 10836 // Check if the name is trivially convertible to an index and get the element 10837 // if so. 10838 uint32_t index; 10839 if (name->AsArrayIndex(&index)) { 10840 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2); 10841 Object* element_or_char; 10842 { MaybeObject* maybe_element_or_char = 10843 Runtime::GetElementOrCharAt(isolate, obj, index); 10844 if (!maybe_element_or_char->ToObject(&element_or_char)) { 10845 return maybe_element_or_char; 10846 } 10847 } 10848 details->set(0, element_or_char); 10849 details->set( 10850 1, PropertyDetails(NONE, NORMAL, Representation::None()).AsSmi()); 10851 return *isolate->factory()->NewJSArrayWithElements(details); 10852 } 10853 10854 // Find the number of objects making up this. 10855 int length = LocalPrototypeChainLength(*obj); 10856 10857 // Try local lookup on each of the objects. 10858 Handle<JSObject> jsproto = obj; 10859 for (int i = 0; i < length; i++) { 10860 LookupResult result(isolate); 10861 jsproto->LocalLookup(*name, &result); 10862 if (result.IsFound()) { 10863 // LookupResult is not GC safe as it holds raw object pointers. 10864 // GC can happen later in this code so put the required fields into 10865 // local variables using handles when required for later use. 10866 Handle<Object> result_callback_obj; 10867 if (result.IsPropertyCallbacks()) { 10868 result_callback_obj = Handle<Object>(result.GetCallbackObject(), 10869 isolate); 10870 } 10871 Smi* property_details = result.GetPropertyDetails().AsSmi(); 10872 // DebugLookupResultValue can cause GC so details from LookupResult needs 10873 // to be copied to handles before this. 10874 bool caught_exception = false; 10875 Object* raw_value; 10876 { MaybeObject* maybe_raw_value = 10877 DebugLookupResultValue(isolate->heap(), *obj, *name, 10878 &result, &caught_exception); 10879 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value; 10880 } 10881 Handle<Object> value(raw_value, isolate); 10882 10883 // If the callback object is a fixed array then it contains JavaScript 10884 // getter and/or setter. 10885 bool hasJavaScriptAccessors = result.IsPropertyCallbacks() && 10886 result_callback_obj->IsAccessorPair(); 10887 Handle<FixedArray> details = 10888 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2); 10889 details->set(0, *value); 10890 details->set(1, property_details); 10891 if (hasJavaScriptAccessors) { 10892 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj); 10893 details->set(2, isolate->heap()->ToBoolean(caught_exception)); 10894 details->set(3, accessors->GetComponent(ACCESSOR_GETTER)); 10895 details->set(4, accessors->GetComponent(ACCESSOR_SETTER)); 10896 } 10897 10898 return *isolate->factory()->NewJSArrayWithElements(details); 10899 } 10900 if (i < length - 1) { 10901 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype())); 10902 } 10903 } 10904 10905 return isolate->heap()->undefined_value(); 10906 } 10907 10908 10909 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) { 10910 HandleScope scope(isolate); 10911 10912 ASSERT(args.length() == 2); 10913 10914 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10915 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10916 10917 LookupResult result(isolate); 10918 obj->Lookup(*name, &result); 10919 if (result.IsFound()) { 10920 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL); 10921 } 10922 return isolate->heap()->undefined_value(); 10923 } 10924 10925 10926 // Return the property type calculated from the property details. 10927 // args[0]: smi with property details. 10928 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) { 10929 SealHandleScope shs(isolate); 10930 ASSERT(args.length() == 1); 10931 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10932 return Smi::FromInt(static_cast<int>(details.type())); 10933 } 10934 10935 10936 // Return the property attribute calculated from the property details. 10937 // args[0]: smi with property details. 10938 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) { 10939 SealHandleScope shs(isolate); 10940 ASSERT(args.length() == 1); 10941 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10942 return Smi::FromInt(static_cast<int>(details.attributes())); 10943 } 10944 10945 10946 // Return the property insertion index calculated from the property details. 10947 // args[0]: smi with property details. 10948 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) { 10949 SealHandleScope shs(isolate); 10950 ASSERT(args.length() == 1); 10951 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0); 10952 // TODO(verwaest): Depends on the type of details. 10953 return Smi::FromInt(details.dictionary_index()); 10954 } 10955 10956 10957 // Return property value from named interceptor. 10958 // args[0]: object 10959 // args[1]: property name 10960 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) { 10961 HandleScope scope(isolate); 10962 ASSERT(args.length() == 2); 10963 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10964 RUNTIME_ASSERT(obj->HasNamedInterceptor()); 10965 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1); 10966 10967 PropertyAttributes attributes; 10968 Handle<Object> result = 10969 JSObject::GetPropertyWithInterceptor(obj, obj, name, &attributes); 10970 RETURN_IF_EMPTY_HANDLE(isolate, result); 10971 return *result; 10972 } 10973 10974 10975 // Return element value from indexed interceptor. 10976 // args[0]: object 10977 // args[1]: index 10978 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) { 10979 HandleScope scope(isolate); 10980 ASSERT(args.length() == 2); 10981 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0); 10982 RUNTIME_ASSERT(obj->HasIndexedInterceptor()); 10983 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]); 10984 10985 return obj->GetElementWithInterceptor(*obj, index); 10986 } 10987 10988 10989 RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) { 10990 SealHandleScope shs(isolate); 10991 ASSERT(args.length() >= 1); 10992 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]); 10993 // Check that the break id is valid. 10994 if (isolate->debug()->break_id() == 0 || 10995 break_id != isolate->debug()->break_id()) { 10996 return isolate->Throw( 10997 isolate->heap()->illegal_execution_state_string()); 10998 } 10999 11000 return isolate->heap()->true_value(); 11001 } 11002 11003 11004 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) { 11005 HandleScope scope(isolate); 11006 ASSERT(args.length() == 1); 11007 11008 // Check arguments. 11009 Object* result; 11010 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 11011 RUNTIME_ARGUMENTS(isolate, args)); 11012 if (!maybe_result->ToObject(&result)) return maybe_result; 11013 } 11014 11015 // Count all frames which are relevant to debugging stack trace. 11016 int n = 0; 11017 StackFrame::Id id = isolate->debug()->break_frame_id(); 11018 if (id == StackFrame::NO_ID) { 11019 // If there is no JavaScript stack frame count is 0. 11020 return Smi::FromInt(0); 11021 } 11022 11023 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) { 11024 n += it.frame()->GetInlineCount(); 11025 } 11026 return Smi::FromInt(n); 11027 } 11028 11029 11030 class FrameInspector { 11031 public: 11032 FrameInspector(JavaScriptFrame* frame, 11033 int inlined_jsframe_index, 11034 Isolate* isolate) 11035 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) { 11036 // Calculate the deoptimized frame. 11037 if (frame->is_optimized()) { 11038 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame( 11039 frame, inlined_jsframe_index, isolate); 11040 } 11041 has_adapted_arguments_ = frame_->has_adapted_arguments(); 11042 is_bottommost_ = inlined_jsframe_index == 0; 11043 is_optimized_ = frame_->is_optimized(); 11044 } 11045 11046 ~FrameInspector() { 11047 // Get rid of the calculated deoptimized frame if any. 11048 if (deoptimized_frame_ != NULL) { 11049 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, 11050 isolate_); 11051 } 11052 } 11053 11054 int GetParametersCount() { 11055 return is_optimized_ 11056 ? deoptimized_frame_->parameters_count() 11057 : frame_->ComputeParametersCount(); 11058 } 11059 int expression_count() { return deoptimized_frame_->expression_count(); } 11060 Object* GetFunction() { 11061 return is_optimized_ 11062 ? deoptimized_frame_->GetFunction() 11063 : frame_->function(); 11064 } 11065 Object* GetParameter(int index) { 11066 return is_optimized_ 11067 ? deoptimized_frame_->GetParameter(index) 11068 : frame_->GetParameter(index); 11069 } 11070 Object* GetExpression(int index) { 11071 return is_optimized_ 11072 ? deoptimized_frame_->GetExpression(index) 11073 : frame_->GetExpression(index); 11074 } 11075 int GetSourcePosition() { 11076 return is_optimized_ 11077 ? deoptimized_frame_->GetSourcePosition() 11078 : frame_->LookupCode()->SourcePosition(frame_->pc()); 11079 } 11080 bool IsConstructor() { 11081 return is_optimized_ && !is_bottommost_ 11082 ? deoptimized_frame_->HasConstructStub() 11083 : frame_->IsConstructor(); 11084 } 11085 11086 // To inspect all the provided arguments the frame might need to be 11087 // replaced with the arguments frame. 11088 void SetArgumentsFrame(JavaScriptFrame* frame) { 11089 ASSERT(has_adapted_arguments_); 11090 frame_ = frame; 11091 is_optimized_ = frame_->is_optimized(); 11092 ASSERT(!is_optimized_); 11093 } 11094 11095 private: 11096 JavaScriptFrame* frame_; 11097 DeoptimizedFrameInfo* deoptimized_frame_; 11098 Isolate* isolate_; 11099 bool is_optimized_; 11100 bool is_bottommost_; 11101 bool has_adapted_arguments_; 11102 11103 DISALLOW_COPY_AND_ASSIGN(FrameInspector); 11104 }; 11105 11106 11107 static const int kFrameDetailsFrameIdIndex = 0; 11108 static const int kFrameDetailsReceiverIndex = 1; 11109 static const int kFrameDetailsFunctionIndex = 2; 11110 static const int kFrameDetailsArgumentCountIndex = 3; 11111 static const int kFrameDetailsLocalCountIndex = 4; 11112 static const int kFrameDetailsSourcePositionIndex = 5; 11113 static const int kFrameDetailsConstructCallIndex = 6; 11114 static const int kFrameDetailsAtReturnIndex = 7; 11115 static const int kFrameDetailsFlagsIndex = 8; 11116 static const int kFrameDetailsFirstDynamicIndex = 9; 11117 11118 11119 static SaveContext* FindSavedContextForFrame(Isolate* isolate, 11120 JavaScriptFrame* frame) { 11121 SaveContext* save = isolate->save_context(); 11122 while (save != NULL && !save->IsBelowFrame(frame)) { 11123 save = save->prev(); 11124 } 11125 ASSERT(save != NULL); 11126 return save; 11127 } 11128 11129 11130 // Return an array with frame details 11131 // args[0]: number: break id 11132 // args[1]: number: frame index 11133 // 11134 // The array returned contains the following information: 11135 // 0: Frame id 11136 // 1: Receiver 11137 // 2: Function 11138 // 3: Argument count 11139 // 4: Local count 11140 // 5: Source position 11141 // 6: Constructor call 11142 // 7: Is at return 11143 // 8: Flags 11144 // Arguments name, value 11145 // Locals name, value 11146 // Return value if any 11147 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) { 11148 HandleScope scope(isolate); 11149 ASSERT(args.length() == 2); 11150 11151 // Check arguments. 11152 Object* check; 11153 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 11154 RUNTIME_ARGUMENTS(isolate, args)); 11155 if (!maybe_check->ToObject(&check)) return maybe_check; 11156 } 11157 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 11158 Heap* heap = isolate->heap(); 11159 11160 // Find the relevant frame with the requested index. 11161 StackFrame::Id id = isolate->debug()->break_frame_id(); 11162 if (id == StackFrame::NO_ID) { 11163 // If there are no JavaScript stack frames return undefined. 11164 return heap->undefined_value(); 11165 } 11166 11167 int count = 0; 11168 JavaScriptFrameIterator it(isolate, id); 11169 for (; !it.done(); it.Advance()) { 11170 if (index < count + it.frame()->GetInlineCount()) break; 11171 count += it.frame()->GetInlineCount(); 11172 } 11173 if (it.done()) return heap->undefined_value(); 11174 11175 bool is_optimized = it.frame()->is_optimized(); 11176 11177 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame. 11178 if (is_optimized) { 11179 inlined_jsframe_index = 11180 it.frame()->GetInlineCount() - (index - count) - 1; 11181 } 11182 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate); 11183 11184 // Traverse the saved contexts chain to find the active context for the 11185 // selected frame. 11186 SaveContext* save = FindSavedContextForFrame(isolate, it.frame()); 11187 11188 // Get the frame id. 11189 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate); 11190 11191 // Find source position in unoptimized code. 11192 int position = frame_inspector.GetSourcePosition(); 11193 11194 // Check for constructor frame. 11195 bool constructor = frame_inspector.IsConstructor(); 11196 11197 // Get scope info and read from it for local variable information. 11198 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11199 Handle<SharedFunctionInfo> shared(function->shared()); 11200 Handle<ScopeInfo> scope_info(shared->scope_info()); 11201 ASSERT(*scope_info != ScopeInfo::Empty(isolate)); 11202 11203 // Get the locals names and values into a temporary array. 11204 // 11205 // TODO(1240907): Hide compiler-introduced stack variables 11206 // (e.g. .result)? For users of the debugger, they will probably be 11207 // confusing. 11208 Handle<FixedArray> locals = 11209 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2); 11210 11211 // Fill in the values of the locals. 11212 int i = 0; 11213 for (; i < scope_info->StackLocalCount(); ++i) { 11214 // Use the value from the stack. 11215 locals->set(i * 2, scope_info->LocalName(i)); 11216 locals->set(i * 2 + 1, frame_inspector.GetExpression(i)); 11217 } 11218 if (i < scope_info->LocalCount()) { 11219 // Get the context containing declarations. 11220 Handle<Context> context( 11221 Context::cast(it.frame()->context())->declaration_context()); 11222 for (; i < scope_info->LocalCount(); ++i) { 11223 Handle<String> name(scope_info->LocalName(i)); 11224 VariableMode mode; 11225 InitializationFlag init_flag; 11226 locals->set(i * 2, *name); 11227 locals->set(i * 2 + 1, context->get( 11228 scope_info->ContextSlotIndex(*name, &mode, &init_flag))); 11229 } 11230 } 11231 11232 // Check whether this frame is positioned at return. If not top 11233 // frame or if the frame is optimized it cannot be at a return. 11234 bool at_return = false; 11235 if (!is_optimized && index == 0) { 11236 at_return = isolate->debug()->IsBreakAtReturn(it.frame()); 11237 } 11238 11239 // If positioned just before return find the value to be returned and add it 11240 // to the frame information. 11241 Handle<Object> return_value = isolate->factory()->undefined_value(); 11242 if (at_return) { 11243 StackFrameIterator it2(isolate); 11244 Address internal_frame_sp = NULL; 11245 while (!it2.done()) { 11246 if (it2.frame()->is_internal()) { 11247 internal_frame_sp = it2.frame()->sp(); 11248 } else { 11249 if (it2.frame()->is_java_script()) { 11250 if (it2.frame()->id() == it.frame()->id()) { 11251 // The internal frame just before the JavaScript frame contains the 11252 // value to return on top. A debug break at return will create an 11253 // internal frame to store the return value (eax/rax/r0) before 11254 // entering the debug break exit frame. 11255 if (internal_frame_sp != NULL) { 11256 return_value = 11257 Handle<Object>(Memory::Object_at(internal_frame_sp), 11258 isolate); 11259 break; 11260 } 11261 } 11262 } 11263 11264 // Indicate that the previous frame was not an internal frame. 11265 internal_frame_sp = NULL; 11266 } 11267 it2.Advance(); 11268 } 11269 } 11270 11271 // Now advance to the arguments adapter frame (if any). It contains all 11272 // the provided parameters whereas the function frame always have the number 11273 // of arguments matching the functions parameters. The rest of the 11274 // information (except for what is collected above) is the same. 11275 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) { 11276 it.AdvanceToArgumentsFrame(); 11277 frame_inspector.SetArgumentsFrame(it.frame()); 11278 } 11279 11280 // Find the number of arguments to fill. At least fill the number of 11281 // parameters for the function and fill more if more parameters are provided. 11282 int argument_count = scope_info->ParameterCount(); 11283 if (argument_count < frame_inspector.GetParametersCount()) { 11284 argument_count = frame_inspector.GetParametersCount(); 11285 } 11286 11287 // Calculate the size of the result. 11288 int details_size = kFrameDetailsFirstDynamicIndex + 11289 2 * (argument_count + scope_info->LocalCount()) + 11290 (at_return ? 1 : 0); 11291 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 11292 11293 // Add the frame id. 11294 details->set(kFrameDetailsFrameIdIndex, *frame_id); 11295 11296 // Add the function (same as in function frame). 11297 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction()); 11298 11299 // Add the arguments count. 11300 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count)); 11301 11302 // Add the locals count 11303 details->set(kFrameDetailsLocalCountIndex, 11304 Smi::FromInt(scope_info->LocalCount())); 11305 11306 // Add the source position. 11307 if (position != RelocInfo::kNoPosition) { 11308 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position)); 11309 } else { 11310 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value()); 11311 } 11312 11313 // Add the constructor information. 11314 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor)); 11315 11316 // Add the at return information. 11317 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return)); 11318 11319 // Add flags to indicate information on whether this frame is 11320 // bit 0: invoked in the debugger context. 11321 // bit 1: optimized frame. 11322 // bit 2: inlined in optimized frame 11323 int flags = 0; 11324 if (*save->context() == *isolate->debug()->debug_context()) { 11325 flags |= 1 << 0; 11326 } 11327 if (is_optimized) { 11328 flags |= 1 << 1; 11329 flags |= inlined_jsframe_index << 2; 11330 } 11331 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags)); 11332 11333 // Fill the dynamic part. 11334 int details_index = kFrameDetailsFirstDynamicIndex; 11335 11336 // Add arguments name and value. 11337 for (int i = 0; i < argument_count; i++) { 11338 // Name of the argument. 11339 if (i < scope_info->ParameterCount()) { 11340 details->set(details_index++, scope_info->ParameterName(i)); 11341 } else { 11342 details->set(details_index++, heap->undefined_value()); 11343 } 11344 11345 // Parameter value. 11346 if (i < frame_inspector.GetParametersCount()) { 11347 // Get the value from the stack. 11348 details->set(details_index++, frame_inspector.GetParameter(i)); 11349 } else { 11350 details->set(details_index++, heap->undefined_value()); 11351 } 11352 } 11353 11354 // Add locals name and value from the temporary copy from the function frame. 11355 for (int i = 0; i < scope_info->LocalCount() * 2; i++) { 11356 details->set(details_index++, locals->get(i)); 11357 } 11358 11359 // Add the value being returned. 11360 if (at_return) { 11361 details->set(details_index++, *return_value); 11362 } 11363 11364 // Add the receiver (same as in function frame). 11365 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE 11366 // THE FRAME ITERATOR TO WRAP THE RECEIVER. 11367 Handle<Object> receiver(it.frame()->receiver(), isolate); 11368 if (!receiver->IsJSObject() && 11369 shared->is_classic_mode() && 11370 !function->IsBuiltin()) { 11371 // If the receiver is not a JSObject and the function is not a 11372 // builtin or strict-mode we have hit an optimization where a 11373 // value object is not converted into a wrapped JS objects. To 11374 // hide this optimization from the debugger, we wrap the receiver 11375 // by creating correct wrapper object based on the calling frame's 11376 // native context. 11377 it.Advance(); 11378 Handle<Context> calling_frames_native_context( 11379 Context::cast(Context::cast(it.frame()->context())->native_context())); 11380 ASSERT(!receiver->IsUndefined() && !receiver->IsNull()); 11381 receiver = 11382 isolate->factory()->ToObject(receiver, calling_frames_native_context); 11383 } 11384 details->set(kFrameDetailsReceiverIndex, *receiver); 11385 11386 ASSERT_EQ(details_size, details_index); 11387 return *isolate->factory()->NewJSArrayWithElements(details); 11388 } 11389 11390 11391 // Create a plain JSObject which materializes the local scope for the specified 11392 // frame. 11393 static Handle<JSObject> MaterializeStackLocalsWithFrameInspector( 11394 Isolate* isolate, 11395 Handle<JSObject> target, 11396 Handle<JSFunction> function, 11397 FrameInspector* frame_inspector) { 11398 Handle<SharedFunctionInfo> shared(function->shared()); 11399 Handle<ScopeInfo> scope_info(shared->scope_info()); 11400 11401 // First fill all parameters. 11402 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11403 Handle<Object> value(i < frame_inspector->GetParametersCount() 11404 ? frame_inspector->GetParameter(i) 11405 : isolate->heap()->undefined_value(), 11406 isolate); 11407 ASSERT(!value->IsTheHole()); 11408 11409 RETURN_IF_EMPTY_HANDLE_VALUE( 11410 isolate, 11411 Runtime::SetObjectProperty(isolate, 11412 target, 11413 Handle<String>(scope_info->ParameterName(i)), 11414 value, 11415 NONE, 11416 kNonStrictMode), 11417 Handle<JSObject>()); 11418 } 11419 11420 // Second fill all stack locals. 11421 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11422 Handle<Object> value(frame_inspector->GetExpression(i), isolate); 11423 if (value->IsTheHole()) continue; 11424 11425 RETURN_IF_EMPTY_HANDLE_VALUE( 11426 isolate, 11427 Runtime::SetObjectProperty( 11428 isolate, 11429 target, 11430 Handle<String>(scope_info->StackLocalName(i)), 11431 value, 11432 NONE, 11433 kNonStrictMode), 11434 Handle<JSObject>()); 11435 } 11436 11437 return target; 11438 } 11439 11440 11441 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, 11442 Handle<JSObject> target, 11443 Handle<JSFunction> function, 11444 JavaScriptFrame* frame, 11445 int inlined_jsframe_index) { 11446 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11447 // Optimized frames are not supported. 11448 // TODO(yangguo): make sure all code deoptimized when debugger is active 11449 // and assert that this cannot happen. 11450 return; 11451 } 11452 11453 Handle<SharedFunctionInfo> shared(function->shared()); 11454 Handle<ScopeInfo> scope_info(shared->scope_info()); 11455 11456 // Parameters. 11457 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11458 ASSERT(!frame->GetParameter(i)->IsTheHole()); 11459 HandleScope scope(isolate); 11460 Handle<Object> value = GetProperty( 11461 isolate, target, Handle<String>(scope_info->ParameterName(i))); 11462 frame->SetParameterValue(i, *value); 11463 } 11464 11465 // Stack locals. 11466 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11467 if (frame->GetExpression(i)->IsTheHole()) continue; 11468 HandleScope scope(isolate); 11469 Handle<Object> value = GetProperty( 11470 isolate, target, Handle<String>(scope_info->StackLocalName(i))); 11471 frame->SetExpression(i, *value); 11472 } 11473 } 11474 11475 11476 static Handle<JSObject> MaterializeLocalContext(Isolate* isolate, 11477 Handle<JSObject> target, 11478 Handle<JSFunction> function, 11479 JavaScriptFrame* frame) { 11480 HandleScope scope(isolate); 11481 Handle<SharedFunctionInfo> shared(function->shared()); 11482 Handle<ScopeInfo> scope_info(shared->scope_info()); 11483 11484 if (!scope_info->HasContext()) return target; 11485 11486 // Third fill all context locals. 11487 Handle<Context> frame_context(Context::cast(frame->context())); 11488 Handle<Context> function_context(frame_context->declaration_context()); 11489 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11490 scope_info, function_context, target)) { 11491 return Handle<JSObject>(); 11492 } 11493 11494 // Finally copy any properties from the function context extension. 11495 // These will be variables introduced by eval. 11496 if (function_context->closure() == *function) { 11497 if (function_context->has_extension() && 11498 !function_context->IsNativeContext()) { 11499 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11500 bool threw = false; 11501 Handle<FixedArray> keys = 11502 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 11503 if (threw) return Handle<JSObject>(); 11504 11505 for (int i = 0; i < keys->length(); i++) { 11506 // Names of variables introduced by eval are strings. 11507 ASSERT(keys->get(i)->IsString()); 11508 Handle<String> key(String::cast(keys->get(i))); 11509 RETURN_IF_EMPTY_HANDLE_VALUE( 11510 isolate, 11511 Runtime::SetObjectProperty(isolate, 11512 target, 11513 key, 11514 GetProperty(isolate, ext, key), 11515 NONE, 11516 kNonStrictMode), 11517 Handle<JSObject>()); 11518 } 11519 } 11520 } 11521 11522 return target; 11523 } 11524 11525 11526 static Handle<JSObject> MaterializeLocalScope( 11527 Isolate* isolate, 11528 JavaScriptFrame* frame, 11529 int inlined_jsframe_index) { 11530 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 11531 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 11532 11533 Handle<JSObject> local_scope = 11534 isolate->factory()->NewJSObject(isolate->object_function()); 11535 local_scope = MaterializeStackLocalsWithFrameInspector( 11536 isolate, local_scope, function, &frame_inspector); 11537 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>()); 11538 11539 return MaterializeLocalContext(isolate, local_scope, function, frame); 11540 } 11541 11542 11543 // Set the context local variable value. 11544 static bool SetContextLocalValue(Isolate* isolate, 11545 Handle<ScopeInfo> scope_info, 11546 Handle<Context> context, 11547 Handle<String> variable_name, 11548 Handle<Object> new_value) { 11549 for (int i = 0; i < scope_info->ContextLocalCount(); i++) { 11550 Handle<String> next_name(scope_info->ContextLocalName(i)); 11551 if (variable_name->Equals(*next_name)) { 11552 VariableMode mode; 11553 InitializationFlag init_flag; 11554 int context_index = 11555 scope_info->ContextSlotIndex(*next_name, &mode, &init_flag); 11556 context->set(context_index, *new_value); 11557 return true; 11558 } 11559 } 11560 11561 return false; 11562 } 11563 11564 11565 static bool SetLocalVariableValue(Isolate* isolate, 11566 JavaScriptFrame* frame, 11567 int inlined_jsframe_index, 11568 Handle<String> variable_name, 11569 Handle<Object> new_value) { 11570 if (inlined_jsframe_index != 0 || frame->is_optimized()) { 11571 // Optimized frames are not supported. 11572 return false; 11573 } 11574 11575 Handle<JSFunction> function(frame->function()); 11576 Handle<SharedFunctionInfo> shared(function->shared()); 11577 Handle<ScopeInfo> scope_info(shared->scope_info()); 11578 11579 bool default_result = false; 11580 11581 // Parameters. 11582 for (int i = 0; i < scope_info->ParameterCount(); ++i) { 11583 if (scope_info->ParameterName(i)->Equals(*variable_name)) { 11584 frame->SetParameterValue(i, *new_value); 11585 // Argument might be shadowed in heap context, don't stop here. 11586 default_result = true; 11587 } 11588 } 11589 11590 // Stack locals. 11591 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { 11592 if (scope_info->StackLocalName(i)->Equals(*variable_name)) { 11593 frame->SetExpression(i, *new_value); 11594 return true; 11595 } 11596 } 11597 11598 if (scope_info->HasContext()) { 11599 // Context locals. 11600 Handle<Context> frame_context(Context::cast(frame->context())); 11601 Handle<Context> function_context(frame_context->declaration_context()); 11602 if (SetContextLocalValue( 11603 isolate, scope_info, function_context, variable_name, new_value)) { 11604 return true; 11605 } 11606 11607 // Function context extension. These are variables introduced by eval. 11608 if (function_context->closure() == *function) { 11609 if (function_context->has_extension() && 11610 !function_context->IsNativeContext()) { 11611 Handle<JSObject> ext(JSObject::cast(function_context->extension())); 11612 11613 if (JSReceiver::HasProperty(ext, variable_name)) { 11614 // We don't expect this to do anything except replacing 11615 // property value. 11616 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, 11617 NONE, 11618 kNonStrictMode); 11619 return true; 11620 } 11621 } 11622 } 11623 } 11624 11625 return default_result; 11626 } 11627 11628 11629 // Create a plain JSObject which materializes the closure content for the 11630 // context. 11631 static Handle<JSObject> MaterializeClosure(Isolate* isolate, 11632 Handle<Context> context) { 11633 ASSERT(context->IsFunctionContext()); 11634 11635 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11636 Handle<ScopeInfo> scope_info(shared->scope_info()); 11637 11638 // Allocate and initialize a JSObject with all the content of this function 11639 // closure. 11640 Handle<JSObject> closure_scope = 11641 isolate->factory()->NewJSObject(isolate->object_function()); 11642 11643 // Fill all context locals to the context extension. 11644 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11645 scope_info, context, closure_scope)) { 11646 return Handle<JSObject>(); 11647 } 11648 11649 // Finally copy any properties from the function context extension. This will 11650 // be variables introduced by eval. 11651 if (context->has_extension()) { 11652 Handle<JSObject> ext(JSObject::cast(context->extension())); 11653 bool threw = false; 11654 Handle<FixedArray> keys = 11655 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw); 11656 if (threw) return Handle<JSObject>(); 11657 11658 for (int i = 0; i < keys->length(); i++) { 11659 // Names of variables introduced by eval are strings. 11660 ASSERT(keys->get(i)->IsString()); 11661 Handle<String> key(String::cast(keys->get(i))); 11662 RETURN_IF_EMPTY_HANDLE_VALUE( 11663 isolate, 11664 Runtime::SetObjectProperty(isolate, closure_scope, key, 11665 GetProperty(isolate, ext, key), 11666 NONE, 11667 kNonStrictMode), 11668 Handle<JSObject>()); 11669 } 11670 } 11671 11672 return closure_scope; 11673 } 11674 11675 11676 // This method copies structure of MaterializeClosure method above. 11677 static bool SetClosureVariableValue(Isolate* isolate, 11678 Handle<Context> context, 11679 Handle<String> variable_name, 11680 Handle<Object> new_value) { 11681 ASSERT(context->IsFunctionContext()); 11682 11683 Handle<SharedFunctionInfo> shared(context->closure()->shared()); 11684 Handle<ScopeInfo> scope_info(shared->scope_info()); 11685 11686 // Context locals to the context extension. 11687 if (SetContextLocalValue( 11688 isolate, scope_info, context, variable_name, new_value)) { 11689 return true; 11690 } 11691 11692 // Properties from the function context extension. This will 11693 // be variables introduced by eval. 11694 if (context->has_extension()) { 11695 Handle<JSObject> ext(JSObject::cast(context->extension())); 11696 if (JSReceiver::HasProperty(ext, variable_name)) { 11697 // We don't expect this to do anything except replacing property value. 11698 Runtime::SetObjectProperty(isolate, ext, variable_name, new_value, 11699 NONE, 11700 kNonStrictMode); 11701 return true; 11702 } 11703 } 11704 11705 return false; 11706 } 11707 11708 11709 // Create a plain JSObject which materializes the scope for the specified 11710 // catch context. 11711 static Handle<JSObject> MaterializeCatchScope(Isolate* isolate, 11712 Handle<Context> context) { 11713 ASSERT(context->IsCatchContext()); 11714 Handle<String> name(String::cast(context->extension())); 11715 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX), 11716 isolate); 11717 Handle<JSObject> catch_scope = 11718 isolate->factory()->NewJSObject(isolate->object_function()); 11719 RETURN_IF_EMPTY_HANDLE_VALUE( 11720 isolate, 11721 Runtime::SetObjectProperty(isolate, catch_scope, name, thrown_object, 11722 NONE, 11723 kNonStrictMode), 11724 Handle<JSObject>()); 11725 return catch_scope; 11726 } 11727 11728 11729 static bool SetCatchVariableValue(Isolate* isolate, 11730 Handle<Context> context, 11731 Handle<String> variable_name, 11732 Handle<Object> new_value) { 11733 ASSERT(context->IsCatchContext()); 11734 Handle<String> name(String::cast(context->extension())); 11735 if (!name->Equals(*variable_name)) { 11736 return false; 11737 } 11738 context->set(Context::THROWN_OBJECT_INDEX, *new_value); 11739 return true; 11740 } 11741 11742 11743 // Create a plain JSObject which materializes the block scope for the specified 11744 // block context. 11745 static Handle<JSObject> MaterializeBlockScope( 11746 Isolate* isolate, 11747 Handle<Context> context) { 11748 ASSERT(context->IsBlockContext()); 11749 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11750 11751 // Allocate and initialize a JSObject with all the arguments, stack locals 11752 // heap locals and extension properties of the debugged function. 11753 Handle<JSObject> block_scope = 11754 isolate->factory()->NewJSObject(isolate->object_function()); 11755 11756 // Fill all context locals. 11757 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11758 scope_info, context, block_scope)) { 11759 return Handle<JSObject>(); 11760 } 11761 11762 return block_scope; 11763 } 11764 11765 11766 // Create a plain JSObject which materializes the module scope for the specified 11767 // module context. 11768 static Handle<JSObject> MaterializeModuleScope( 11769 Isolate* isolate, 11770 Handle<Context> context) { 11771 ASSERT(context->IsModuleContext()); 11772 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); 11773 11774 // Allocate and initialize a JSObject with all the members of the debugged 11775 // module. 11776 Handle<JSObject> module_scope = 11777 isolate->factory()->NewJSObject(isolate->object_function()); 11778 11779 // Fill all context locals. 11780 if (!ScopeInfo::CopyContextLocalsToScopeObject( 11781 scope_info, context, module_scope)) { 11782 return Handle<JSObject>(); 11783 } 11784 11785 return module_scope; 11786 } 11787 11788 11789 // Iterate over the actual scopes visible from a stack frame or from a closure. 11790 // The iteration proceeds from the innermost visible nested scope outwards. 11791 // All scopes are backed by an actual context except the local scope, 11792 // which is inserted "artificially" in the context chain. 11793 class ScopeIterator { 11794 public: 11795 enum ScopeType { 11796 ScopeTypeGlobal = 0, 11797 ScopeTypeLocal, 11798 ScopeTypeWith, 11799 ScopeTypeClosure, 11800 ScopeTypeCatch, 11801 ScopeTypeBlock, 11802 ScopeTypeModule 11803 }; 11804 11805 ScopeIterator(Isolate* isolate, 11806 JavaScriptFrame* frame, 11807 int inlined_jsframe_index) 11808 : isolate_(isolate), 11809 frame_(frame), 11810 inlined_jsframe_index_(inlined_jsframe_index), 11811 function_(frame->function()), 11812 context_(Context::cast(frame->context())), 11813 nested_scope_chain_(4), 11814 failed_(false) { 11815 11816 // Catch the case when the debugger stops in an internal function. 11817 Handle<SharedFunctionInfo> shared_info(function_->shared()); 11818 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11819 if (shared_info->script() == isolate->heap()->undefined_value()) { 11820 while (context_->closure() == *function_) { 11821 context_ = Handle<Context>(context_->previous(), isolate_); 11822 } 11823 return; 11824 } 11825 11826 // Get the debug info (create it if it does not exist). 11827 if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) { 11828 // Return if ensuring debug info failed. 11829 return; 11830 } 11831 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info); 11832 11833 // Find the break point where execution has stopped. 11834 BreakLocationIterator break_location_iterator(debug_info, 11835 ALL_BREAK_LOCATIONS); 11836 // pc points to the instruction after the current one, possibly a break 11837 // location as well. So the "- 1" to exclude it from the search. 11838 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); 11839 if (break_location_iterator.IsExit()) { 11840 // We are within the return sequence. At the momemt it is not possible to 11841 // get a source position which is consistent with the current scope chain. 11842 // Thus all nested with, catch and block contexts are skipped and we only 11843 // provide the function scope. 11844 if (scope_info->HasContext()) { 11845 context_ = Handle<Context>(context_->declaration_context(), isolate_); 11846 } else { 11847 while (context_->closure() == *function_) { 11848 context_ = Handle<Context>(context_->previous(), isolate_); 11849 } 11850 } 11851 if (scope_info->scope_type() != EVAL_SCOPE) { 11852 nested_scope_chain_.Add(scope_info); 11853 } 11854 } else { 11855 // Reparse the code and analyze the scopes. 11856 Handle<Script> script(Script::cast(shared_info->script())); 11857 Scope* scope = NULL; 11858 11859 // Check whether we are in global, eval or function code. 11860 Handle<ScopeInfo> scope_info(shared_info->scope_info()); 11861 if (scope_info->scope_type() != FUNCTION_SCOPE) { 11862 // Global or eval code. 11863 CompilationInfoWithZone info(script); 11864 if (scope_info->scope_type() == GLOBAL_SCOPE) { 11865 info.MarkAsGlobal(); 11866 } else { 11867 ASSERT(scope_info->scope_type() == EVAL_SCOPE); 11868 info.MarkAsEval(); 11869 info.SetContext(Handle<Context>(function_->context())); 11870 } 11871 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 11872 scope = info.function()->scope(); 11873 } 11874 RetrieveScopeChain(scope, shared_info); 11875 } else { 11876 // Function code 11877 CompilationInfoWithZone info(shared_info); 11878 if (Parser::Parse(&info) && Scope::Analyze(&info)) { 11879 scope = info.function()->scope(); 11880 } 11881 RetrieveScopeChain(scope, shared_info); 11882 } 11883 } 11884 } 11885 11886 ScopeIterator(Isolate* isolate, 11887 Handle<JSFunction> function) 11888 : isolate_(isolate), 11889 frame_(NULL), 11890 inlined_jsframe_index_(0), 11891 function_(function), 11892 context_(function->context()), 11893 failed_(false) { 11894 if (function->IsBuiltin()) { 11895 context_ = Handle<Context>(); 11896 } 11897 } 11898 11899 // More scopes? 11900 bool Done() { 11901 ASSERT(!failed_); 11902 return context_.is_null(); 11903 } 11904 11905 bool Failed() { return failed_; } 11906 11907 // Move to the next scope. 11908 void Next() { 11909 ASSERT(!failed_); 11910 ScopeType scope_type = Type(); 11911 if (scope_type == ScopeTypeGlobal) { 11912 // The global scope is always the last in the chain. 11913 ASSERT(context_->IsNativeContext()); 11914 context_ = Handle<Context>(); 11915 return; 11916 } 11917 if (nested_scope_chain_.is_empty()) { 11918 context_ = Handle<Context>(context_->previous(), isolate_); 11919 } else { 11920 if (nested_scope_chain_.last()->HasContext()) { 11921 ASSERT(context_->previous() != NULL); 11922 context_ = Handle<Context>(context_->previous(), isolate_); 11923 } 11924 nested_scope_chain_.RemoveLast(); 11925 } 11926 } 11927 11928 // Return the type of the current scope. 11929 ScopeType Type() { 11930 ASSERT(!failed_); 11931 if (!nested_scope_chain_.is_empty()) { 11932 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); 11933 switch (scope_info->scope_type()) { 11934 case FUNCTION_SCOPE: 11935 ASSERT(context_->IsFunctionContext() || 11936 !scope_info->HasContext()); 11937 return ScopeTypeLocal; 11938 case MODULE_SCOPE: 11939 ASSERT(context_->IsModuleContext()); 11940 return ScopeTypeModule; 11941 case GLOBAL_SCOPE: 11942 ASSERT(context_->IsNativeContext()); 11943 return ScopeTypeGlobal; 11944 case WITH_SCOPE: 11945 ASSERT(context_->IsWithContext()); 11946 return ScopeTypeWith; 11947 case CATCH_SCOPE: 11948 ASSERT(context_->IsCatchContext()); 11949 return ScopeTypeCatch; 11950 case BLOCK_SCOPE: 11951 ASSERT(!scope_info->HasContext() || 11952 context_->IsBlockContext()); 11953 return ScopeTypeBlock; 11954 case EVAL_SCOPE: 11955 UNREACHABLE(); 11956 } 11957 } 11958 if (context_->IsNativeContext()) { 11959 ASSERT(context_->global_object()->IsGlobalObject()); 11960 return ScopeTypeGlobal; 11961 } 11962 if (context_->IsFunctionContext()) { 11963 return ScopeTypeClosure; 11964 } 11965 if (context_->IsCatchContext()) { 11966 return ScopeTypeCatch; 11967 } 11968 if (context_->IsBlockContext()) { 11969 return ScopeTypeBlock; 11970 } 11971 if (context_->IsModuleContext()) { 11972 return ScopeTypeModule; 11973 } 11974 ASSERT(context_->IsWithContext()); 11975 return ScopeTypeWith; 11976 } 11977 11978 // Return the JavaScript object with the content of the current scope. 11979 Handle<JSObject> ScopeObject() { 11980 ASSERT(!failed_); 11981 switch (Type()) { 11982 case ScopeIterator::ScopeTypeGlobal: 11983 return Handle<JSObject>(CurrentContext()->global_object()); 11984 case ScopeIterator::ScopeTypeLocal: 11985 // Materialize the content of the local scope into a JSObject. 11986 ASSERT(nested_scope_chain_.length() == 1); 11987 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); 11988 case ScopeIterator::ScopeTypeWith: 11989 // Return the with object. 11990 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); 11991 case ScopeIterator::ScopeTypeCatch: 11992 return MaterializeCatchScope(isolate_, CurrentContext()); 11993 case ScopeIterator::ScopeTypeClosure: 11994 // Materialize the content of the closure scope into a JSObject. 11995 return MaterializeClosure(isolate_, CurrentContext()); 11996 case ScopeIterator::ScopeTypeBlock: 11997 return MaterializeBlockScope(isolate_, CurrentContext()); 11998 case ScopeIterator::ScopeTypeModule: 11999 return MaterializeModuleScope(isolate_, CurrentContext()); 12000 } 12001 UNREACHABLE(); 12002 return Handle<JSObject>(); 12003 } 12004 12005 bool SetVariableValue(Handle<String> variable_name, 12006 Handle<Object> new_value) { 12007 ASSERT(!failed_); 12008 switch (Type()) { 12009 case ScopeIterator::ScopeTypeGlobal: 12010 break; 12011 case ScopeIterator::ScopeTypeLocal: 12012 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, 12013 variable_name, new_value); 12014 case ScopeIterator::ScopeTypeWith: 12015 break; 12016 case ScopeIterator::ScopeTypeCatch: 12017 return SetCatchVariableValue(isolate_, CurrentContext(), 12018 variable_name, new_value); 12019 case ScopeIterator::ScopeTypeClosure: 12020 return SetClosureVariableValue(isolate_, CurrentContext(), 12021 variable_name, new_value); 12022 case ScopeIterator::ScopeTypeBlock: 12023 // TODO(2399): should we implement it? 12024 break; 12025 case ScopeIterator::ScopeTypeModule: 12026 // TODO(2399): should we implement it? 12027 break; 12028 } 12029 return false; 12030 } 12031 12032 Handle<ScopeInfo> CurrentScopeInfo() { 12033 ASSERT(!failed_); 12034 if (!nested_scope_chain_.is_empty()) { 12035 return nested_scope_chain_.last(); 12036 } else if (context_->IsBlockContext()) { 12037 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension())); 12038 } else if (context_->IsFunctionContext()) { 12039 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info()); 12040 } 12041 return Handle<ScopeInfo>::null(); 12042 } 12043 12044 // Return the context for this scope. For the local context there might not 12045 // be an actual context. 12046 Handle<Context> CurrentContext() { 12047 ASSERT(!failed_); 12048 if (Type() == ScopeTypeGlobal || 12049 nested_scope_chain_.is_empty()) { 12050 return context_; 12051 } else if (nested_scope_chain_.last()->HasContext()) { 12052 return context_; 12053 } else { 12054 return Handle<Context>(); 12055 } 12056 } 12057 12058 #ifdef DEBUG 12059 // Debug print of the content of the current scope. 12060 void DebugPrint() { 12061 ASSERT(!failed_); 12062 switch (Type()) { 12063 case ScopeIterator::ScopeTypeGlobal: 12064 PrintF("Global:\n"); 12065 CurrentContext()->Print(); 12066 break; 12067 12068 case ScopeIterator::ScopeTypeLocal: { 12069 PrintF("Local:\n"); 12070 function_->shared()->scope_info()->Print(); 12071 if (!CurrentContext().is_null()) { 12072 CurrentContext()->Print(); 12073 if (CurrentContext()->has_extension()) { 12074 Handle<Object> extension(CurrentContext()->extension(), isolate_); 12075 if (extension->IsJSContextExtensionObject()) { 12076 extension->Print(); 12077 } 12078 } 12079 } 12080 break; 12081 } 12082 12083 case ScopeIterator::ScopeTypeWith: 12084 PrintF("With:\n"); 12085 CurrentContext()->extension()->Print(); 12086 break; 12087 12088 case ScopeIterator::ScopeTypeCatch: 12089 PrintF("Catch:\n"); 12090 CurrentContext()->extension()->Print(); 12091 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(); 12092 break; 12093 12094 case ScopeIterator::ScopeTypeClosure: 12095 PrintF("Closure:\n"); 12096 CurrentContext()->Print(); 12097 if (CurrentContext()->has_extension()) { 12098 Handle<Object> extension(CurrentContext()->extension(), isolate_); 12099 if (extension->IsJSContextExtensionObject()) { 12100 extension->Print(); 12101 } 12102 } 12103 break; 12104 12105 default: 12106 UNREACHABLE(); 12107 } 12108 PrintF("\n"); 12109 } 12110 #endif 12111 12112 private: 12113 Isolate* isolate_; 12114 JavaScriptFrame* frame_; 12115 int inlined_jsframe_index_; 12116 Handle<JSFunction> function_; 12117 Handle<Context> context_; 12118 List<Handle<ScopeInfo> > nested_scope_chain_; 12119 bool failed_; 12120 12121 void RetrieveScopeChain(Scope* scope, 12122 Handle<SharedFunctionInfo> shared_info) { 12123 if (scope != NULL) { 12124 int source_position = shared_info->code()->SourcePosition(frame_->pc()); 12125 scope->GetNestedScopeChain(&nested_scope_chain_, source_position); 12126 } else { 12127 // A failed reparse indicates that the preparser has diverged from the 12128 // parser or that the preparse data given to the initial parse has been 12129 // faulty. We fail in debug mode but in release mode we only provide the 12130 // information we get from the context chain but nothing about 12131 // completely stack allocated scopes or stack allocated locals. 12132 // Or it could be due to stack overflow. 12133 ASSERT(isolate_->has_pending_exception()); 12134 failed_ = true; 12135 } 12136 } 12137 12138 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); 12139 }; 12140 12141 12142 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) { 12143 HandleScope scope(isolate); 12144 ASSERT(args.length() == 2); 12145 12146 // Check arguments. 12147 Object* check; 12148 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12149 RUNTIME_ARGUMENTS(isolate, args)); 12150 if (!maybe_check->ToObject(&check)) return maybe_check; 12151 } 12152 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12153 12154 // Get the frame where the debugging is performed. 12155 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12156 JavaScriptFrameIterator it(isolate, id); 12157 JavaScriptFrame* frame = it.frame(); 12158 12159 // Count the visible scopes. 12160 int n = 0; 12161 for (ScopeIterator it(isolate, frame, 0); 12162 !it.Done(); 12163 it.Next()) { 12164 n++; 12165 } 12166 12167 return Smi::FromInt(n); 12168 } 12169 12170 12171 // Returns the list of step-in positions (text offset) in a function of the 12172 // stack frame in a range from the current debug break position to the end 12173 // of the corresponding statement. 12174 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetStepInPositions) { 12175 HandleScope scope(isolate); 12176 ASSERT(args.length() == 2); 12177 12178 // Check arguments. 12179 Object* check; 12180 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12181 RUNTIME_ARGUMENTS(isolate, args)); 12182 if (!maybe_check->ToObject(&check)) return maybe_check; 12183 } 12184 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12185 12186 // Get the frame where the debugging is performed. 12187 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12188 JavaScriptFrameIterator frame_it(isolate, id); 12189 RUNTIME_ASSERT(!frame_it.done()); 12190 12191 JavaScriptFrame* frame = frame_it.frame(); 12192 12193 Handle<JSFunction> fun = 12194 Handle<JSFunction>(frame->function()); 12195 Handle<SharedFunctionInfo> shared = 12196 Handle<SharedFunctionInfo>(fun->shared()); 12197 12198 if (!isolate->debug()->EnsureDebugInfo(shared, fun)) { 12199 return isolate->heap()->undefined_value(); 12200 } 12201 12202 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared); 12203 12204 int len = 0; 12205 Handle<JSArray> array(isolate->factory()->NewJSArray(10)); 12206 // Find the break point where execution has stopped. 12207 BreakLocationIterator break_location_iterator(debug_info, 12208 ALL_BREAK_LOCATIONS); 12209 12210 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); 12211 int current_statement_pos = break_location_iterator.statement_position(); 12212 12213 while (!break_location_iterator.Done()) { 12214 bool accept; 12215 if (break_location_iterator.pc() > frame->pc()) { 12216 accept = true; 12217 } else { 12218 StackFrame::Id break_frame_id = isolate->debug()->break_frame_id(); 12219 // The break point is near our pc. Could be a step-in possibility, 12220 // that is currently taken by active debugger call. 12221 if (break_frame_id == StackFrame::NO_ID) { 12222 // We are not stepping. 12223 accept = false; 12224 } else { 12225 JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id); 12226 // If our frame is a top frame and we are stepping, we can do step-in 12227 // at this place. 12228 accept = additional_frame_it.frame()->id() == id; 12229 } 12230 } 12231 if (accept) { 12232 if (break_location_iterator.IsStepInLocation(isolate)) { 12233 Smi* position_value = Smi::FromInt(break_location_iterator.position()); 12234 JSObject::SetElement(array, len, 12235 Handle<Object>(position_value, isolate), 12236 NONE, kNonStrictMode); 12237 len++; 12238 } 12239 } 12240 // Advance iterator. 12241 break_location_iterator.Next(); 12242 if (current_statement_pos != 12243 break_location_iterator.statement_position()) { 12244 break; 12245 } 12246 } 12247 return *array; 12248 } 12249 12250 12251 static const int kScopeDetailsTypeIndex = 0; 12252 static const int kScopeDetailsObjectIndex = 1; 12253 static const int kScopeDetailsSize = 2; 12254 12255 12256 static MaybeObject* MaterializeScopeDetails(Isolate* isolate, 12257 ScopeIterator* it) { 12258 // Calculate the size of the result. 12259 int details_size = kScopeDetailsSize; 12260 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size); 12261 12262 // Fill in scope details. 12263 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type())); 12264 Handle<JSObject> scope_object = it->ScopeObject(); 12265 RETURN_IF_EMPTY_HANDLE(isolate, scope_object); 12266 details->set(kScopeDetailsObjectIndex, *scope_object); 12267 12268 return *isolate->factory()->NewJSArrayWithElements(details); 12269 } 12270 12271 12272 // Return an array with scope details 12273 // args[0]: number: break id 12274 // args[1]: number: frame index 12275 // args[2]: number: inlined frame index 12276 // args[3]: number: scope index 12277 // 12278 // The array returned contains the following information: 12279 // 0: Scope type 12280 // 1: Scope object 12281 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) { 12282 HandleScope scope(isolate); 12283 ASSERT(args.length() == 4); 12284 12285 // Check arguments. 12286 Object* check; 12287 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12288 RUNTIME_ARGUMENTS(isolate, args)); 12289 if (!maybe_check->ToObject(&check)) return maybe_check; 12290 } 12291 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12292 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12293 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12294 12295 // Get the frame where the debugging is performed. 12296 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12297 JavaScriptFrameIterator frame_it(isolate, id); 12298 JavaScriptFrame* frame = frame_it.frame(); 12299 12300 // Find the requested scope. 12301 int n = 0; 12302 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12303 for (; !it.Done() && n < index; it.Next()) { 12304 n++; 12305 } 12306 if (it.Done()) { 12307 return isolate->heap()->undefined_value(); 12308 } 12309 return MaterializeScopeDetails(isolate, &it); 12310 } 12311 12312 12313 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) { 12314 HandleScope scope(isolate); 12315 ASSERT(args.length() == 1); 12316 12317 // Check arguments. 12318 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12319 12320 // Count the visible scopes. 12321 int n = 0; 12322 for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) { 12323 n++; 12324 } 12325 12326 return Smi::FromInt(n); 12327 } 12328 12329 12330 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) { 12331 HandleScope scope(isolate); 12332 ASSERT(args.length() == 2); 12333 12334 // Check arguments. 12335 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12336 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12337 12338 // Find the requested scope. 12339 int n = 0; 12340 ScopeIterator it(isolate, fun); 12341 for (; !it.Done() && n < index; it.Next()) { 12342 n++; 12343 } 12344 if (it.Done()) { 12345 return isolate->heap()->undefined_value(); 12346 } 12347 12348 return MaterializeScopeDetails(isolate, &it); 12349 } 12350 12351 12352 static bool SetScopeVariableValue(ScopeIterator* it, int index, 12353 Handle<String> variable_name, 12354 Handle<Object> new_value) { 12355 for (int n = 0; !it->Done() && n < index; it->Next()) { 12356 n++; 12357 } 12358 if (it->Done()) { 12359 return false; 12360 } 12361 return it->SetVariableValue(variable_name, new_value); 12362 } 12363 12364 12365 // Change variable value in closure or local scope 12366 // args[0]: number or JsFunction: break id or function 12367 // args[1]: number: frame index (when arg[0] is break id) 12368 // args[2]: number: inlined frame index (when arg[0] is break id) 12369 // args[3]: number: scope index 12370 // args[4]: string: variable name 12371 // args[5]: object: new value 12372 // 12373 // Return true if success and false otherwise 12374 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScopeVariableValue) { 12375 HandleScope scope(isolate); 12376 ASSERT(args.length() == 6); 12377 12378 // Check arguments. 12379 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]); 12380 CONVERT_ARG_HANDLE_CHECKED(String, variable_name, 4); 12381 Handle<Object> new_value = args.at<Object>(5); 12382 12383 bool res; 12384 if (args[0]->IsNumber()) { 12385 Object* check; 12386 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12387 RUNTIME_ARGUMENTS(isolate, args)); 12388 if (!maybe_check->ToObject(&check)) return maybe_check; 12389 } 12390 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12391 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12392 12393 // Get the frame where the debugging is performed. 12394 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12395 JavaScriptFrameIterator frame_it(isolate, id); 12396 JavaScriptFrame* frame = frame_it.frame(); 12397 12398 ScopeIterator it(isolate, frame, inlined_jsframe_index); 12399 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12400 } else { 12401 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12402 ScopeIterator it(isolate, fun); 12403 res = SetScopeVariableValue(&it, index, variable_name, new_value); 12404 } 12405 12406 return isolate->heap()->ToBoolean(res); 12407 } 12408 12409 12410 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) { 12411 HandleScope scope(isolate); 12412 ASSERT(args.length() == 0); 12413 12414 #ifdef DEBUG 12415 // Print the scopes for the top frame. 12416 StackFrameLocator locator(isolate); 12417 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0); 12418 for (ScopeIterator it(isolate, frame, 0); 12419 !it.Done(); 12420 it.Next()) { 12421 it.DebugPrint(); 12422 } 12423 #endif 12424 return isolate->heap()->undefined_value(); 12425 } 12426 12427 12428 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) { 12429 HandleScope scope(isolate); 12430 ASSERT(args.length() == 1); 12431 12432 // Check arguments. 12433 Object* result; 12434 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12435 RUNTIME_ARGUMENTS(isolate, args)); 12436 if (!maybe_result->ToObject(&result)) return maybe_result; 12437 } 12438 12439 // Count all archived V8 threads. 12440 int n = 0; 12441 for (ThreadState* thread = 12442 isolate->thread_manager()->FirstThreadStateInUse(); 12443 thread != NULL; 12444 thread = thread->Next()) { 12445 n++; 12446 } 12447 12448 // Total number of threads is current thread and archived threads. 12449 return Smi::FromInt(n + 1); 12450 } 12451 12452 12453 static const int kThreadDetailsCurrentThreadIndex = 0; 12454 static const int kThreadDetailsThreadIdIndex = 1; 12455 static const int kThreadDetailsSize = 2; 12456 12457 // Return an array with thread details 12458 // args[0]: number: break id 12459 // args[1]: number: thread index 12460 // 12461 // The array returned contains the following information: 12462 // 0: Is current thread? 12463 // 1: Thread id 12464 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) { 12465 HandleScope scope(isolate); 12466 ASSERT(args.length() == 2); 12467 12468 // Check arguments. 12469 Object* check; 12470 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12471 RUNTIME_ARGUMENTS(isolate, args)); 12472 if (!maybe_check->ToObject(&check)) return maybe_check; 12473 } 12474 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 12475 12476 // Allocate array for result. 12477 Handle<FixedArray> details = 12478 isolate->factory()->NewFixedArray(kThreadDetailsSize); 12479 12480 // Thread index 0 is current thread. 12481 if (index == 0) { 12482 // Fill the details. 12483 details->set(kThreadDetailsCurrentThreadIndex, 12484 isolate->heap()->true_value()); 12485 details->set(kThreadDetailsThreadIdIndex, 12486 Smi::FromInt(ThreadId::Current().ToInteger())); 12487 } else { 12488 // Find the thread with the requested index. 12489 int n = 1; 12490 ThreadState* thread = 12491 isolate->thread_manager()->FirstThreadStateInUse(); 12492 while (index != n && thread != NULL) { 12493 thread = thread->Next(); 12494 n++; 12495 } 12496 if (thread == NULL) { 12497 return isolate->heap()->undefined_value(); 12498 } 12499 12500 // Fill the details. 12501 details->set(kThreadDetailsCurrentThreadIndex, 12502 isolate->heap()->false_value()); 12503 details->set(kThreadDetailsThreadIdIndex, 12504 Smi::FromInt(thread->id().ToInteger())); 12505 } 12506 12507 // Convert to JS array and return. 12508 return *isolate->factory()->NewJSArrayWithElements(details); 12509 } 12510 12511 12512 // Sets the disable break state 12513 // args[0]: disable break state 12514 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) { 12515 HandleScope scope(isolate); 12516 ASSERT(args.length() == 1); 12517 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0); 12518 isolate->debug()->set_disable_break(disable_break); 12519 return isolate->heap()->undefined_value(); 12520 } 12521 12522 12523 static bool IsPositionAlignmentCodeCorrect(int alignment) { 12524 return alignment == STATEMENT_ALIGNED || alignment == BREAK_POSITION_ALIGNED; 12525 } 12526 12527 12528 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) { 12529 HandleScope scope(isolate); 12530 ASSERT(args.length() == 2); 12531 12532 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); 12533 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[1]); 12534 12535 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12536 return isolate->ThrowIllegalOperation(); 12537 } 12538 BreakPositionAlignment alignment = 12539 static_cast<BreakPositionAlignment>(statement_aligned_code); 12540 12541 Handle<SharedFunctionInfo> shared(fun->shared()); 12542 // Find the number of break points 12543 Handle<Object> break_locations = 12544 Debug::GetSourceBreakLocations(shared, alignment); 12545 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value(); 12546 // Return array as JS array 12547 return *isolate->factory()->NewJSArrayWithElements( 12548 Handle<FixedArray>::cast(break_locations)); 12549 } 12550 12551 12552 // Set a break point in a function. 12553 // args[0]: function 12554 // args[1]: number: break source position (within the function source) 12555 // args[2]: number: break point object 12556 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) { 12557 HandleScope scope(isolate); 12558 ASSERT(args.length() == 3); 12559 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 12560 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12561 RUNTIME_ASSERT(source_position >= 0); 12562 Handle<Object> break_point_object_arg = args.at<Object>(2); 12563 12564 // Set break point. 12565 isolate->debug()->SetBreakPoint(function, break_point_object_arg, 12566 &source_position); 12567 12568 return Smi::FromInt(source_position); 12569 } 12570 12571 12572 // Changes the state of a break point in a script and returns source position 12573 // where break point was set. NOTE: Regarding performance see the NOTE for 12574 // GetScriptFromScriptData. 12575 // args[0]: script to set break point in 12576 // args[1]: number: break source position (within the script source) 12577 // args[2]: number, breakpoint position alignment 12578 // args[3]: number: break point object 12579 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) { 12580 HandleScope scope(isolate); 12581 ASSERT(args.length() == 4); 12582 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0); 12583 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 12584 RUNTIME_ASSERT(source_position >= 0); 12585 CONVERT_NUMBER_CHECKED(int32_t, statement_aligned_code, Int32, args[2]); 12586 Handle<Object> break_point_object_arg = args.at<Object>(3); 12587 12588 if (!IsPositionAlignmentCodeCorrect(statement_aligned_code)) { 12589 return isolate->ThrowIllegalOperation(); 12590 } 12591 BreakPositionAlignment alignment = 12592 static_cast<BreakPositionAlignment>(statement_aligned_code); 12593 12594 // Get the script from the script wrapper. 12595 RUNTIME_ASSERT(wrapper->value()->IsScript()); 12596 Handle<Script> script(Script::cast(wrapper->value())); 12597 12598 // Set break point. 12599 if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg, 12600 &source_position, 12601 alignment)) { 12602 return isolate->heap()->undefined_value(); 12603 } 12604 12605 return Smi::FromInt(source_position); 12606 } 12607 12608 12609 // Clear a break point 12610 // args[0]: number: break point object 12611 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) { 12612 HandleScope scope(isolate); 12613 ASSERT(args.length() == 1); 12614 Handle<Object> break_point_object_arg = args.at<Object>(0); 12615 12616 // Clear break point. 12617 isolate->debug()->ClearBreakPoint(break_point_object_arg); 12618 12619 return isolate->heap()->undefined_value(); 12620 } 12621 12622 12623 // Change the state of break on exceptions. 12624 // args[0]: Enum value indicating whether to affect caught/uncaught exceptions. 12625 // args[1]: Boolean indicating on/off. 12626 RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) { 12627 HandleScope scope(isolate); 12628 ASSERT(args.length() == 2); 12629 RUNTIME_ASSERT(args[0]->IsNumber()); 12630 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1); 12631 12632 // If the number doesn't match an enum value, the ChangeBreakOnException 12633 // function will default to affecting caught exceptions. 12634 ExceptionBreakType type = 12635 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 12636 // Update break point state. 12637 isolate->debug()->ChangeBreakOnException(type, enable); 12638 return isolate->heap()->undefined_value(); 12639 } 12640 12641 12642 // Returns the state of break on exceptions 12643 // args[0]: boolean indicating uncaught exceptions 12644 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) { 12645 HandleScope scope(isolate); 12646 ASSERT(args.length() == 1); 12647 RUNTIME_ASSERT(args[0]->IsNumber()); 12648 12649 ExceptionBreakType type = 12650 static_cast<ExceptionBreakType>(NumberToUint32(args[0])); 12651 bool result = isolate->debug()->IsBreakOnException(type); 12652 return Smi::FromInt(result); 12653 } 12654 12655 12656 // Prepare for stepping 12657 // args[0]: break id for checking execution state 12658 // args[1]: step action from the enumeration StepAction 12659 // args[2]: number of times to perform the step, for step out it is the number 12660 // of frames to step down. 12661 RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) { 12662 HandleScope scope(isolate); 12663 ASSERT(args.length() == 4); 12664 // Check arguments. 12665 Object* check; 12666 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 12667 RUNTIME_ARGUMENTS(isolate, args)); 12668 if (!maybe_check->ToObject(&check)) return maybe_check; 12669 } 12670 if (!args[1]->IsNumber() || !args[2]->IsNumber()) { 12671 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12672 } 12673 12674 CONVERT_NUMBER_CHECKED(int, wrapped_frame_id, Int32, args[3]); 12675 12676 StackFrame::Id frame_id; 12677 if (wrapped_frame_id == 0) { 12678 frame_id = StackFrame::NO_ID; 12679 } else { 12680 frame_id = UnwrapFrameId(wrapped_frame_id); 12681 } 12682 12683 // Get the step action and check validity. 12684 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1])); 12685 if (step_action != StepIn && 12686 step_action != StepNext && 12687 step_action != StepOut && 12688 step_action != StepInMin && 12689 step_action != StepMin) { 12690 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12691 } 12692 12693 if (frame_id != StackFrame::NO_ID && step_action != StepNext && 12694 step_action != StepMin && step_action != StepOut) { 12695 return isolate->ThrowIllegalOperation(); 12696 } 12697 12698 // Get the number of steps. 12699 int step_count = NumberToInt32(args[2]); 12700 if (step_count < 1) { 12701 return isolate->Throw(isolate->heap()->illegal_argument_string()); 12702 } 12703 12704 // Clear all current stepping setup. 12705 isolate->debug()->ClearStepping(); 12706 12707 // Prepare step. 12708 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action), 12709 step_count, 12710 frame_id); 12711 return isolate->heap()->undefined_value(); 12712 } 12713 12714 12715 // Clear all stepping set by PrepareStep. 12716 RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) { 12717 HandleScope scope(isolate); 12718 ASSERT(args.length() == 0); 12719 isolate->debug()->ClearStepping(); 12720 return isolate->heap()->undefined_value(); 12721 } 12722 12723 12724 // Helper function to find or create the arguments object for 12725 // Runtime_DebugEvaluate. 12726 static Handle<JSObject> MaterializeArgumentsObject( 12727 Isolate* isolate, 12728 Handle<JSObject> target, 12729 Handle<JSFunction> function) { 12730 // Do not materialize the arguments object for eval or top-level code. 12731 // Skip if "arguments" is already taken. 12732 if (!function->shared()->is_function() || 12733 JSReceiver::HasLocalProperty(target, 12734 isolate->factory()->arguments_string())) { 12735 return target; 12736 } 12737 12738 // FunctionGetArguments can't throw an exception. 12739 Handle<JSObject> arguments = Handle<JSObject>::cast( 12740 Accessors::FunctionGetArguments(function)); 12741 Runtime::SetObjectProperty(isolate, target, 12742 isolate->factory()->arguments_string(), 12743 arguments, 12744 ::NONE, 12745 kNonStrictMode); 12746 return target; 12747 } 12748 12749 12750 // Compile and evaluate source for the given context. 12751 static MaybeObject* DebugEvaluate(Isolate* isolate, 12752 Handle<Context> context, 12753 Handle<Object> context_extension, 12754 Handle<Object> receiver, 12755 Handle<String> source) { 12756 if (context_extension->IsJSObject()) { 12757 Handle<JSObject> extension = Handle<JSObject>::cast(context_extension); 12758 Handle<JSFunction> closure(context->closure(), isolate); 12759 context = isolate->factory()->NewWithContext(closure, context, extension); 12760 } 12761 12762 Handle<SharedFunctionInfo> shared = Compiler::CompileEval( 12763 source, 12764 context, 12765 context->IsNativeContext(), 12766 CLASSIC_MODE, 12767 NO_PARSE_RESTRICTION, 12768 RelocInfo::kNoPosition); 12769 RETURN_IF_EMPTY_HANDLE(isolate, shared); 12770 12771 Handle<JSFunction> eval_fun = 12772 isolate->factory()->NewFunctionFromSharedFunctionInfo( 12773 shared, context, NOT_TENURED); 12774 bool pending_exception; 12775 Handle<Object> result = Execution::Call( 12776 isolate, eval_fun, receiver, 0, NULL, &pending_exception); 12777 12778 if (pending_exception) return Failure::Exception(); 12779 12780 // Skip the global proxy as it has no properties and always delegates to the 12781 // real global object. 12782 if (result->IsJSGlobalProxy()) { 12783 result = Handle<JSObject>(JSObject::cast(result->GetPrototype(isolate))); 12784 } 12785 12786 // Clear the oneshot breakpoints so that the debugger does not step further. 12787 isolate->debug()->ClearStepping(); 12788 return *result; 12789 } 12790 12791 12792 // Evaluate a piece of JavaScript in the context of a stack frame for 12793 // debugging. Things that need special attention are: 12794 // - Parameters and stack-allocated locals need to be materialized. Altered 12795 // values need to be written back to the stack afterwards. 12796 // - The arguments object needs to materialized. 12797 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { 12798 HandleScope scope(isolate); 12799 12800 // Check the execution state and decode arguments frame and source to be 12801 // evaluated. 12802 ASSERT(args.length() == 6); 12803 Object* check_result; 12804 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12805 RUNTIME_ARGUMENTS(isolate, args)); 12806 if (!maybe_result->ToObject(&check_result)) return maybe_result; 12807 } 12808 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1); 12809 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]); 12810 CONVERT_ARG_HANDLE_CHECKED(String, source, 3); 12811 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4); 12812 Handle<Object> context_extension(args[5], isolate); 12813 12814 // Handle the processing of break. 12815 DisableBreak disable_break_save(isolate, disable_break); 12816 12817 // Get the frame where the debugging is performed. 12818 StackFrame::Id id = UnwrapFrameId(wrapped_id); 12819 JavaScriptFrameIterator it(isolate, id); 12820 JavaScriptFrame* frame = it.frame(); 12821 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); 12822 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); 12823 12824 // Traverse the saved contexts chain to find the active context for the 12825 // selected frame. 12826 SaveContext* save = FindSavedContextForFrame(isolate, frame); 12827 12828 SaveContext savex(isolate); 12829 isolate->set_context(*(save->context())); 12830 12831 // Evaluate on the context of the frame. 12832 Handle<Context> context(Context::cast(frame->context())); 12833 ASSERT(!context.is_null()); 12834 12835 // Materialize stack locals and the arguments object. 12836 Handle<JSObject> materialized = 12837 isolate->factory()->NewJSObject(isolate->object_function()); 12838 12839 materialized = MaterializeStackLocalsWithFrameInspector( 12840 isolate, materialized, function, &frame_inspector); 12841 RETURN_IF_EMPTY_HANDLE(isolate, materialized); 12842 12843 materialized = MaterializeArgumentsObject(isolate, materialized, function); 12844 RETURN_IF_EMPTY_HANDLE(isolate, materialized); 12845 12846 // Add the materialized object in a with-scope to shadow the stack locals. 12847 context = isolate->factory()->NewWithContext(function, context, materialized); 12848 12849 Handle<Object> receiver(frame->receiver(), isolate); 12850 Object* evaluate_result_object; 12851 { MaybeObject* maybe_result = 12852 DebugEvaluate(isolate, context, context_extension, receiver, source); 12853 if (!maybe_result->ToObject(&evaluate_result_object)) return maybe_result; 12854 } 12855 12856 Handle<Object> result(evaluate_result_object, isolate); 12857 12858 // Write back potential changes to materialized stack locals to the stack. 12859 UpdateStackLocalsFromMaterializedObject( 12860 isolate, materialized, function, frame, inlined_jsframe_index); 12861 12862 return *result; 12863 } 12864 12865 12866 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { 12867 HandleScope scope(isolate); 12868 12869 // Check the execution state and decode arguments frame and source to be 12870 // evaluated. 12871 ASSERT(args.length() == 4); 12872 Object* check_result; 12873 { MaybeObject* maybe_result = Runtime_CheckExecutionState( 12874 RUNTIME_ARGUMENTS(isolate, args)); 12875 if (!maybe_result->ToObject(&check_result)) return maybe_result; 12876 } 12877 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 12878 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2); 12879 Handle<Object> context_extension(args[3], isolate); 12880 12881 // Handle the processing of break. 12882 DisableBreak disable_break_save(isolate, disable_break); 12883 12884 // Enter the top context from before the debugger was invoked. 12885 SaveContext save(isolate); 12886 SaveContext* top = &save; 12887 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) { 12888 top = top->prev(); 12889 } 12890 if (top != NULL) { 12891 isolate->set_context(*top->context()); 12892 } 12893 12894 // Get the native context now set to the top context from before the 12895 // debugger was invoked. 12896 Handle<Context> context = isolate->native_context(); 12897 Handle<Object> receiver = isolate->global_object(); 12898 return DebugEvaluate(isolate, context, context_extension, receiver, source); 12899 } 12900 12901 12902 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) { 12903 HandleScope scope(isolate); 12904 ASSERT(args.length() == 0); 12905 12906 // Fill the script objects. 12907 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts(); 12908 12909 // Convert the script objects to proper JS objects. 12910 for (int i = 0; i < instances->length(); i++) { 12911 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i))); 12912 // Get the script wrapper in a local handle before calling GetScriptWrapper, 12913 // because using 12914 // instances->set(i, *GetScriptWrapper(script)) 12915 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might 12916 // already have dereferenced the instances handle. 12917 Handle<JSValue> wrapper = GetScriptWrapper(script); 12918 instances->set(i, *wrapper); 12919 } 12920 12921 // Return result as a JS array. 12922 Handle<JSObject> result = 12923 isolate->factory()->NewJSObject(isolate->array_function()); 12924 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances); 12925 return *result; 12926 } 12927 12928 12929 // Helper function used by Runtime_DebugReferencedBy below. 12930 static int DebugReferencedBy(HeapIterator* iterator, 12931 JSObject* target, 12932 Object* instance_filter, int max_references, 12933 FixedArray* instances, int instances_size, 12934 JSFunction* arguments_function) { 12935 Isolate* isolate = target->GetIsolate(); 12936 SealHandleScope shs(isolate); 12937 DisallowHeapAllocation no_allocation; 12938 12939 // Iterate the heap. 12940 int count = 0; 12941 JSObject* last = NULL; 12942 HeapObject* heap_obj = NULL; 12943 while (((heap_obj = iterator->next()) != NULL) && 12944 (max_references == 0 || count < max_references)) { 12945 // Only look at all JSObjects. 12946 if (heap_obj->IsJSObject()) { 12947 // Skip context extension objects and argument arrays as these are 12948 // checked in the context of functions using them. 12949 JSObject* obj = JSObject::cast(heap_obj); 12950 if (obj->IsJSContextExtensionObject() || 12951 obj->map()->constructor() == arguments_function) { 12952 continue; 12953 } 12954 12955 // Check if the JS object has a reference to the object looked for. 12956 if (obj->ReferencesObject(target)) { 12957 // Check instance filter if supplied. This is normally used to avoid 12958 // references from mirror objects (see Runtime_IsInPrototypeChain). 12959 if (!instance_filter->IsUndefined()) { 12960 Object* V = obj; 12961 while (true) { 12962 Object* prototype = V->GetPrototype(isolate); 12963 if (prototype->IsNull()) { 12964 break; 12965 } 12966 if (instance_filter == prototype) { 12967 obj = NULL; // Don't add this object. 12968 break; 12969 } 12970 V = prototype; 12971 } 12972 } 12973 12974 if (obj != NULL) { 12975 // Valid reference found add to instance array if supplied an update 12976 // count. 12977 if (instances != NULL && count < instances_size) { 12978 instances->set(count, obj); 12979 } 12980 last = obj; 12981 count++; 12982 } 12983 } 12984 } 12985 } 12986 12987 // Check for circular reference only. This can happen when the object is only 12988 // referenced from mirrors and has a circular reference in which case the 12989 // object is not really alive and would have been garbage collected if not 12990 // referenced from the mirror. 12991 if (count == 1 && last == target) { 12992 count = 0; 12993 } 12994 12995 // Return the number of referencing objects found. 12996 return count; 12997 } 12998 12999 13000 // Scan the heap for objects with direct references to an object 13001 // args[0]: the object to find references to 13002 // args[1]: constructor function for instances to exclude (Mirror) 13003 // args[2]: the the maximum number of objects to return 13004 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) { 13005 SealHandleScope shs(isolate); 13006 ASSERT(args.length() == 3); 13007 13008 // First perform a full GC in order to avoid references from dead objects. 13009 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 13010 "%DebugReferencedBy"); 13011 // The heap iterator reserves the right to do a GC to make the heap iterable. 13012 // Due to the GC above we know it won't need to do that, but it seems cleaner 13013 // to get the heap iterator constructed before we start having unprotected 13014 // Object* locals that are not protected by handles. 13015 13016 // Check parameters. 13017 CONVERT_ARG_CHECKED(JSObject, target, 0); 13018 Object* instance_filter = args[1]; 13019 RUNTIME_ASSERT(instance_filter->IsUndefined() || 13020 instance_filter->IsJSObject()); 13021 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]); 13022 RUNTIME_ASSERT(max_references >= 0); 13023 13024 13025 // Get the constructor function for context extension and arguments array. 13026 JSObject* arguments_boilerplate = 13027 isolate->context()->native_context()->arguments_boilerplate(); 13028 JSFunction* arguments_function = 13029 JSFunction::cast(arguments_boilerplate->map()->constructor()); 13030 13031 // Get the number of referencing objects. 13032 int count; 13033 Heap* heap = isolate->heap(); 13034 HeapIterator heap_iterator(heap); 13035 count = DebugReferencedBy(&heap_iterator, 13036 target, instance_filter, max_references, 13037 NULL, 0, arguments_function); 13038 13039 // Allocate an array to hold the result. 13040 Object* object; 13041 { MaybeObject* maybe_object = heap->AllocateFixedArray(count); 13042 if (!maybe_object->ToObject(&object)) return maybe_object; 13043 } 13044 FixedArray* instances = FixedArray::cast(object); 13045 13046 // Fill the referencing objects. 13047 // AllocateFixedArray above does not make the heap non-iterable. 13048 ASSERT(heap->IsHeapIterable()); 13049 HeapIterator heap_iterator2(heap); 13050 count = DebugReferencedBy(&heap_iterator2, 13051 target, instance_filter, max_references, 13052 instances, count, arguments_function); 13053 13054 // Return result as JS array. 13055 Object* result; 13056 MaybeObject* maybe_result = heap->AllocateJSObject( 13057 isolate->context()->native_context()->array_function()); 13058 if (!maybe_result->ToObject(&result)) return maybe_result; 13059 return JSArray::cast(result)->SetContent(instances); 13060 } 13061 13062 13063 // Helper function used by Runtime_DebugConstructedBy below. 13064 static int DebugConstructedBy(HeapIterator* iterator, 13065 JSFunction* constructor, 13066 int max_references, 13067 FixedArray* instances, 13068 int instances_size) { 13069 DisallowHeapAllocation no_allocation; 13070 13071 // Iterate the heap. 13072 int count = 0; 13073 HeapObject* heap_obj = NULL; 13074 while (((heap_obj = iterator->next()) != NULL) && 13075 (max_references == 0 || count < max_references)) { 13076 // Only look at all JSObjects. 13077 if (heap_obj->IsJSObject()) { 13078 JSObject* obj = JSObject::cast(heap_obj); 13079 if (obj->map()->constructor() == constructor) { 13080 // Valid reference found add to instance array if supplied an update 13081 // count. 13082 if (instances != NULL && count < instances_size) { 13083 instances->set(count, obj); 13084 } 13085 count++; 13086 } 13087 } 13088 } 13089 13090 // Return the number of referencing objects found. 13091 return count; 13092 } 13093 13094 13095 // Scan the heap for objects constructed by a specific function. 13096 // args[0]: the constructor to find instances of 13097 // args[1]: the the maximum number of objects to return 13098 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) { 13099 SealHandleScope shs(isolate); 13100 ASSERT(args.length() == 2); 13101 13102 // First perform a full GC in order to avoid dead objects. 13103 Heap* heap = isolate->heap(); 13104 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy"); 13105 13106 // Check parameters. 13107 CONVERT_ARG_CHECKED(JSFunction, constructor, 0); 13108 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]); 13109 RUNTIME_ASSERT(max_references >= 0); 13110 13111 // Get the number of referencing objects. 13112 int count; 13113 HeapIterator heap_iterator(heap); 13114 count = DebugConstructedBy(&heap_iterator, 13115 constructor, 13116 max_references, 13117 NULL, 13118 0); 13119 13120 // Allocate an array to hold the result. 13121 Object* object; 13122 { MaybeObject* maybe_object = heap->AllocateFixedArray(count); 13123 if (!maybe_object->ToObject(&object)) return maybe_object; 13124 } 13125 FixedArray* instances = FixedArray::cast(object); 13126 13127 ASSERT(isolate->heap()->IsHeapIterable()); 13128 // Fill the referencing objects. 13129 HeapIterator heap_iterator2(heap); 13130 count = DebugConstructedBy(&heap_iterator2, 13131 constructor, 13132 max_references, 13133 instances, 13134 count); 13135 13136 // Return result as JS array. 13137 Object* result; 13138 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject( 13139 isolate->context()->native_context()->array_function()); 13140 if (!maybe_result->ToObject(&result)) return maybe_result; 13141 } 13142 return JSArray::cast(result)->SetContent(instances); 13143 } 13144 13145 13146 // Find the effective prototype object as returned by __proto__. 13147 // args[0]: the object to find the prototype for. 13148 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) { 13149 SealHandleScope shs(isolate); 13150 ASSERT(args.length() == 1); 13151 CONVERT_ARG_CHECKED(JSObject, obj, 0); 13152 return GetPrototypeSkipHiddenPrototypes(isolate, obj); 13153 } 13154 13155 13156 // Patches script source (should be called upon BeforeCompile event). 13157 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) { 13158 HandleScope scope(isolate); 13159 ASSERT(args.length() == 2); 13160 13161 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0); 13162 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13163 13164 RUNTIME_ASSERT(script_wrapper->value()->IsScript()); 13165 Handle<Script> script(Script::cast(script_wrapper->value())); 13166 13167 int compilation_state = script->compilation_state(); 13168 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL); 13169 script->set_source(*source); 13170 13171 return isolate->heap()->undefined_value(); 13172 } 13173 13174 13175 RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) { 13176 SealHandleScope shs(isolate); 13177 ASSERT(args.length() == 0); 13178 OS::DebugBreak(); 13179 return isolate->heap()->undefined_value(); 13180 } 13181 13182 13183 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) { 13184 HandleScope scope(isolate); 13185 #ifdef DEBUG 13186 ASSERT(args.length() == 1); 13187 // Get the function and make sure it is compiled. 13188 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 13189 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { 13190 return Failure::Exception(); 13191 } 13192 func->code()->PrintLn(); 13193 #endif // DEBUG 13194 return isolate->heap()->undefined_value(); 13195 } 13196 13197 13198 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) { 13199 HandleScope scope(isolate); 13200 #ifdef DEBUG 13201 ASSERT(args.length() == 1); 13202 // Get the function and make sure it is compiled. 13203 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0); 13204 if (!JSFunction::EnsureCompiled(func, KEEP_EXCEPTION)) { 13205 return Failure::Exception(); 13206 } 13207 func->shared()->construct_stub()->PrintLn(); 13208 #endif // DEBUG 13209 return isolate->heap()->undefined_value(); 13210 } 13211 13212 13213 RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) { 13214 SealHandleScope shs(isolate); 13215 ASSERT(args.length() == 1); 13216 13217 CONVERT_ARG_CHECKED(JSFunction, f, 0); 13218 return f->shared()->inferred_name(); 13219 } 13220 13221 13222 static int FindSharedFunctionInfosForScript(HeapIterator* iterator, 13223 Script* script, 13224 FixedArray* buffer) { 13225 DisallowHeapAllocation no_allocation; 13226 int counter = 0; 13227 int buffer_size = buffer->length(); 13228 for (HeapObject* obj = iterator->next(); 13229 obj != NULL; 13230 obj = iterator->next()) { 13231 ASSERT(obj != NULL); 13232 if (!obj->IsSharedFunctionInfo()) { 13233 continue; 13234 } 13235 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 13236 if (shared->script() != script) { 13237 continue; 13238 } 13239 if (counter < buffer_size) { 13240 buffer->set(counter, shared); 13241 } 13242 counter++; 13243 } 13244 return counter; 13245 } 13246 13247 13248 // For a script finds all SharedFunctionInfo's in the heap that points 13249 // to this script. Returns JSArray of SharedFunctionInfo wrapped 13250 // in OpaqueReferences. 13251 RUNTIME_FUNCTION(MaybeObject*, 13252 Runtime_LiveEditFindSharedFunctionInfosForScript) { 13253 HandleScope scope(isolate); 13254 CHECK(isolate->debugger()->live_edit_enabled()); 13255 ASSERT(args.length() == 1); 13256 CONVERT_ARG_CHECKED(JSValue, script_value, 0); 13257 13258 RUNTIME_ASSERT(script_value->value()->IsScript()); 13259 Handle<Script> script = Handle<Script>(Script::cast(script_value->value())); 13260 13261 const int kBufferSize = 32; 13262 13263 Handle<FixedArray> array; 13264 array = isolate->factory()->NewFixedArray(kBufferSize); 13265 int number; 13266 Heap* heap = isolate->heap(); 13267 { 13268 heap->EnsureHeapIsIterable(); 13269 DisallowHeapAllocation no_allocation; 13270 HeapIterator heap_iterator(heap); 13271 Script* scr = *script; 13272 FixedArray* arr = *array; 13273 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13274 } 13275 if (number > kBufferSize) { 13276 array = isolate->factory()->NewFixedArray(number); 13277 heap->EnsureHeapIsIterable(); 13278 DisallowHeapAllocation no_allocation; 13279 HeapIterator heap_iterator(heap); 13280 Script* scr = *script; 13281 FixedArray* arr = *array; 13282 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr); 13283 } 13284 13285 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array); 13286 result->set_length(Smi::FromInt(number)); 13287 13288 LiveEdit::WrapSharedFunctionInfos(result); 13289 13290 return *result; 13291 } 13292 13293 13294 // For a script calculates compilation information about all its functions. 13295 // The script source is explicitly specified by the second argument. 13296 // The source of the actual script is not used, however it is important that 13297 // all generated code keeps references to this particular instance of script. 13298 // Returns a JSArray of compilation infos. The array is ordered so that 13299 // each function with all its descendant is always stored in a continues range 13300 // with the function itself going first. The root function is a script function. 13301 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) { 13302 HandleScope scope(isolate); 13303 CHECK(isolate->debugger()->live_edit_enabled()); 13304 ASSERT(args.length() == 2); 13305 CONVERT_ARG_CHECKED(JSValue, script, 0); 13306 CONVERT_ARG_HANDLE_CHECKED(String, source, 1); 13307 13308 RUNTIME_ASSERT(script->value()->IsScript()); 13309 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value())); 13310 13311 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source); 13312 13313 if (isolate->has_pending_exception()) { 13314 return Failure::Exception(); 13315 } 13316 13317 return result; 13318 } 13319 13320 13321 // Changes the source of the script to a new_source. 13322 // If old_script_name is provided (i.e. is a String), also creates a copy of 13323 // the script with its original source and sends notification to debugger. 13324 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) { 13325 HandleScope scope(isolate); 13326 CHECK(isolate->debugger()->live_edit_enabled()); 13327 ASSERT(args.length() == 3); 13328 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0); 13329 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1); 13330 Handle<Object> old_script_name(args[2], isolate); 13331 13332 RUNTIME_ASSERT(original_script_value->value()->IsScript()); 13333 Handle<Script> original_script(Script::cast(original_script_value->value())); 13334 13335 Object* old_script = LiveEdit::ChangeScriptSource(original_script, 13336 new_source, 13337 old_script_name); 13338 13339 if (old_script->IsScript()) { 13340 Handle<Script> script_handle(Script::cast(old_script)); 13341 return *(GetScriptWrapper(script_handle)); 13342 } else { 13343 return isolate->heap()->null_value(); 13344 } 13345 } 13346 13347 13348 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) { 13349 HandleScope scope(isolate); 13350 CHECK(isolate->debugger()->live_edit_enabled()); 13351 ASSERT(args.length() == 1); 13352 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0); 13353 return LiveEdit::FunctionSourceUpdated(shared_info); 13354 } 13355 13356 13357 // Replaces code of SharedFunctionInfo with a new one. 13358 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) { 13359 HandleScope scope(isolate); 13360 CHECK(isolate->debugger()->live_edit_enabled()); 13361 ASSERT(args.length() == 2); 13362 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0); 13363 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1); 13364 13365 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info); 13366 } 13367 13368 13369 // Connects SharedFunctionInfo to another script. 13370 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) { 13371 HandleScope scope(isolate); 13372 CHECK(isolate->debugger()->live_edit_enabled()); 13373 ASSERT(args.length() == 2); 13374 Handle<Object> function_object(args[0], isolate); 13375 Handle<Object> script_object(args[1], isolate); 13376 13377 if (function_object->IsJSValue()) { 13378 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object); 13379 if (script_object->IsJSValue()) { 13380 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript()); 13381 Script* script = Script::cast(JSValue::cast(*script_object)->value()); 13382 script_object = Handle<Object>(script, isolate); 13383 } 13384 13385 LiveEdit::SetFunctionScript(function_wrapper, script_object); 13386 } else { 13387 // Just ignore this. We may not have a SharedFunctionInfo for some functions 13388 // and we check it in this function. 13389 } 13390 13391 return isolate->heap()->undefined_value(); 13392 } 13393 13394 13395 // In a code of a parent function replaces original function as embedded object 13396 // with a substitution one. 13397 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) { 13398 HandleScope scope(isolate); 13399 CHECK(isolate->debugger()->live_edit_enabled()); 13400 ASSERT(args.length() == 3); 13401 13402 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0); 13403 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1); 13404 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2); 13405 13406 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper, 13407 subst_wrapper); 13408 13409 return isolate->heap()->undefined_value(); 13410 } 13411 13412 13413 // Updates positions of a shared function info (first parameter) according 13414 // to script source change. Text change is described in second parameter as 13415 // array of groups of 3 numbers: 13416 // (change_begin, change_end, change_end_new_position). 13417 // Each group describes a change in text; groups are sorted by change_begin. 13418 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) { 13419 HandleScope scope(isolate); 13420 CHECK(isolate->debugger()->live_edit_enabled()); 13421 ASSERT(args.length() == 2); 13422 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13423 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1); 13424 13425 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array); 13426 } 13427 13428 13429 // For array of SharedFunctionInfo's (each wrapped in JSValue) 13430 // checks that none of them have activations on stacks (of any thread). 13431 // Returns array of the same length with corresponding results of 13432 // LiveEdit::FunctionPatchabilityStatus type. 13433 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) { 13434 HandleScope scope(isolate); 13435 CHECK(isolate->debugger()->live_edit_enabled()); 13436 ASSERT(args.length() == 2); 13437 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0); 13438 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1); 13439 13440 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop); 13441 } 13442 13443 13444 // Compares 2 strings line-by-line, then token-wise and returns diff in form 13445 // of JSArray of triplets (pos1, pos1_end, pos2_end) describing list 13446 // of diff chunks. 13447 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) { 13448 HandleScope scope(isolate); 13449 CHECK(isolate->debugger()->live_edit_enabled()); 13450 ASSERT(args.length() == 2); 13451 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0); 13452 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1); 13453 13454 return *LiveEdit::CompareStrings(s1, s2); 13455 } 13456 13457 13458 // Restarts a call frame and completely drops all frames above. 13459 // Returns true if successful. Otherwise returns undefined or an error message. 13460 RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditRestartFrame) { 13461 HandleScope scope(isolate); 13462 CHECK(isolate->debugger()->live_edit_enabled()); 13463 ASSERT(args.length() == 2); 13464 13465 // Check arguments. 13466 Object* check; 13467 { MaybeObject* maybe_check = Runtime_CheckExecutionState( 13468 RUNTIME_ARGUMENTS(isolate, args)); 13469 if (!maybe_check->ToObject(&check)) return maybe_check; 13470 } 13471 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]); 13472 Heap* heap = isolate->heap(); 13473 13474 // Find the relevant frame with the requested index. 13475 StackFrame::Id id = isolate->debug()->break_frame_id(); 13476 if (id == StackFrame::NO_ID) { 13477 // If there are no JavaScript stack frames return undefined. 13478 return heap->undefined_value(); 13479 } 13480 13481 int count = 0; 13482 JavaScriptFrameIterator it(isolate, id); 13483 for (; !it.done(); it.Advance()) { 13484 if (index < count + it.frame()->GetInlineCount()) break; 13485 count += it.frame()->GetInlineCount(); 13486 } 13487 if (it.done()) return heap->undefined_value(); 13488 13489 const char* error_message = LiveEdit::RestartFrame(it.frame()); 13490 if (error_message) { 13491 return *(isolate->factory()->InternalizeUtf8String(error_message)); 13492 } 13493 return heap->true_value(); 13494 } 13495 13496 13497 // A testing entry. Returns statement position which is the closest to 13498 // source_position. 13499 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) { 13500 HandleScope scope(isolate); 13501 CHECK(isolate->debugger()->live_edit_enabled()); 13502 ASSERT(args.length() == 2); 13503 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13504 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]); 13505 13506 Handle<Code> code(function->code(), isolate); 13507 13508 if (code->kind() != Code::FUNCTION && 13509 code->kind() != Code::OPTIMIZED_FUNCTION) { 13510 return isolate->heap()->undefined_value(); 13511 } 13512 13513 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION)); 13514 int closest_pc = 0; 13515 int distance = kMaxInt; 13516 while (!it.done()) { 13517 int statement_position = static_cast<int>(it.rinfo()->data()); 13518 // Check if this break point is closer that what was previously found. 13519 if (source_position <= statement_position && 13520 statement_position - source_position < distance) { 13521 closest_pc = 13522 static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 13523 distance = statement_position - source_position; 13524 // Check whether we can't get any closer. 13525 if (distance == 0) break; 13526 } 13527 it.next(); 13528 } 13529 13530 return Smi::FromInt(closest_pc); 13531 } 13532 13533 13534 // Calls specified function with or without entering the debugger. 13535 // This is used in unit tests to run code as if debugger is entered or simply 13536 // to have a stack with C++ frame in the middle. 13537 RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) { 13538 HandleScope scope(isolate); 13539 ASSERT(args.length() == 2); 13540 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); 13541 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1); 13542 13543 Handle<Object> result; 13544 bool pending_exception; 13545 { 13546 if (without_debugger) { 13547 result = Execution::Call(isolate, 13548 function, 13549 isolate->global_object(), 13550 0, 13551 NULL, 13552 &pending_exception); 13553 } else { 13554 EnterDebugger enter_debugger(isolate); 13555 result = Execution::Call(isolate, 13556 function, 13557 isolate->global_object(), 13558 0, 13559 NULL, 13560 &pending_exception); 13561 } 13562 } 13563 if (!pending_exception) { 13564 return *result; 13565 } else { 13566 return Failure::Exception(); 13567 } 13568 } 13569 13570 13571 // Sets a v8 flag. 13572 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) { 13573 SealHandleScope shs(isolate); 13574 CONVERT_ARG_CHECKED(String, arg, 0); 13575 SmartArrayPointer<char> flags = 13576 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); 13577 FlagList::SetFlagsFromString(*flags, StrLength(*flags)); 13578 return isolate->heap()->undefined_value(); 13579 } 13580 13581 13582 // Performs a GC. 13583 // Presently, it only does a full GC. 13584 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) { 13585 SealHandleScope shs(isolate); 13586 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage"); 13587 return isolate->heap()->undefined_value(); 13588 } 13589 13590 13591 // Gets the current heap usage. 13592 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) { 13593 SealHandleScope shs(isolate); 13594 int usage = static_cast<int>(isolate->heap()->SizeOfObjects()); 13595 if (!Smi::IsValid(usage)) { 13596 return *isolate->factory()->NewNumberFromInt(usage); 13597 } 13598 return Smi::FromInt(usage); 13599 } 13600 13601 #endif // ENABLE_DEBUGGER_SUPPORT 13602 13603 13604 #ifdef V8_I18N_SUPPORT 13605 RUNTIME_FUNCTION(MaybeObject*, Runtime_CanonicalizeLanguageTag) { 13606 HandleScope scope(isolate); 13607 13608 ASSERT(args.length() == 1); 13609 CONVERT_ARG_HANDLE_CHECKED(String, locale_id_str, 0); 13610 13611 v8::String::Utf8Value locale_id(v8::Utils::ToLocal(locale_id_str)); 13612 13613 // Return value which denotes invalid language tag. 13614 const char* const kInvalidTag = "invalid-tag"; 13615 13616 UErrorCode error = U_ZERO_ERROR; 13617 char icu_result[ULOC_FULLNAME_CAPACITY]; 13618 int icu_length = 0; 13619 13620 uloc_forLanguageTag(*locale_id, icu_result, ULOC_FULLNAME_CAPACITY, 13621 &icu_length, &error); 13622 if (U_FAILURE(error) || icu_length == 0) { 13623 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); 13624 } 13625 13626 char result[ULOC_FULLNAME_CAPACITY]; 13627 13628 // Force strict BCP47 rules. 13629 uloc_toLanguageTag(icu_result, result, ULOC_FULLNAME_CAPACITY, TRUE, &error); 13630 13631 if (U_FAILURE(error)) { 13632 return isolate->heap()->AllocateStringFromOneByte(CStrVector(kInvalidTag)); 13633 } 13634 13635 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); 13636 } 13637 13638 13639 RUNTIME_FUNCTION(MaybeObject*, Runtime_AvailableLocalesOf) { 13640 HandleScope scope(isolate); 13641 13642 ASSERT(args.length() == 1); 13643 CONVERT_ARG_HANDLE_CHECKED(String, service, 0); 13644 13645 const icu::Locale* available_locales = NULL; 13646 int32_t count = 0; 13647 13648 if (service->IsUtf8EqualTo(CStrVector("collator"))) { 13649 available_locales = icu::Collator::getAvailableLocales(count); 13650 } else if (service->IsUtf8EqualTo(CStrVector("numberformat"))) { 13651 available_locales = icu::NumberFormat::getAvailableLocales(count); 13652 } else if (service->IsUtf8EqualTo(CStrVector("dateformat"))) { 13653 available_locales = icu::DateFormat::getAvailableLocales(count); 13654 } else if (service->IsUtf8EqualTo(CStrVector("breakiterator"))) { 13655 available_locales = icu::BreakIterator::getAvailableLocales(count); 13656 } 13657 13658 UErrorCode error = U_ZERO_ERROR; 13659 char result[ULOC_FULLNAME_CAPACITY]; 13660 Handle<JSObject> locales = 13661 isolate->factory()->NewJSObject(isolate->object_function()); 13662 13663 for (int32_t i = 0; i < count; ++i) { 13664 const char* icu_name = available_locales[i].getName(); 13665 13666 error = U_ZERO_ERROR; 13667 // No need to force strict BCP47 rules. 13668 uloc_toLanguageTag(icu_name, result, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13669 if (U_FAILURE(error)) { 13670 // This shouldn't happen, but lets not break the user. 13671 continue; 13672 } 13673 13674 RETURN_IF_EMPTY_HANDLE(isolate, 13675 JSObject::SetLocalPropertyIgnoreAttributes( 13676 locales, 13677 isolate->factory()->NewStringFromAscii(CStrVector(result)), 13678 isolate->factory()->NewNumber(i), 13679 NONE)); 13680 } 13681 13682 return *locales; 13683 } 13684 13685 13686 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultICULocale) { 13687 SealHandleScope shs(isolate); 13688 13689 ASSERT(args.length() == 0); 13690 13691 icu::Locale default_locale; 13692 13693 // Set the locale 13694 char result[ULOC_FULLNAME_CAPACITY]; 13695 UErrorCode status = U_ZERO_ERROR; 13696 uloc_toLanguageTag( 13697 default_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); 13698 if (U_SUCCESS(status)) { 13699 return isolate->heap()->AllocateStringFromOneByte(CStrVector(result)); 13700 } 13701 13702 return isolate->heap()->AllocateStringFromOneByte(CStrVector("und")); 13703 } 13704 13705 13706 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) { 13707 HandleScope scope(isolate); 13708 13709 ASSERT(args.length() == 1); 13710 13711 CONVERT_ARG_HANDLE_CHECKED(JSArray, input, 0); 13712 13713 uint32_t length = static_cast<uint32_t>(input->length()->Number()); 13714 Handle<FixedArray> output = isolate->factory()->NewFixedArray(length); 13715 Handle<Name> maximized = 13716 isolate->factory()->NewStringFromAscii(CStrVector("maximized")); 13717 Handle<Name> base = 13718 isolate->factory()->NewStringFromAscii(CStrVector("base")); 13719 for (unsigned int i = 0; i < length; ++i) { 13720 MaybeObject* maybe_string = input->GetElement(isolate, i); 13721 Object* locale_id; 13722 if (!maybe_string->ToObject(&locale_id) || !locale_id->IsString()) { 13723 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13724 } 13725 13726 v8::String::Utf8Value utf8_locale_id( 13727 v8::Utils::ToLocal(Handle<String>(String::cast(locale_id)))); 13728 13729 UErrorCode error = U_ZERO_ERROR; 13730 13731 // Convert from BCP47 to ICU format. 13732 // de-DE-u-co-phonebk -> de_DE@collation=phonebook 13733 char icu_locale[ULOC_FULLNAME_CAPACITY]; 13734 int icu_locale_length = 0; 13735 uloc_forLanguageTag(*utf8_locale_id, icu_locale, ULOC_FULLNAME_CAPACITY, 13736 &icu_locale_length, &error); 13737 if (U_FAILURE(error) || icu_locale_length == 0) { 13738 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13739 } 13740 13741 // Maximize the locale. 13742 // de_DE@collation=phonebook -> de_Latn_DE@collation=phonebook 13743 char icu_max_locale[ULOC_FULLNAME_CAPACITY]; 13744 uloc_addLikelySubtags( 13745 icu_locale, icu_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13746 13747 // Remove extensions from maximized locale. 13748 // de_Latn_DE@collation=phonebook -> de_Latn_DE 13749 char icu_base_max_locale[ULOC_FULLNAME_CAPACITY]; 13750 uloc_getBaseName( 13751 icu_max_locale, icu_base_max_locale, ULOC_FULLNAME_CAPACITY, &error); 13752 13753 // Get original name without extensions. 13754 // de_DE@collation=phonebook -> de_DE 13755 char icu_base_locale[ULOC_FULLNAME_CAPACITY]; 13756 uloc_getBaseName( 13757 icu_locale, icu_base_locale, ULOC_FULLNAME_CAPACITY, &error); 13758 13759 // Convert from ICU locale format to BCP47 format. 13760 // de_Latn_DE -> de-Latn-DE 13761 char base_max_locale[ULOC_FULLNAME_CAPACITY]; 13762 uloc_toLanguageTag(icu_base_max_locale, base_max_locale, 13763 ULOC_FULLNAME_CAPACITY, FALSE, &error); 13764 13765 // de_DE -> de-DE 13766 char base_locale[ULOC_FULLNAME_CAPACITY]; 13767 uloc_toLanguageTag( 13768 icu_base_locale, base_locale, ULOC_FULLNAME_CAPACITY, FALSE, &error); 13769 13770 if (U_FAILURE(error)) { 13771 return isolate->Throw(isolate->heap()->illegal_argument_string()); 13772 } 13773 13774 Handle<JSObject> result = 13775 isolate->factory()->NewJSObject(isolate->object_function()); 13776 RETURN_IF_EMPTY_HANDLE(isolate, 13777 JSObject::SetLocalPropertyIgnoreAttributes( 13778 result, 13779 maximized, 13780 isolate->factory()->NewStringFromAscii(CStrVector(base_max_locale)), 13781 NONE)); 13782 RETURN_IF_EMPTY_HANDLE(isolate, 13783 JSObject::SetLocalPropertyIgnoreAttributes( 13784 result, 13785 base, 13786 isolate->factory()->NewStringFromAscii(CStrVector(base_locale)), 13787 NONE)); 13788 output->set(i, *result); 13789 } 13790 13791 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(output); 13792 result->set_length(Smi::FromInt(length)); 13793 return *result; 13794 } 13795 13796 13797 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) { 13798 HandleScope scope(isolate); 13799 13800 ASSERT(args.length() == 3); 13801 13802 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 13803 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 13804 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 13805 13806 Handle<ObjectTemplateInfo> date_format_template = 13807 I18N::GetTemplate(isolate); 13808 13809 // Create an empty object wrapper. 13810 bool has_pending_exception = false; 13811 Handle<JSObject> local_object = Execution::InstantiateObject( 13812 date_format_template, &has_pending_exception); 13813 if (has_pending_exception) { 13814 ASSERT(isolate->has_pending_exception()); 13815 return Failure::Exception(); 13816 } 13817 13818 // Set date time formatter as internal field of the resulting JS object. 13819 icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat( 13820 isolate, locale, options, resolved); 13821 13822 if (!date_format) return isolate->ThrowIllegalOperation(); 13823 13824 local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format)); 13825 13826 RETURN_IF_EMPTY_HANDLE(isolate, 13827 JSObject::SetLocalPropertyIgnoreAttributes( 13828 local_object, 13829 isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")), 13830 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 13831 NONE)); 13832 13833 // Make object handle weak so we can delete the data format once GC kicks in. 13834 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 13835 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), 13836 NULL, 13837 DateFormat::DeleteDateFormat); 13838 return *local_object; 13839 } 13840 13841 13842 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) { 13843 HandleScope scope(isolate); 13844 13845 ASSERT(args.length() == 2); 13846 13847 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 13848 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1); 13849 13850 bool has_pending_exception = false; 13851 Handle<Object> value = 13852 Execution::ToNumber(isolate, date, &has_pending_exception); 13853 if (has_pending_exception) { 13854 ASSERT(isolate->has_pending_exception()); 13855 return Failure::Exception(); 13856 } 13857 13858 icu::SimpleDateFormat* date_format = 13859 DateFormat::UnpackDateFormat(isolate, date_format_holder); 13860 if (!date_format) return isolate->ThrowIllegalOperation(); 13861 13862 icu::UnicodeString result; 13863 date_format->format(value->Number(), result); 13864 13865 return *isolate->factory()->NewStringFromTwoByte( 13866 Vector<const uint16_t>( 13867 reinterpret_cast<const uint16_t*>(result.getBuffer()), 13868 result.length())); 13869 } 13870 13871 13872 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) { 13873 HandleScope scope(isolate); 13874 13875 ASSERT(args.length() == 2); 13876 13877 CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0); 13878 CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1); 13879 13880 v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string)); 13881 icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date)); 13882 icu::SimpleDateFormat* date_format = 13883 DateFormat::UnpackDateFormat(isolate, date_format_holder); 13884 if (!date_format) return isolate->ThrowIllegalOperation(); 13885 13886 UErrorCode status = U_ZERO_ERROR; 13887 UDate date = date_format->parse(u_date, status); 13888 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 13889 13890 bool has_pending_exception = false; 13891 Handle<JSDate> result = Handle<JSDate>::cast( 13892 Execution::NewDate( 13893 isolate, static_cast<double>(date), &has_pending_exception)); 13894 if (has_pending_exception) { 13895 ASSERT(isolate->has_pending_exception()); 13896 return Failure::Exception(); 13897 } 13898 return *result; 13899 } 13900 13901 13902 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateNumberFormat) { 13903 HandleScope scope(isolate); 13904 13905 ASSERT(args.length() == 3); 13906 13907 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 13908 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 13909 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 13910 13911 Handle<ObjectTemplateInfo> number_format_template = 13912 I18N::GetTemplate(isolate); 13913 13914 // Create an empty object wrapper. 13915 bool has_pending_exception = false; 13916 Handle<JSObject> local_object = Execution::InstantiateObject( 13917 number_format_template, &has_pending_exception); 13918 if (has_pending_exception) { 13919 ASSERT(isolate->has_pending_exception()); 13920 return Failure::Exception(); 13921 } 13922 13923 // Set number formatter as internal field of the resulting JS object. 13924 icu::DecimalFormat* number_format = NumberFormat::InitializeNumberFormat( 13925 isolate, locale, options, resolved); 13926 13927 if (!number_format) return isolate->ThrowIllegalOperation(); 13928 13929 local_object->SetInternalField(0, reinterpret_cast<Smi*>(number_format)); 13930 13931 RETURN_IF_EMPTY_HANDLE(isolate, 13932 JSObject::SetLocalPropertyIgnoreAttributes( 13933 local_object, 13934 isolate->factory()->NewStringFromAscii(CStrVector("numberFormat")), 13935 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 13936 NONE)); 13937 13938 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 13939 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), 13940 NULL, 13941 NumberFormat::DeleteNumberFormat); 13942 return *local_object; 13943 } 13944 13945 13946 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberFormat) { 13947 HandleScope scope(isolate); 13948 13949 ASSERT(args.length() == 2); 13950 13951 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 13952 CONVERT_ARG_HANDLE_CHECKED(Object, number, 1); 13953 13954 bool has_pending_exception = false; 13955 Handle<Object> value = Execution::ToNumber( 13956 isolate, number, &has_pending_exception); 13957 if (has_pending_exception) { 13958 ASSERT(isolate->has_pending_exception()); 13959 return Failure::Exception(); 13960 } 13961 13962 icu::DecimalFormat* number_format = 13963 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 13964 if (!number_format) return isolate->ThrowIllegalOperation(); 13965 13966 icu::UnicodeString result; 13967 number_format->format(value->Number(), result); 13968 13969 return *isolate->factory()->NewStringFromTwoByte( 13970 Vector<const uint16_t>( 13971 reinterpret_cast<const uint16_t*>(result.getBuffer()), 13972 result.length())); 13973 } 13974 13975 13976 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalNumberParse) { 13977 HandleScope scope(isolate); 13978 13979 ASSERT(args.length() == 2); 13980 13981 CONVERT_ARG_HANDLE_CHECKED(JSObject, number_format_holder, 0); 13982 CONVERT_ARG_HANDLE_CHECKED(String, number_string, 1); 13983 13984 v8::String::Utf8Value utf8_number(v8::Utils::ToLocal(number_string)); 13985 icu::UnicodeString u_number(icu::UnicodeString::fromUTF8(*utf8_number)); 13986 icu::DecimalFormat* number_format = 13987 NumberFormat::UnpackNumberFormat(isolate, number_format_holder); 13988 if (!number_format) return isolate->ThrowIllegalOperation(); 13989 13990 UErrorCode status = U_ZERO_ERROR; 13991 icu::Formattable result; 13992 // ICU 4.6 doesn't support parseCurrency call. We need to wait for ICU49 13993 // to be part of Chrome. 13994 // TODO(cira): Include currency parsing code using parseCurrency call. 13995 // We need to check if the formatter parses all currencies or only the 13996 // one it was constructed with (it will impact the API - how to return ISO 13997 // code and the value). 13998 number_format->parse(u_number, result, status); 13999 if (U_FAILURE(status)) return isolate->heap()->undefined_value(); 14000 14001 switch (result.getType()) { 14002 case icu::Formattable::kDouble: 14003 return *isolate->factory()->NewNumber(result.getDouble()); 14004 case icu::Formattable::kLong: 14005 return *isolate->factory()->NewNumberFromInt(result.getLong()); 14006 case icu::Formattable::kInt64: 14007 return *isolate->factory()->NewNumber( 14008 static_cast<double>(result.getInt64())); 14009 default: 14010 return isolate->heap()->undefined_value(); 14011 } 14012 } 14013 14014 14015 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCollator) { 14016 HandleScope scope(isolate); 14017 14018 ASSERT(args.length() == 3); 14019 14020 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14021 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14022 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14023 14024 Handle<ObjectTemplateInfo> collator_template = I18N::GetTemplate(isolate); 14025 14026 // Create an empty object wrapper. 14027 bool has_pending_exception = false; 14028 Handle<JSObject> local_object = Execution::InstantiateObject( 14029 collator_template, &has_pending_exception); 14030 if (has_pending_exception) { 14031 ASSERT(isolate->has_pending_exception()); 14032 return Failure::Exception(); 14033 } 14034 14035 // Set collator as internal field of the resulting JS object. 14036 icu::Collator* collator = Collator::InitializeCollator( 14037 isolate, locale, options, resolved); 14038 14039 if (!collator) return isolate->ThrowIllegalOperation(); 14040 14041 local_object->SetInternalField(0, reinterpret_cast<Smi*>(collator)); 14042 14043 RETURN_IF_EMPTY_HANDLE(isolate, 14044 JSObject::SetLocalPropertyIgnoreAttributes( 14045 local_object, 14046 isolate->factory()->NewStringFromAscii(CStrVector("collator")), 14047 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 14048 NONE)); 14049 14050 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14051 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), 14052 NULL, 14053 Collator::DeleteCollator); 14054 return *local_object; 14055 } 14056 14057 14058 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalCompare) { 14059 HandleScope scope(isolate); 14060 14061 ASSERT(args.length() == 3); 14062 14063 CONVERT_ARG_HANDLE_CHECKED(JSObject, collator_holder, 0); 14064 CONVERT_ARG_HANDLE_CHECKED(String, string1, 1); 14065 CONVERT_ARG_HANDLE_CHECKED(String, string2, 2); 14066 14067 icu::Collator* collator = Collator::UnpackCollator(isolate, collator_holder); 14068 if (!collator) return isolate->ThrowIllegalOperation(); 14069 14070 v8::String::Value string_value1(v8::Utils::ToLocal(string1)); 14071 v8::String::Value string_value2(v8::Utils::ToLocal(string2)); 14072 const UChar* u_string1 = reinterpret_cast<const UChar*>(*string_value1); 14073 const UChar* u_string2 = reinterpret_cast<const UChar*>(*string_value2); 14074 UErrorCode status = U_ZERO_ERROR; 14075 UCollationResult result = collator->compare(u_string1, 14076 string_value1.length(), 14077 u_string2, 14078 string_value2.length(), 14079 status); 14080 if (U_FAILURE(status)) return isolate->ThrowIllegalOperation(); 14081 14082 return *isolate->factory()->NewNumberFromInt(result); 14083 } 14084 14085 14086 RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateBreakIterator) { 14087 HandleScope scope(isolate); 14088 14089 ASSERT(args.length() == 3); 14090 14091 CONVERT_ARG_HANDLE_CHECKED(String, locale, 0); 14092 CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1); 14093 CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2); 14094 14095 Handle<ObjectTemplateInfo> break_iterator_template = 14096 I18N::GetTemplate2(isolate); 14097 14098 // Create an empty object wrapper. 14099 bool has_pending_exception = false; 14100 Handle<JSObject> local_object = Execution::InstantiateObject( 14101 break_iterator_template, &has_pending_exception); 14102 if (has_pending_exception) { 14103 ASSERT(isolate->has_pending_exception()); 14104 return Failure::Exception(); 14105 } 14106 14107 // Set break iterator as internal field of the resulting JS object. 14108 icu::BreakIterator* break_iterator = BreakIterator::InitializeBreakIterator( 14109 isolate, locale, options, resolved); 14110 14111 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14112 14113 local_object->SetInternalField(0, reinterpret_cast<Smi*>(break_iterator)); 14114 // Make sure that the pointer to adopted text is NULL. 14115 local_object->SetInternalField(1, reinterpret_cast<Smi*>(NULL)); 14116 14117 RETURN_IF_EMPTY_HANDLE(isolate, 14118 JSObject::SetLocalPropertyIgnoreAttributes( 14119 local_object, 14120 isolate->factory()->NewStringFromAscii(CStrVector("breakIterator")), 14121 isolate->factory()->NewStringFromAscii(CStrVector("valid")), 14122 NONE)); 14123 14124 // Make object handle weak so we can delete the break iterator once GC kicks 14125 // in. 14126 Handle<Object> wrapper = isolate->global_handles()->Create(*local_object); 14127 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(wrapper.location()), 14128 NULL, 14129 BreakIterator::DeleteBreakIterator); 14130 return *local_object; 14131 } 14132 14133 14134 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorAdoptText) { 14135 HandleScope scope(isolate); 14136 14137 ASSERT(args.length() == 2); 14138 14139 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14140 CONVERT_ARG_HANDLE_CHECKED(String, text, 1); 14141 14142 icu::BreakIterator* break_iterator = 14143 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14144 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14145 14146 icu::UnicodeString* u_text = reinterpret_cast<icu::UnicodeString*>( 14147 break_iterator_holder->GetInternalField(1)); 14148 delete u_text; 14149 14150 v8::String::Value text_value(v8::Utils::ToLocal(text)); 14151 u_text = new icu::UnicodeString( 14152 reinterpret_cast<const UChar*>(*text_value), text_value.length()); 14153 break_iterator_holder->SetInternalField(1, reinterpret_cast<Smi*>(u_text)); 14154 14155 break_iterator->setText(*u_text); 14156 14157 return isolate->heap()->undefined_value(); 14158 } 14159 14160 14161 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorFirst) { 14162 HandleScope scope(isolate); 14163 14164 ASSERT(args.length() == 1); 14165 14166 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14167 14168 icu::BreakIterator* break_iterator = 14169 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14170 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14171 14172 return *isolate->factory()->NewNumberFromInt(break_iterator->first()); 14173 } 14174 14175 14176 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorNext) { 14177 HandleScope scope(isolate); 14178 14179 ASSERT(args.length() == 1); 14180 14181 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14182 14183 icu::BreakIterator* break_iterator = 14184 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14185 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14186 14187 return *isolate->factory()->NewNumberFromInt(break_iterator->next()); 14188 } 14189 14190 14191 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorCurrent) { 14192 HandleScope scope(isolate); 14193 14194 ASSERT(args.length() == 1); 14195 14196 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14197 14198 icu::BreakIterator* break_iterator = 14199 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14200 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14201 14202 return *isolate->factory()->NewNumberFromInt(break_iterator->current()); 14203 } 14204 14205 14206 RUNTIME_FUNCTION(MaybeObject*, Runtime_BreakIteratorBreakType) { 14207 HandleScope scope(isolate); 14208 14209 ASSERT(args.length() == 1); 14210 14211 CONVERT_ARG_HANDLE_CHECKED(JSObject, break_iterator_holder, 0); 14212 14213 icu::BreakIterator* break_iterator = 14214 BreakIterator::UnpackBreakIterator(isolate, break_iterator_holder); 14215 if (!break_iterator) return isolate->ThrowIllegalOperation(); 14216 14217 // TODO(cira): Remove cast once ICU fixes base BreakIterator class. 14218 icu::RuleBasedBreakIterator* rule_based_iterator = 14219 static_cast<icu::RuleBasedBreakIterator*>(break_iterator); 14220 int32_t status = rule_based_iterator->getRuleStatus(); 14221 // Keep return values in sync with JavaScript BreakType enum. 14222 if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) { 14223 return *isolate->factory()->NewStringFromAscii(CStrVector("none")); 14224 } else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) { 14225 return *isolate->factory()->NewStringFromAscii(CStrVector("number")); 14226 } else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) { 14227 return *isolate->factory()->NewStringFromAscii(CStrVector("letter")); 14228 } else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) { 14229 return *isolate->factory()->NewStringFromAscii(CStrVector("kana")); 14230 } else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) { 14231 return *isolate->factory()->NewStringFromAscii(CStrVector("ideo")); 14232 } else { 14233 return *isolate->factory()->NewStringFromAscii(CStrVector("unknown")); 14234 } 14235 } 14236 #endif // V8_I18N_SUPPORT 14237 14238 14239 // Finds the script object from the script data. NOTE: This operation uses 14240 // heap traversal to find the function generated for the source position 14241 // for the requested break point. For lazily compiled functions several heap 14242 // traversals might be required rendering this operation as a rather slow 14243 // operation. However for setting break points which is normally done through 14244 // some kind of user interaction the performance is not crucial. 14245 static Handle<Object> Runtime_GetScriptFromScriptName( 14246 Handle<String> script_name) { 14247 // Scan the heap for Script objects to find the script with the requested 14248 // script data. 14249 Handle<Script> script; 14250 Factory* factory = script_name->GetIsolate()->factory(); 14251 Heap* heap = script_name->GetHeap(); 14252 heap->EnsureHeapIsIterable(); 14253 DisallowHeapAllocation no_allocation_during_heap_iteration; 14254 HeapIterator iterator(heap); 14255 HeapObject* obj = NULL; 14256 while (script.is_null() && ((obj = iterator.next()) != NULL)) { 14257 // If a script is found check if it has the script data requested. 14258 if (obj->IsScript()) { 14259 if (Script::cast(obj)->name()->IsString()) { 14260 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) { 14261 script = Handle<Script>(Script::cast(obj)); 14262 } 14263 } 14264 } 14265 } 14266 14267 // If no script with the requested script data is found return undefined. 14268 if (script.is_null()) return factory->undefined_value(); 14269 14270 // Return the script found. 14271 return GetScriptWrapper(script); 14272 } 14273 14274 14275 // Get the script object from script data. NOTE: Regarding performance 14276 // see the NOTE for GetScriptFromScriptData. 14277 // args[0]: script data for the script to find the source for 14278 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) { 14279 HandleScope scope(isolate); 14280 14281 ASSERT(args.length() == 1); 14282 14283 CONVERT_ARG_CHECKED(String, script_name, 0); 14284 14285 // Find the requested script. 14286 Handle<Object> result = 14287 Runtime_GetScriptFromScriptName(Handle<String>(script_name)); 14288 return *result; 14289 } 14290 14291 14292 // Collect the raw data for a stack trace. Returns an array of 4 14293 // element segments each containing a receiver, function, code and 14294 // native code offset. 14295 RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) { 14296 HandleScope scope(isolate); 14297 ASSERT_EQ(args.length(), 3); 14298 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 14299 Handle<Object> caller = args.at<Object>(1); 14300 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]); 14301 14302 // Optionally capture a more detailed stack trace for the message. 14303 isolate->CaptureAndSetDetailedStackTrace(error_object); 14304 // Capture a simple stack trace for the stack property. 14305 return *isolate->CaptureSimpleStackTrace(error_object, caller, limit); 14306 } 14307 14308 14309 // Retrieve the stack trace. This is the raw stack trace that yet has to 14310 // be formatted. Since we only need this once, clear it afterwards. 14311 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetAndClearOverflowedStackTrace) { 14312 HandleScope scope(isolate); 14313 ASSERT_EQ(args.length(), 1); 14314 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0); 14315 Handle<String> key = isolate->factory()->hidden_stack_trace_string(); 14316 Handle<Object> result(error_object->GetHiddenProperty(*key), isolate); 14317 if (result->IsTheHole()) return isolate->heap()->undefined_value(); 14318 RUNTIME_ASSERT(result->IsJSArray() || result->IsUndefined()); 14319 JSObject::DeleteHiddenProperty(error_object, key); 14320 return *result; 14321 } 14322 14323 14324 // Returns V8 version as a string. 14325 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) { 14326 SealHandleScope shs(isolate); 14327 ASSERT_EQ(args.length(), 0); 14328 14329 const char* version_string = v8::V8::GetVersion(); 14330 14331 return isolate->heap()->AllocateStringFromOneByte(CStrVector(version_string), 14332 NOT_TENURED); 14333 } 14334 14335 14336 RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) { 14337 SealHandleScope shs(isolate); 14338 ASSERT(args.length() == 2); 14339 OS::PrintError("abort: %s\n", 14340 reinterpret_cast<char*>(args[0]) + args.smi_at(1)); 14341 isolate->PrintStack(stderr); 14342 OS::Abort(); 14343 UNREACHABLE(); 14344 return NULL; 14345 } 14346 14347 14348 RUNTIME_FUNCTION(MaybeObject*, Runtime_AbortJS) { 14349 HandleScope scope(isolate); 14350 ASSERT(args.length() == 1); 14351 CONVERT_ARG_HANDLE_CHECKED(String, message, 0); 14352 OS::PrintError("abort: %s\n", *message->ToCString()); 14353 isolate->PrintStack(stderr); 14354 OS::Abort(); 14355 UNREACHABLE(); 14356 return NULL; 14357 } 14358 14359 14360 RUNTIME_FUNCTION(MaybeObject*, Runtime_FlattenString) { 14361 HandleScope scope(isolate); 14362 ASSERT(args.length() == 1); 14363 CONVERT_ARG_HANDLE_CHECKED(String, str, 0); 14364 FlattenString(str); 14365 return isolate->heap()->undefined_value(); 14366 } 14367 14368 14369 RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyContextDisposed) { 14370 HandleScope scope(isolate); 14371 ASSERT(args.length() == 0); 14372 isolate->heap()->NotifyContextDisposed(); 14373 return isolate->heap()->undefined_value(); 14374 } 14375 14376 14377 RUNTIME_FUNCTION(MaybeObject*, Runtime_MigrateInstance) { 14378 HandleScope scope(isolate); 14379 ASSERT(args.length() == 1); 14380 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); 14381 if (!object->IsJSObject()) return Smi::FromInt(0); 14382 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 14383 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0); 14384 JSObject::MigrateInstance(js_object); 14385 return *object; 14386 } 14387 14388 14389 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) { 14390 SealHandleScope shs(isolate); 14391 // This is only called from codegen, so checks might be more lax. 14392 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0); 14393 Object* key = args[1]; 14394 14395 int finger_index = cache->finger_index(); 14396 Object* o = cache->get(finger_index); 14397 if (o == key) { 14398 // The fastest case: hit the same place again. 14399 return cache->get(finger_index + 1); 14400 } 14401 14402 for (int i = finger_index - 2; 14403 i >= JSFunctionResultCache::kEntriesIndex; 14404 i -= 2) { 14405 o = cache->get(i); 14406 if (o == key) { 14407 cache->set_finger_index(i); 14408 return cache->get(i + 1); 14409 } 14410 } 14411 14412 int size = cache->size(); 14413 ASSERT(size <= cache->length()); 14414 14415 for (int i = size - 2; i > finger_index; i -= 2) { 14416 o = cache->get(i); 14417 if (o == key) { 14418 cache->set_finger_index(i); 14419 return cache->get(i + 1); 14420 } 14421 } 14422 14423 // There is no value in the cache. Invoke the function and cache result. 14424 HandleScope scope(isolate); 14425 14426 Handle<JSFunctionResultCache> cache_handle(cache); 14427 Handle<Object> key_handle(key, isolate); 14428 Handle<Object> value; 14429 { 14430 Handle<JSFunction> factory(JSFunction::cast( 14431 cache_handle->get(JSFunctionResultCache::kFactoryIndex))); 14432 // TODO(antonm): consider passing a receiver when constructing a cache. 14433 Handle<Object> receiver(isolate->native_context()->global_object(), 14434 isolate); 14435 // This handle is nor shared, nor used later, so it's safe. 14436 Handle<Object> argv[] = { key_handle }; 14437 bool pending_exception; 14438 value = Execution::Call(isolate, 14439 factory, 14440 receiver, 14441 ARRAY_SIZE(argv), 14442 argv, 14443 &pending_exception); 14444 if (pending_exception) return Failure::Exception(); 14445 } 14446 14447 #ifdef VERIFY_HEAP 14448 if (FLAG_verify_heap) { 14449 cache_handle->JSFunctionResultCacheVerify(); 14450 } 14451 #endif 14452 14453 // Function invocation may have cleared the cache. Reread all the data. 14454 finger_index = cache_handle->finger_index(); 14455 size = cache_handle->size(); 14456 14457 // If we have spare room, put new data into it, otherwise evict post finger 14458 // entry which is likely to be the least recently used. 14459 int index = -1; 14460 if (size < cache_handle->length()) { 14461 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize); 14462 index = size; 14463 } else { 14464 index = finger_index + JSFunctionResultCache::kEntrySize; 14465 if (index == cache_handle->length()) { 14466 index = JSFunctionResultCache::kEntriesIndex; 14467 } 14468 } 14469 14470 ASSERT(index % 2 == 0); 14471 ASSERT(index >= JSFunctionResultCache::kEntriesIndex); 14472 ASSERT(index < cache_handle->length()); 14473 14474 cache_handle->set(index, *key_handle); 14475 cache_handle->set(index + 1, *value); 14476 cache_handle->set_finger_index(index); 14477 14478 #ifdef VERIFY_HEAP 14479 if (FLAG_verify_heap) { 14480 cache_handle->JSFunctionResultCacheVerify(); 14481 } 14482 #endif 14483 14484 return *value; 14485 } 14486 14487 14488 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) { 14489 SealHandleScope shs(isolate); 14490 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14491 return Smi::FromInt(message->start_position()); 14492 } 14493 14494 14495 RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) { 14496 SealHandleScope shs(isolate); 14497 CONVERT_ARG_CHECKED(JSMessageObject, message, 0); 14498 return message->script(); 14499 } 14500 14501 14502 #ifdef DEBUG 14503 // ListNatives is ONLY used by the fuzz-natives.js in debug mode 14504 // Exclude the code in release mode. 14505 RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) { 14506 HandleScope scope(isolate); 14507 ASSERT(args.length() == 0); 14508 #define COUNT_ENTRY(Name, argc, ressize) + 1 14509 int entry_count = 0 14510 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) 14511 INLINE_FUNCTION_LIST(COUNT_ENTRY) 14512 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY); 14513 #undef COUNT_ENTRY 14514 Factory* factory = isolate->factory(); 14515 Handle<FixedArray> elements = factory->NewFixedArray(entry_count); 14516 int index = 0; 14517 bool inline_runtime_functions = false; 14518 #define ADD_ENTRY(Name, argc, ressize) \ 14519 { \ 14520 HandleScope inner(isolate); \ 14521 Handle<String> name; \ 14522 /* Inline runtime functions have an underscore in front of the name. */ \ 14523 if (inline_runtime_functions) { \ 14524 name = factory->NewStringFromAscii( \ 14525 Vector<const char>("_" #Name, StrLength("_" #Name))); \ 14526 } else { \ 14527 name = factory->NewStringFromAscii( \ 14528 Vector<const char>(#Name, StrLength(#Name))); \ 14529 } \ 14530 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \ 14531 pair_elements->set(0, *name); \ 14532 pair_elements->set(1, Smi::FromInt(argc)); \ 14533 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \ 14534 elements->set(index++, *pair); \ 14535 } 14536 inline_runtime_functions = false; 14537 RUNTIME_FUNCTION_LIST(ADD_ENTRY) 14538 inline_runtime_functions = true; 14539 INLINE_FUNCTION_LIST(ADD_ENTRY) 14540 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY) 14541 #undef ADD_ENTRY 14542 ASSERT_EQ(index, entry_count); 14543 Handle<JSArray> result = factory->NewJSArrayWithElements(elements); 14544 return *result; 14545 } 14546 #endif 14547 14548 14549 RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) { 14550 SealHandleScope shs(isolate); 14551 ASSERT(args.length() == 2); 14552 CONVERT_ARG_CHECKED(String, format, 0); 14553 CONVERT_ARG_CHECKED(JSArray, elms, 1); 14554 DisallowHeapAllocation no_gc; 14555 String::FlatContent format_content = format->GetFlatContent(); 14556 RUNTIME_ASSERT(format_content.IsAscii()); 14557 Vector<const uint8_t> chars = format_content.ToOneByteVector(); 14558 isolate->logger()->LogRuntime(Vector<const char>::cast(chars), elms); 14559 return isolate->heap()->undefined_value(); 14560 } 14561 14562 14563 RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) { 14564 UNREACHABLE(); // implemented as macro in the parser 14565 return NULL; 14566 } 14567 14568 14569 #define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \ 14570 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \ 14571 CONVERT_ARG_CHECKED(JSObject, obj, 0); \ 14572 return isolate->heap()->ToBoolean(obj->Has##Name()); \ 14573 } 14574 14575 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiElements) 14576 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastObjectElements) 14577 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOrObjectElements) 14578 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) 14579 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) 14580 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) 14581 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(NonStrictArgumentsElements) 14582 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements) 14583 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) 14584 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements) 14585 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements) 14586 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements) 14587 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements) 14588 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements) 14589 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements) 14590 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements) 14591 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements) 14592 // Properties test sitting with elements tests - not fooling anyone. 14593 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) 14594 14595 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION 14596 14597 14598 RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) { 14599 SealHandleScope shs(isolate); 14600 ASSERT(args.length() == 2); 14601 CONVERT_ARG_CHECKED(JSObject, obj1, 0); 14602 CONVERT_ARG_CHECKED(JSObject, obj2, 1); 14603 return isolate->heap()->ToBoolean(obj1->map() == obj2->map()); 14604 } 14605 14606 14607 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessCheckNeeded) { 14608 SealHandleScope shs(isolate); 14609 ASSERT(args.length() == 1); 14610 CONVERT_ARG_CHECKED(HeapObject, obj, 0); 14611 return isolate->heap()->ToBoolean(obj->IsAccessCheckNeeded()); 14612 } 14613 14614 14615 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsObserved) { 14616 SealHandleScope shs(isolate); 14617 ASSERT(args.length() == 1); 14618 14619 if (!args[0]->IsJSReceiver()) return isolate->heap()->false_value(); 14620 JSReceiver* obj = JSReceiver::cast(args[0]); 14621 if (obj->IsJSGlobalProxy()) { 14622 Object* proto = obj->GetPrototype(); 14623 if (proto->IsNull()) return isolate->heap()->false_value(); 14624 ASSERT(proto->IsJSGlobalObject()); 14625 obj = JSReceiver::cast(proto); 14626 } 14627 return isolate->heap()->ToBoolean(obj->map()->is_observed()); 14628 } 14629 14630 14631 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) { 14632 HandleScope scope(isolate); 14633 ASSERT(args.length() == 1); 14634 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0); 14635 if (obj->IsJSGlobalProxy()) { 14636 Object* proto = obj->GetPrototype(); 14637 if (proto->IsNull()) return isolate->heap()->undefined_value(); 14638 ASSERT(proto->IsJSGlobalObject()); 14639 obj = handle(JSReceiver::cast(proto)); 14640 } 14641 if (obj->IsJSProxy()) 14642 return isolate->heap()->undefined_value(); 14643 14644 ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() && 14645 Handle<JSObject>::cast(obj)->HasFastElements())); 14646 ASSERT(obj->IsJSObject()); 14647 JSObject::SetObserved(Handle<JSObject>::cast(obj)); 14648 return isolate->heap()->undefined_value(); 14649 } 14650 14651 14652 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetMicrotaskPending) { 14653 SealHandleScope shs(isolate); 14654 ASSERT(args.length() == 1); 14655 CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0); 14656 bool old_state = isolate->microtask_pending(); 14657 isolate->set_microtask_pending(new_state); 14658 return isolate->heap()->ToBoolean(old_state); 14659 } 14660 14661 14662 RUNTIME_FUNCTION(MaybeObject*, Runtime_GetObservationState) { 14663 SealHandleScope shs(isolate); 14664 ASSERT(args.length() == 0); 14665 return isolate->heap()->observation_state(); 14666 } 14667 14668 14669 RUNTIME_FUNCTION(MaybeObject*, Runtime_ObservationWeakMapCreate) { 14670 HandleScope scope(isolate); 14671 ASSERT(args.length() == 0); 14672 // TODO(adamk): Currently this runtime function is only called three times per 14673 // isolate. If it's called more often, the map should be moved into the 14674 // strong root list. 14675 Handle<Map> map = 14676 isolate->factory()->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize); 14677 Handle<JSWeakMap> weakmap = 14678 Handle<JSWeakMap>::cast(isolate->factory()->NewJSObjectFromMap(map)); 14679 return WeakCollectionInitialize(isolate, weakmap); 14680 } 14681 14682 14683 RUNTIME_FUNCTION(MaybeObject*, Runtime_UnwrapGlobalProxy) { 14684 SealHandleScope shs(isolate); 14685 ASSERT(args.length() == 1); 14686 Object* object = args[0]; 14687 if (object->IsJSGlobalProxy()) { 14688 object = object->GetPrototype(isolate); 14689 if (object->IsNull()) return isolate->heap()->undefined_value(); 14690 } 14691 return object; 14692 } 14693 14694 14695 RUNTIME_FUNCTION(MaybeObject*, Runtime_IsAccessAllowedForObserver) { 14696 HandleScope scope(isolate); 14697 ASSERT(args.length() == 3); 14698 CONVERT_ARG_HANDLE_CHECKED(JSFunction, observer, 0); 14699 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 1); 14700 ASSERT(object->IsAccessCheckNeeded()); 14701 Handle<Object> key = args.at<Object>(2); 14702 SaveContext save(isolate); 14703 isolate->set_context(observer->context()); 14704 if (!isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(), 14705 v8::ACCESS_KEYS)) { 14706 return isolate->heap()->false_value(); 14707 } 14708 bool access_allowed = false; 14709 uint32_t index = 0; 14710 if (key->ToArrayIndex(&index) || 14711 (key->IsString() && String::cast(*key)->AsArrayIndex(&index))) { 14712 access_allowed = 14713 isolate->MayIndexedAccess(*object, index, v8::ACCESS_GET) && 14714 isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS); 14715 } else { 14716 access_allowed = isolate->MayNamedAccess(*object, *key, v8::ACCESS_GET) && 14717 isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS); 14718 } 14719 return isolate->heap()->ToBoolean(access_allowed); 14720 } 14721 14722 14723 static MaybeObject* ArrayConstructorCommon(Isolate* isolate, 14724 Handle<JSFunction> constructor, 14725 Handle<AllocationSite> site, 14726 Arguments* caller_args) { 14727 bool holey = false; 14728 bool can_use_type_feedback = true; 14729 if (caller_args->length() == 1) { 14730 Object* argument_one = (*caller_args)[0]; 14731 if (argument_one->IsSmi()) { 14732 int value = Smi::cast(argument_one)->value(); 14733 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) { 14734 // the array is a dictionary in this case. 14735 can_use_type_feedback = false; 14736 } else if (value != 0) { 14737 holey = true; 14738 } 14739 } else { 14740 // Non-smi length argument produces a dictionary 14741 can_use_type_feedback = false; 14742 } 14743 } 14744 14745 JSArray* array; 14746 MaybeObject* maybe_array; 14747 if (!site.is_null() && can_use_type_feedback) { 14748 ElementsKind to_kind = site->GetElementsKind(); 14749 if (holey && !IsFastHoleyElementsKind(to_kind)) { 14750 to_kind = GetHoleyElementsKind(to_kind); 14751 // Update the allocation site info to reflect the advice alteration. 14752 site->SetElementsKind(to_kind); 14753 } 14754 14755 maybe_array = isolate->heap()->AllocateJSObjectWithAllocationSite( 14756 *constructor, site); 14757 if (!maybe_array->To(&array)) return maybe_array; 14758 } else { 14759 maybe_array = isolate->heap()->AllocateJSObject(*constructor); 14760 if (!maybe_array->To(&array)) return maybe_array; 14761 // We might need to transition to holey 14762 ElementsKind kind = constructor->initial_map()->elements_kind(); 14763 if (holey && !IsFastHoleyElementsKind(kind)) { 14764 kind = GetHoleyElementsKind(kind); 14765 maybe_array = array->TransitionElementsKind(kind); 14766 if (maybe_array->IsFailure()) return maybe_array; 14767 } 14768 } 14769 14770 maybe_array = isolate->heap()->AllocateJSArrayStorage(array, 0, 0, 14771 DONT_INITIALIZE_ARRAY_ELEMENTS); 14772 if (maybe_array->IsFailure()) return maybe_array; 14773 ElementsKind old_kind = array->GetElementsKind(); 14774 maybe_array = ArrayConstructInitializeElements(array, caller_args); 14775 if (maybe_array->IsFailure()) return maybe_array; 14776 if (!site.is_null() && 14777 (old_kind != array->GetElementsKind() || 14778 !can_use_type_feedback)) { 14779 // The arguments passed in caused a transition. This kind of complexity 14780 // can't be dealt with in the inlined hydrogen array constructor case. 14781 // We must mark the allocationsite as un-inlinable. 14782 site->SetDoNotInlineCall(); 14783 } 14784 return array; 14785 } 14786 14787 14788 RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) { 14789 HandleScope scope(isolate); 14790 // If we get 2 arguments then they are the stub parameters (constructor, type 14791 // info). If we get 4, then the first one is a pointer to the arguments 14792 // passed by the caller, and the last one is the length of the arguments 14793 // passed to the caller (redundant, but useful to check on the deoptimizer 14794 // with an assert). 14795 Arguments empty_args(0, NULL); 14796 bool no_caller_args = args.length() == 2; 14797 ASSERT(no_caller_args || args.length() == 4); 14798 int parameters_start = no_caller_args ? 0 : 1; 14799 Arguments* caller_args = no_caller_args 14800 ? &empty_args 14801 : reinterpret_cast<Arguments*>(args[0]); 14802 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 14803 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1); 14804 #ifdef DEBUG 14805 if (!no_caller_args) { 14806 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2); 14807 ASSERT(arg_count == caller_args->length()); 14808 } 14809 #endif 14810 14811 Handle<AllocationSite> site; 14812 if (!type_info.is_null() && 14813 *type_info != isolate->heap()->undefined_value() && 14814 Cell::cast(*type_info)->value()->IsAllocationSite()) { 14815 site = Handle<AllocationSite>( 14816 AllocationSite::cast(Cell::cast(*type_info)->value()), isolate); 14817 ASSERT(!site->SitePointsToLiteral()); 14818 } 14819 14820 return ArrayConstructorCommon(isolate, 14821 constructor, 14822 site, 14823 caller_args); 14824 } 14825 14826 14827 RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalArrayConstructor) { 14828 HandleScope scope(isolate); 14829 Arguments empty_args(0, NULL); 14830 bool no_caller_args = args.length() == 1; 14831 ASSERT(no_caller_args || args.length() == 3); 14832 int parameters_start = no_caller_args ? 0 : 1; 14833 Arguments* caller_args = no_caller_args 14834 ? &empty_args 14835 : reinterpret_cast<Arguments*>(args[0]); 14836 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start); 14837 #ifdef DEBUG 14838 if (!no_caller_args) { 14839 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1); 14840 ASSERT(arg_count == caller_args->length()); 14841 } 14842 #endif 14843 return ArrayConstructorCommon(isolate, 14844 constructor, 14845 Handle<AllocationSite>::null(), 14846 caller_args); 14847 } 14848 14849 14850 RUNTIME_FUNCTION(MaybeObject*, Runtime_MaxSmi) { 14851 return Smi::FromInt(Smi::kMaxValue); 14852 } 14853 14854 14855 // ---------------------------------------------------------------------------- 14856 // Implementation of Runtime 14857 14858 #define F(name, number_of_args, result_size) \ 14859 { Runtime::k##name, Runtime::RUNTIME, #name, \ 14860 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size }, 14861 14862 14863 #define I(name, number_of_args, result_size) \ 14864 { Runtime::kInline##name, Runtime::INLINE, \ 14865 "_" #name, NULL, number_of_args, result_size }, 14866 14867 static const Runtime::Function kIntrinsicFunctions[] = { 14868 RUNTIME_FUNCTION_LIST(F) 14869 INLINE_FUNCTION_LIST(I) 14870 INLINE_RUNTIME_FUNCTION_LIST(I) 14871 }; 14872 14873 14874 MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap, 14875 Object* dictionary) { 14876 ASSERT(dictionary != NULL); 14877 ASSERT(NameDictionary::cast(dictionary)->NumberOfElements() == 0); 14878 for (int i = 0; i < kNumFunctions; ++i) { 14879 Object* name_string; 14880 { MaybeObject* maybe_name_string = 14881 heap->InternalizeUtf8String(kIntrinsicFunctions[i].name); 14882 if (!maybe_name_string->ToObject(&name_string)) return maybe_name_string; 14883 } 14884 NameDictionary* name_dictionary = NameDictionary::cast(dictionary); 14885 { MaybeObject* maybe_dictionary = name_dictionary->Add( 14886 String::cast(name_string), 14887 Smi::FromInt(i), 14888 PropertyDetails(NONE, NORMAL, Representation::None())); 14889 if (!maybe_dictionary->ToObject(&dictionary)) { 14890 // Non-recoverable failure. Calling code must restart heap 14891 // initialization. 14892 return maybe_dictionary; 14893 } 14894 } 14895 } 14896 return dictionary; 14897 } 14898 14899 14900 const Runtime::Function* Runtime::FunctionForName(Handle<String> name) { 14901 Heap* heap = name->GetHeap(); 14902 int entry = heap->intrinsic_function_names()->FindEntry(*name); 14903 if (entry != kNotFound) { 14904 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry); 14905 int function_index = Smi::cast(smi_index)->value(); 14906 return &(kIntrinsicFunctions[function_index]); 14907 } 14908 return NULL; 14909 } 14910 14911 14912 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) { 14913 return &(kIntrinsicFunctions[static_cast<int>(id)]); 14914 } 14915 14916 14917 void Runtime::PerformGC(Object* result, Isolate* isolate) { 14918 Failure* failure = Failure::cast(result); 14919 if (failure->IsRetryAfterGC()) { 14920 if (isolate->heap()->new_space()->AddFreshPage()) { 14921 return; 14922 } 14923 14924 // Try to do a garbage collection; ignore it if it fails. The C 14925 // entry stub will throw an out-of-memory exception in that case. 14926 isolate->heap()->CollectGarbage(failure->allocation_space(), 14927 "Runtime::PerformGC"); 14928 } else { 14929 // Handle last resort GC and make sure to allow future allocations 14930 // to grow the heap without causing GCs (if possible). 14931 isolate->counters()->gc_last_resort_from_js()->Increment(); 14932 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 14933 "Runtime::PerformGC"); 14934 } 14935 } 14936 14937 14938 } } // namespace v8::internal 14939