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 "v8.h" 29 30 #include "bootstrapper.h" 31 #include "code-stubs.h" 32 #include "cpu-profiler.h" 33 #include "stub-cache.h" 34 #include "factory.h" 35 #include "gdb-jit.h" 36 #include "macro-assembler.h" 37 38 namespace v8 { 39 namespace internal { 40 41 42 CodeStubInterfaceDescriptor::CodeStubInterfaceDescriptor() 43 : register_param_count_(-1), 44 stack_parameter_count_(NULL), 45 hint_stack_parameter_count_(-1), 46 function_mode_(NOT_JS_FUNCTION_STUB_MODE), 47 register_params_(NULL), 48 deoptimization_handler_(NULL), 49 miss_handler_(IC_Utility(IC::kUnreachable), Isolate::Current()), 50 has_miss_handler_(false) { } 51 52 53 bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) { 54 UnseededNumberDictionary* stubs = isolate->heap()->code_stubs(); 55 int index = stubs->FindEntry(GetKey()); 56 if (index != UnseededNumberDictionary::kNotFound) { 57 *code_out = Code::cast(stubs->ValueAt(index)); 58 return true; 59 } 60 return false; 61 } 62 63 64 SmartArrayPointer<const char> CodeStub::GetName() { 65 char buffer[100]; 66 NoAllocationStringAllocator allocator(buffer, 67 static_cast<unsigned>(sizeof(buffer))); 68 StringStream stream(&allocator); 69 PrintName(&stream); 70 return stream.ToCString(); 71 } 72 73 74 void CodeStub::RecordCodeGeneration(Code* code, Isolate* isolate) { 75 SmartArrayPointer<const char> name = GetName(); 76 PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name)); 77 GDBJIT(AddCode(GDBJITInterface::STUB, *name, code)); 78 Counters* counters = isolate->counters(); 79 counters->total_stubs_code_size()->Increment(code->instruction_size()); 80 } 81 82 83 Code::Kind CodeStub::GetCodeKind() const { 84 return Code::STUB; 85 } 86 87 88 Handle<Code> CodeStub::GetCodeCopyFromTemplate(Isolate* isolate) { 89 Handle<Code> ic = GetCode(isolate); 90 ic = isolate->factory()->CopyCode(ic); 91 RecordCodeGeneration(*ic, isolate); 92 return ic; 93 } 94 95 96 Handle<Code> PlatformCodeStub::GenerateCode() { 97 Isolate* isolate = Isolate::Current(); 98 Factory* factory = isolate->factory(); 99 100 // Generate the new code. 101 MacroAssembler masm(isolate, NULL, 256); 102 103 { 104 // Update the static counter each time a new code stub is generated. 105 isolate->counters()->code_stubs()->Increment(); 106 107 // Nested stubs are not allowed for leaves. 108 AllowStubCallsScope allow_scope(&masm, false); 109 110 // Generate the code for the stub. 111 masm.set_generating_stub(true); 112 NoCurrentFrameScope scope(&masm); 113 Generate(&masm); 114 } 115 116 // Create the code object. 117 CodeDesc desc; 118 masm.GetCode(&desc); 119 120 // Copy the generated code into a heap object. 121 Code::Flags flags = Code::ComputeFlags( 122 GetCodeKind(), 123 GetICState(), 124 GetExtraICState(), 125 GetStubType(), 126 GetStubFlags()); 127 Handle<Code> new_object = factory->NewCode( 128 desc, flags, masm.CodeObject(), NeedsImmovableCode()); 129 return new_object; 130 } 131 132 133 Handle<Code> CodeStub::GetCode(Isolate* isolate) { 134 Factory* factory = isolate->factory(); 135 Heap* heap = isolate->heap(); 136 Code* code; 137 if (UseSpecialCache() 138 ? FindCodeInSpecialCache(&code, isolate) 139 : FindCodeInCache(&code, isolate)) { 140 ASSERT(IsPregenerated() == code->is_pregenerated()); 141 return Handle<Code>(code); 142 } 143 144 { 145 HandleScope scope(isolate); 146 147 Handle<Code> new_object = GenerateCode(); 148 new_object->set_major_key(MajorKey()); 149 FinishCode(new_object); 150 RecordCodeGeneration(*new_object, isolate); 151 152 #ifdef ENABLE_DISASSEMBLER 153 if (FLAG_print_code_stubs) { 154 new_object->Disassemble(*GetName()); 155 PrintF("\n"); 156 } 157 #endif 158 159 if (UseSpecialCache()) { 160 AddToSpecialCache(new_object); 161 } else { 162 // Update the dictionary and the root in Heap. 163 Handle<UnseededNumberDictionary> dict = 164 factory->DictionaryAtNumberPut( 165 Handle<UnseededNumberDictionary>(heap->code_stubs()), 166 GetKey(), 167 new_object); 168 heap->public_set_code_stubs(*dict); 169 } 170 code = *new_object; 171 } 172 173 Activate(code); 174 ASSERT(!NeedsImmovableCode() || 175 heap->lo_space()->Contains(code) || 176 heap->code_space()->FirstPage()->Contains(code->address())); 177 return Handle<Code>(code, isolate); 178 } 179 180 181 const char* CodeStub::MajorName(CodeStub::Major major_key, 182 bool allow_unknown_keys) { 183 switch (major_key) { 184 #define DEF_CASE(name) case name: return #name "Stub"; 185 CODE_STUB_LIST(DEF_CASE) 186 #undef DEF_CASE 187 default: 188 if (!allow_unknown_keys) { 189 UNREACHABLE(); 190 } 191 return NULL; 192 } 193 } 194 195 196 void CodeStub::PrintBaseName(StringStream* stream) { 197 stream->Add("%s", MajorName(MajorKey(), false)); 198 } 199 200 201 void CodeStub::PrintName(StringStream* stream) { 202 PrintBaseName(stream); 203 PrintState(stream); 204 } 205 206 207 void BinaryOpStub::Generate(MacroAssembler* masm) { 208 // Explicitly allow generation of nested stubs. It is safe here because 209 // generation code does not use any raw pointers. 210 AllowStubCallsScope allow_stub_calls(masm, true); 211 212 BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_); 213 if (left_type_ == BinaryOpIC::ODDBALL && right_type_ == BinaryOpIC::ODDBALL) { 214 // The OddballStub handles a number and an oddball, not two oddballs. 215 operands_type = BinaryOpIC::GENERIC; 216 } 217 switch (operands_type) { 218 case BinaryOpIC::UNINITIALIZED: 219 GenerateTypeTransition(masm); 220 break; 221 case BinaryOpIC::SMI: 222 GenerateSmiStub(masm); 223 break; 224 case BinaryOpIC::INT32: 225 GenerateInt32Stub(masm); 226 break; 227 case BinaryOpIC::NUMBER: 228 GenerateNumberStub(masm); 229 break; 230 case BinaryOpIC::ODDBALL: 231 GenerateOddballStub(masm); 232 break; 233 case BinaryOpIC::STRING: 234 GenerateStringStub(masm); 235 break; 236 case BinaryOpIC::GENERIC: 237 GenerateGeneric(masm); 238 break; 239 default: 240 UNREACHABLE(); 241 } 242 } 243 244 245 #define __ ACCESS_MASM(masm) 246 247 248 void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { 249 switch (op_) { 250 case Token::ADD: 251 __ InvokeBuiltin(Builtins::ADD, CALL_FUNCTION); 252 break; 253 case Token::SUB: 254 __ InvokeBuiltin(Builtins::SUB, CALL_FUNCTION); 255 break; 256 case Token::MUL: 257 __ InvokeBuiltin(Builtins::MUL, CALL_FUNCTION); 258 break; 259 case Token::DIV: 260 __ InvokeBuiltin(Builtins::DIV, CALL_FUNCTION); 261 break; 262 case Token::MOD: 263 __ InvokeBuiltin(Builtins::MOD, CALL_FUNCTION); 264 break; 265 case Token::BIT_OR: 266 __ InvokeBuiltin(Builtins::BIT_OR, CALL_FUNCTION); 267 break; 268 case Token::BIT_AND: 269 __ InvokeBuiltin(Builtins::BIT_AND, CALL_FUNCTION); 270 break; 271 case Token::BIT_XOR: 272 __ InvokeBuiltin(Builtins::BIT_XOR, CALL_FUNCTION); 273 break; 274 case Token::SAR: 275 __ InvokeBuiltin(Builtins::SAR, CALL_FUNCTION); 276 break; 277 case Token::SHR: 278 __ InvokeBuiltin(Builtins::SHR, CALL_FUNCTION); 279 break; 280 case Token::SHL: 281 __ InvokeBuiltin(Builtins::SHL, CALL_FUNCTION); 282 break; 283 default: 284 UNREACHABLE(); 285 } 286 } 287 288 289 #undef __ 290 291 292 void BinaryOpStub::PrintName(StringStream* stream) { 293 const char* op_name = Token::Name(op_); 294 const char* overwrite_name; 295 switch (mode_) { 296 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 297 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 298 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 299 default: overwrite_name = "UnknownOverwrite"; break; 300 } 301 stream->Add("BinaryOpStub_%s_%s_%s+%s", 302 op_name, 303 overwrite_name, 304 BinaryOpIC::GetName(left_type_), 305 BinaryOpIC::GetName(right_type_)); 306 } 307 308 309 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 310 ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ == BinaryOpIC::STRING); 311 ASSERT(op_ == Token::ADD); 312 if (left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING) { 313 GenerateBothStringStub(masm); 314 return; 315 } 316 // Try to add arguments as strings, otherwise, transition to the generic 317 // BinaryOpIC type. 318 GenerateAddStrings(masm); 319 GenerateTypeTransition(masm); 320 } 321 322 323 InlineCacheState ICCompareStub::GetICState() { 324 CompareIC::State state = Max(left_, right_); 325 switch (state) { 326 case CompareIC::UNINITIALIZED: 327 return ::v8::internal::UNINITIALIZED; 328 case CompareIC::SMI: 329 case CompareIC::NUMBER: 330 case CompareIC::INTERNALIZED_STRING: 331 case CompareIC::STRING: 332 case CompareIC::UNIQUE_NAME: 333 case CompareIC::OBJECT: 334 case CompareIC::KNOWN_OBJECT: 335 return MONOMORPHIC; 336 case CompareIC::GENERIC: 337 return ::v8::internal::GENERIC; 338 } 339 UNREACHABLE(); 340 return ::v8::internal::UNINITIALIZED; 341 } 342 343 344 void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) { 345 ASSERT(*known_map_ != NULL); 346 Isolate* isolate = new_object->GetIsolate(); 347 Factory* factory = isolate->factory(); 348 return Map::UpdateCodeCache(known_map_, 349 strict() ? 350 factory->strict_compare_ic_string() : 351 factory->compare_ic_string(), 352 new_object); 353 } 354 355 356 bool ICCompareStub::FindCodeInSpecialCache(Code** code_out, Isolate* isolate) { 357 Factory* factory = isolate->factory(); 358 Code::Flags flags = Code::ComputeFlags( 359 GetCodeKind(), 360 UNINITIALIZED); 361 ASSERT(op_ == Token::EQ || op_ == Token::EQ_STRICT); 362 Handle<Object> probe( 363 known_map_->FindInCodeCache( 364 strict() ? 365 *factory->strict_compare_ic_string() : 366 *factory->compare_ic_string(), 367 flags), 368 isolate); 369 if (probe->IsCode()) { 370 *code_out = Code::cast(*probe); 371 #ifdef DEBUG 372 Token::Value cached_op; 373 ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL, 374 &cached_op); 375 ASSERT(op_ == cached_op); 376 #endif 377 return true; 378 } 379 return false; 380 } 381 382 383 int ICCompareStub::MinorKey() { 384 return OpField::encode(op_ - Token::EQ) | 385 LeftStateField::encode(left_) | 386 RightStateField::encode(right_) | 387 HandlerStateField::encode(state_); 388 } 389 390 391 void ICCompareStub::DecodeMinorKey(int minor_key, 392 CompareIC::State* left_state, 393 CompareIC::State* right_state, 394 CompareIC::State* handler_state, 395 Token::Value* op) { 396 if (left_state) { 397 *left_state = 398 static_cast<CompareIC::State>(LeftStateField::decode(minor_key)); 399 } 400 if (right_state) { 401 *right_state = 402 static_cast<CompareIC::State>(RightStateField::decode(minor_key)); 403 } 404 if (handler_state) { 405 *handler_state = 406 static_cast<CompareIC::State>(HandlerStateField::decode(minor_key)); 407 } 408 if (op) { 409 *op = static_cast<Token::Value>(OpField::decode(minor_key) + Token::EQ); 410 } 411 } 412 413 414 void ICCompareStub::Generate(MacroAssembler* masm) { 415 switch (state_) { 416 case CompareIC::UNINITIALIZED: 417 GenerateMiss(masm); 418 break; 419 case CompareIC::SMI: 420 GenerateSmis(masm); 421 break; 422 case CompareIC::NUMBER: 423 GenerateNumbers(masm); 424 break; 425 case CompareIC::STRING: 426 GenerateStrings(masm); 427 break; 428 case CompareIC::INTERNALIZED_STRING: 429 GenerateInternalizedStrings(masm); 430 break; 431 case CompareIC::UNIQUE_NAME: 432 GenerateUniqueNames(masm); 433 break; 434 case CompareIC::OBJECT: 435 GenerateObjects(masm); 436 break; 437 case CompareIC::KNOWN_OBJECT: 438 ASSERT(*known_map_ != NULL); 439 GenerateKnownObjects(masm); 440 break; 441 case CompareIC::GENERIC: 442 GenerateGeneric(masm); 443 break; 444 } 445 } 446 447 448 void CompareNilICStub::UpdateStatus(Handle<Object> object) { 449 ASSERT(!state_.Contains(GENERIC)); 450 State old_state(state_); 451 if (object->IsNull()) { 452 state_.Add(NULL_TYPE); 453 } else if (object->IsUndefined()) { 454 state_.Add(UNDEFINED); 455 } else if (object->IsUndetectableObject() || 456 object->IsOddball() || 457 !object->IsHeapObject()) { 458 state_.RemoveAll(); 459 state_.Add(GENERIC); 460 } else if (IsMonomorphic()) { 461 state_.RemoveAll(); 462 state_.Add(GENERIC); 463 } else { 464 state_.Add(MONOMORPHIC_MAP); 465 } 466 TraceTransition(old_state, state_); 467 } 468 469 470 template<class StateType> 471 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { 472 // Note: Although a no-op transition is semantically OK, it is hinting at a 473 // bug somewhere in our state transition machinery. 474 ASSERT(from != to); 475 #ifdef DEBUG 476 if (!FLAG_trace_ic) return; 477 char buffer[100]; 478 NoAllocationStringAllocator allocator(buffer, 479 static_cast<unsigned>(sizeof(buffer))); 480 StringStream stream(&allocator); 481 stream.Add("["); 482 PrintBaseName(&stream); 483 stream.Add(": "); 484 from.Print(&stream); 485 stream.Add("=>"); 486 to.Print(&stream); 487 stream.Add("]\n"); 488 stream.OutputToStdOut(); 489 #endif 490 } 491 492 493 void CompareNilICStub::PrintBaseName(StringStream* stream) { 494 CodeStub::PrintBaseName(stream); 495 stream->Add((nil_value_ == kNullValue) ? "(NullValue)": 496 "(UndefinedValue)"); 497 } 498 499 500 void CompareNilICStub::PrintState(StringStream* stream) { 501 state_.Print(stream); 502 } 503 504 505 void CompareNilICStub::State::Print(StringStream* stream) const { 506 stream->Add("("); 507 SimpleListPrinter printer(stream); 508 if (IsEmpty()) printer.Add("None"); 509 if (Contains(UNDEFINED)) printer.Add("Undefined"); 510 if (Contains(NULL_TYPE)) printer.Add("Null"); 511 if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap"); 512 if (Contains(GENERIC)) printer.Add("Generic"); 513 stream->Add(")"); 514 } 515 516 517 Handle<Type> CompareNilICStub::GetType( 518 Isolate* isolate, 519 Handle<Map> map) { 520 if (state_.Contains(CompareNilICStub::GENERIC)) { 521 return handle(Type::Any(), isolate); 522 } 523 524 Handle<Type> result(Type::None(), isolate); 525 if (state_.Contains(CompareNilICStub::UNDEFINED)) { 526 result = handle(Type::Union(result, handle(Type::Undefined(), isolate)), 527 isolate); 528 } 529 if (state_.Contains(CompareNilICStub::NULL_TYPE)) { 530 result = handle(Type::Union(result, handle(Type::Null(), isolate)), 531 isolate); 532 } 533 if (state_.Contains(CompareNilICStub::MONOMORPHIC_MAP)) { 534 Type* type = map.is_null() ? Type::Detectable() : Type::Class(map); 535 result = handle(Type::Union(result, handle(type, isolate)), isolate); 536 } 537 538 return result; 539 } 540 541 542 Handle<Type> CompareNilICStub::GetInputType( 543 Isolate* isolate, 544 Handle<Map> map) { 545 Handle<Type> output_type = GetType(isolate, map); 546 Handle<Type> nil_type = handle(nil_value_ == kNullValue 547 ? Type::Null() : Type::Undefined(), isolate); 548 return handle(Type::Union(output_type, nil_type), isolate); 549 } 550 551 552 void InstanceofStub::PrintName(StringStream* stream) { 553 const char* args = ""; 554 if (HasArgsInRegisters()) { 555 args = "_REGS"; 556 } 557 558 const char* inline_check = ""; 559 if (HasCallSiteInlineCheck()) { 560 inline_check = "_INLINE"; 561 } 562 563 const char* return_true_false_object = ""; 564 if (ReturnTrueFalseObject()) { 565 return_true_false_object = "_TRUEFALSE"; 566 } 567 568 stream->Add("InstanceofStub%s%s%s", 569 args, 570 inline_check, 571 return_true_false_object); 572 } 573 574 575 void JSEntryStub::FinishCode(Handle<Code> code) { 576 Handle<FixedArray> handler_table = 577 code->GetIsolate()->factory()->NewFixedArray(1, TENURED); 578 handler_table->set(0, Smi::FromInt(handler_offset_)); 579 code->set_handler_table(*handler_table); 580 } 581 582 583 void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) { 584 KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm); 585 } 586 587 588 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { 589 CreateAllocationSiteStub stub; 590 stub.GetCode(isolate)->set_is_pregenerated(true); 591 } 592 593 594 void KeyedStoreElementStub::Generate(MacroAssembler* masm) { 595 switch (elements_kind_) { 596 case FAST_ELEMENTS: 597 case FAST_HOLEY_ELEMENTS: 598 case FAST_SMI_ELEMENTS: 599 case FAST_HOLEY_SMI_ELEMENTS: { 600 KeyedStoreStubCompiler::GenerateStoreFastElement(masm, 601 is_js_array_, 602 elements_kind_, 603 store_mode_); 604 } 605 break; 606 case FAST_DOUBLE_ELEMENTS: 607 case FAST_HOLEY_DOUBLE_ELEMENTS: 608 KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm, 609 is_js_array_, 610 store_mode_); 611 break; 612 case EXTERNAL_BYTE_ELEMENTS: 613 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 614 case EXTERNAL_SHORT_ELEMENTS: 615 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 616 case EXTERNAL_INT_ELEMENTS: 617 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 618 case EXTERNAL_FLOAT_ELEMENTS: 619 case EXTERNAL_DOUBLE_ELEMENTS: 620 case EXTERNAL_PIXEL_ELEMENTS: 621 KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_); 622 break; 623 case DICTIONARY_ELEMENTS: 624 KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm); 625 break; 626 case NON_STRICT_ARGUMENTS_ELEMENTS: 627 UNREACHABLE(); 628 break; 629 } 630 } 631 632 633 void ArgumentsAccessStub::PrintName(StringStream* stream) { 634 stream->Add("ArgumentsAccessStub_"); 635 switch (type_) { 636 case READ_ELEMENT: stream->Add("ReadElement"); break; 637 case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break; 638 case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break; 639 case NEW_STRICT: stream->Add("NewStrict"); break; 640 } 641 } 642 643 644 void CallFunctionStub::PrintName(StringStream* stream) { 645 stream->Add("CallFunctionStub_Args%d", argc_); 646 if (ReceiverMightBeImplicit()) stream->Add("_Implicit"); 647 if (RecordCallTarget()) stream->Add("_Recording"); 648 } 649 650 651 void CallConstructStub::PrintName(StringStream* stream) { 652 stream->Add("CallConstructStub"); 653 if (RecordCallTarget()) stream->Add("_Recording"); 654 } 655 656 657 bool ToBooleanStub::UpdateStatus(Handle<Object> object) { 658 Types old_types(types_); 659 bool to_boolean_value = types_.UpdateStatus(object); 660 TraceTransition(old_types, types_); 661 return to_boolean_value; 662 } 663 664 665 void ToBooleanStub::PrintState(StringStream* stream) { 666 types_.Print(stream); 667 } 668 669 670 void ToBooleanStub::Types::Print(StringStream* stream) const { 671 stream->Add("("); 672 SimpleListPrinter printer(stream); 673 if (IsEmpty()) printer.Add("None"); 674 if (Contains(UNDEFINED)) printer.Add("Undefined"); 675 if (Contains(BOOLEAN)) printer.Add("Bool"); 676 if (Contains(NULL_TYPE)) printer.Add("Null"); 677 if (Contains(SMI)) printer.Add("Smi"); 678 if (Contains(SPEC_OBJECT)) printer.Add("SpecObject"); 679 if (Contains(STRING)) printer.Add("String"); 680 if (Contains(SYMBOL)) printer.Add("Symbol"); 681 if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber"); 682 stream->Add(")"); 683 } 684 685 686 bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) { 687 if (object->IsUndefined()) { 688 Add(UNDEFINED); 689 return false; 690 } else if (object->IsBoolean()) { 691 Add(BOOLEAN); 692 return object->IsTrue(); 693 } else if (object->IsNull()) { 694 Add(NULL_TYPE); 695 return false; 696 } else if (object->IsSmi()) { 697 Add(SMI); 698 return Smi::cast(*object)->value() != 0; 699 } else if (object->IsSpecObject()) { 700 Add(SPEC_OBJECT); 701 return !object->IsUndetectableObject(); 702 } else if (object->IsString()) { 703 Add(STRING); 704 return !object->IsUndetectableObject() && 705 String::cast(*object)->length() != 0; 706 } else if (object->IsSymbol()) { 707 Add(SYMBOL); 708 return true; 709 } else if (object->IsHeapNumber()) { 710 ASSERT(!object->IsUndetectableObject()); 711 Add(HEAP_NUMBER); 712 double value = HeapNumber::cast(*object)->value(); 713 return value != 0 && !std::isnan(value); 714 } else { 715 // We should never see an internal object at runtime here! 716 UNREACHABLE(); 717 return true; 718 } 719 } 720 721 722 bool ToBooleanStub::Types::NeedsMap() const { 723 return Contains(ToBooleanStub::SPEC_OBJECT) 724 || Contains(ToBooleanStub::STRING) 725 || Contains(ToBooleanStub::SYMBOL) 726 || Contains(ToBooleanStub::HEAP_NUMBER); 727 } 728 729 730 bool ToBooleanStub::Types::CanBeUndetectable() const { 731 return Contains(ToBooleanStub::SPEC_OBJECT) 732 || Contains(ToBooleanStub::STRING); 733 } 734 735 736 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) { 737 StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE); 738 StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE); 739 stub1.GetCode(isolate)->set_is_pregenerated(true); 740 stub2.GetCode(isolate)->set_is_pregenerated(true); 741 } 742 743 744 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function, 745 intptr_t stack_pointer) { 746 FunctionEntryHook entry_hook = Isolate::Current()->function_entry_hook(); 747 ASSERT(entry_hook != NULL); 748 entry_hook(function, stack_pointer); 749 } 750 751 752 static void InstallDescriptor(Isolate* isolate, HydrogenCodeStub* stub) { 753 int major_key = stub->MajorKey(); 754 CodeStubInterfaceDescriptor* descriptor = 755 isolate->code_stub_interface_descriptor(major_key); 756 if (!descriptor->initialized()) { 757 stub->InitializeInterfaceDescriptor(isolate, descriptor); 758 } 759 } 760 761 762 void ArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) { 763 ArrayNoArgumentConstructorStub stub1(GetInitialFastElementsKind()); 764 InstallDescriptor(isolate, &stub1); 765 ArraySingleArgumentConstructorStub stub2(GetInitialFastElementsKind()); 766 InstallDescriptor(isolate, &stub2); 767 ArrayNArgumentsConstructorStub stub3(GetInitialFastElementsKind()); 768 InstallDescriptor(isolate, &stub3); 769 } 770 771 772 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) 773 : argument_count_(ANY) { 774 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 775 } 776 777 778 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate, 779 int argument_count) { 780 if (argument_count == 0) { 781 argument_count_ = NONE; 782 } else if (argument_count == 1) { 783 argument_count_ = ONE; 784 } else if (argument_count >= 2) { 785 argument_count_ = MORE_THAN_ONE; 786 } else { 787 UNREACHABLE(); 788 } 789 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 790 } 791 792 793 void InternalArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) { 794 InternalArrayNoArgumentConstructorStub stub1(FAST_ELEMENTS); 795 InstallDescriptor(isolate, &stub1); 796 InternalArraySingleArgumentConstructorStub stub2(FAST_ELEMENTS); 797 InstallDescriptor(isolate, &stub2); 798 InternalArrayNArgumentsConstructorStub stub3(FAST_ELEMENTS); 799 InstallDescriptor(isolate, &stub3); 800 } 801 802 InternalArrayConstructorStub::InternalArrayConstructorStub( 803 Isolate* isolate) { 804 InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); 805 } 806 807 808 } } // namespace v8::internal 809