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 #ifndef V8_CODE_STUBS_H_ 29 #define V8_CODE_STUBS_H_ 30 31 #include "allocation.h" 32 #include "assembler.h" 33 #include "globals.h" 34 #include "codegen.h" 35 36 namespace v8 { 37 namespace internal { 38 39 // List of code stubs used on all platforms. 40 #define CODE_STUB_LIST_ALL_PLATFORMS(V) \ 41 V(CallFunction) \ 42 V(CallConstruct) \ 43 V(BinaryOp) \ 44 V(StringAdd) \ 45 V(SubString) \ 46 V(StringCompare) \ 47 V(Compare) \ 48 V(CompareIC) \ 49 V(CompareNilIC) \ 50 V(MathPow) \ 51 V(StringLength) \ 52 V(FunctionPrototype) \ 53 V(StoreArrayLength) \ 54 V(RecordWrite) \ 55 V(StoreBufferOverflow) \ 56 V(RegExpExec) \ 57 V(TranscendentalCache) \ 58 V(Instanceof) \ 59 V(ConvertToDouble) \ 60 V(WriteInt32ToHeapNumber) \ 61 V(StackCheck) \ 62 V(Interrupt) \ 63 V(FastNewClosure) \ 64 V(FastNewContext) \ 65 V(FastNewBlockContext) \ 66 V(FastCloneShallowArray) \ 67 V(FastCloneShallowObject) \ 68 V(CreateAllocationSite) \ 69 V(ToBoolean) \ 70 V(ToNumber) \ 71 V(ArgumentsAccess) \ 72 V(RegExpConstructResult) \ 73 V(NumberToString) \ 74 V(DoubleToI) \ 75 V(CEntry) \ 76 V(JSEntry) \ 77 V(KeyedLoadElement) \ 78 V(ArrayNoArgumentConstructor) \ 79 V(ArraySingleArgumentConstructor) \ 80 V(ArrayNArgumentsConstructor) \ 81 V(InternalArrayNoArgumentConstructor) \ 82 V(InternalArraySingleArgumentConstructor) \ 83 V(InternalArrayNArgumentsConstructor) \ 84 V(KeyedStoreElement) \ 85 V(DebuggerStatement) \ 86 V(NameDictionaryLookup) \ 87 V(ElementsTransitionAndStore) \ 88 V(TransitionElementsKind) \ 89 V(StoreArrayLiteralElement) \ 90 V(StubFailureTrampoline) \ 91 V(ArrayConstructor) \ 92 V(InternalArrayConstructor) \ 93 V(ProfileEntryHook) \ 94 V(StoreGlobal) \ 95 /* IC Handler stubs */ \ 96 V(LoadField) \ 97 V(KeyedLoadField) 98 99 // List of code stubs only used on ARM platforms. 100 #if V8_TARGET_ARCH_ARM 101 #define CODE_STUB_LIST_ARM(V) \ 102 V(GetProperty) \ 103 V(SetProperty) \ 104 V(InvokeBuiltin) \ 105 V(RegExpCEntry) \ 106 V(DirectCEntry) 107 #else 108 #define CODE_STUB_LIST_ARM(V) 109 #endif 110 111 // List of code stubs only used on MIPS platforms. 112 #if V8_TARGET_ARCH_MIPS 113 #define CODE_STUB_LIST_MIPS(V) \ 114 V(RegExpCEntry) \ 115 V(DirectCEntry) 116 #else 117 #define CODE_STUB_LIST_MIPS(V) 118 #endif 119 120 // Combined list of code stubs. 121 #define CODE_STUB_LIST(V) \ 122 CODE_STUB_LIST_ALL_PLATFORMS(V) \ 123 CODE_STUB_LIST_ARM(V) \ 124 CODE_STUB_LIST_MIPS(V) 125 126 // Mode to overwrite BinaryExpression values. 127 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; 128 129 // Stub is base classes of all stubs. 130 class CodeStub BASE_EMBEDDED { 131 public: 132 enum Major { 133 #define DEF_ENUM(name) name, 134 CODE_STUB_LIST(DEF_ENUM) 135 #undef DEF_ENUM 136 NoCache, // marker for stubs that do custom caching 137 NUMBER_OF_IDS 138 }; 139 140 // Retrieve the code for the stub. Generate the code if needed. 141 Handle<Code> GetCode(Isolate* isolate); 142 143 // Retrieve the code for the stub, make and return a copy of the code. 144 Handle<Code> GetCodeCopyFromTemplate(Isolate* isolate); 145 static Major MajorKeyFromKey(uint32_t key) { 146 return static_cast<Major>(MajorKeyBits::decode(key)); 147 } 148 static int MinorKeyFromKey(uint32_t key) { 149 return MinorKeyBits::decode(key); 150 } 151 152 // Gets the major key from a code object that is a code stub or binary op IC. 153 static Major GetMajorKey(Code* code_stub) { 154 return static_cast<Major>(code_stub->major_key()); 155 } 156 157 static const char* MajorName(Major major_key, bool allow_unknown_keys); 158 159 virtual ~CodeStub() {} 160 161 bool CompilingCallsToThisStubIsGCSafe(Isolate* isolate) { 162 bool is_pregenerated = IsPregenerated(); 163 Code* code = NULL; 164 CHECK(!is_pregenerated || FindCodeInCache(&code, isolate)); 165 return is_pregenerated; 166 } 167 168 // See comment above, where Instanceof is defined. 169 virtual bool IsPregenerated() { return false; } 170 171 static void GenerateStubsAheadOfTime(Isolate* isolate); 172 static void GenerateFPStubs(Isolate* isolate); 173 174 // Some stubs put untagged junk on the stack that cannot be scanned by the 175 // GC. This means that we must be statically sure that no GC can occur while 176 // they are running. If that is the case they should override this to return 177 // true, which will cause an assertion if we try to call something that can 178 // GC or if we try to put a stack frame on top of the junk, which would not 179 // result in a traversable stack. 180 virtual bool SometimesSetsUpAFrame() { return true; } 181 182 // Lookup the code in the (possibly custom) cache. 183 bool FindCodeInCache(Code** code_out, Isolate* isolate); 184 185 // Returns information for computing the number key. 186 virtual Major MajorKey() = 0; 187 virtual int MinorKey() = 0; 188 189 virtual InlineCacheState GetICState() { 190 return UNINITIALIZED; 191 } 192 virtual Code::ExtraICState GetExtraICState() { 193 return Code::kNoExtraICState; 194 } 195 virtual Code::StubType GetStubType() { 196 return Code::NORMAL; 197 } 198 virtual int GetStubFlags() { 199 return -1; 200 } 201 202 virtual void PrintName(StringStream* stream); 203 204 protected: 205 static bool CanUseFPRegisters(); 206 207 // Generates the assembler code for the stub. 208 virtual Handle<Code> GenerateCode() = 0; 209 210 211 // Returns whether the code generated for this stub needs to be allocated as 212 // a fixed (non-moveable) code object. 213 virtual bool NeedsImmovableCode() { return false; } 214 215 // Returns a name for logging/debugging purposes. 216 SmartArrayPointer<const char> GetName(); 217 virtual void PrintBaseName(StringStream* stream); 218 virtual void PrintState(StringStream* stream) { } 219 220 private: 221 // Perform bookkeeping required after code generation when stub code is 222 // initially generated. 223 void RecordCodeGeneration(Code* code, Isolate* isolate); 224 225 // Finish the code object after it has been generated. 226 virtual void FinishCode(Handle<Code> code) { } 227 228 // Activate newly generated stub. Is called after 229 // registering stub in the stub cache. 230 virtual void Activate(Code* code) { } 231 232 // BinaryOpStub needs to override this. 233 virtual Code::Kind GetCodeKind() const; 234 235 // Add the code to a specialized cache, specific to an individual 236 // stub type. Please note, this method must add the code object to a 237 // roots object, otherwise we will remove the code during GC. 238 virtual void AddToSpecialCache(Handle<Code> new_object) { } 239 240 // Find code in a specialized cache, work is delegated to the specific stub. 241 virtual bool FindCodeInSpecialCache(Code** code_out, Isolate* isolate) { 242 return false; 243 } 244 245 // If a stub uses a special cache override this. 246 virtual bool UseSpecialCache() { return false; } 247 248 // Computes the key based on major and minor. 249 uint32_t GetKey() { 250 ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS); 251 return MinorKeyBits::encode(MinorKey()) | 252 MajorKeyBits::encode(MajorKey()); 253 } 254 255 class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {}; 256 class MinorKeyBits: public BitField<uint32_t, 257 kStubMajorKeyBits, kStubMinorKeyBits> {}; // NOLINT 258 259 friend class BreakPointIterator; 260 }; 261 262 263 class PlatformCodeStub : public CodeStub { 264 public: 265 // Retrieve the code for the stub. Generate the code if needed. 266 virtual Handle<Code> GenerateCode(); 267 268 virtual Code::Kind GetCodeKind() const { return Code::STUB; } 269 270 protected: 271 // Generates the assembler code for the stub. 272 virtual void Generate(MacroAssembler* masm) = 0; 273 }; 274 275 276 enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE }; 277 278 279 struct CodeStubInterfaceDescriptor { 280 CodeStubInterfaceDescriptor(); 281 int register_param_count_; 282 const Register* stack_parameter_count_; 283 // if hint_stack_parameter_count_ > 0, the code stub can optimize the 284 // return sequence. Default value is -1, which means it is ignored. 285 int hint_stack_parameter_count_; 286 StubFunctionMode function_mode_; 287 Register* register_params_; 288 Address deoptimization_handler_; 289 290 int environment_length() const { 291 if (stack_parameter_count_ != NULL) { 292 return register_param_count_ + 1; 293 } 294 return register_param_count_; 295 } 296 297 bool initialized() const { return register_param_count_ >= 0; } 298 299 void SetMissHandler(ExternalReference handler) { 300 miss_handler_ = handler; 301 has_miss_handler_ = true; 302 } 303 304 ExternalReference miss_handler() { 305 ASSERT(has_miss_handler_); 306 return miss_handler_; 307 } 308 309 bool has_miss_handler() { 310 return has_miss_handler_; 311 } 312 313 private: 314 ExternalReference miss_handler_; 315 bool has_miss_handler_; 316 }; 317 318 // A helper to make up for the fact that type Register is not fully 319 // defined outside of the platform directories 320 #define DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index) \ 321 ((index) == (descriptor)->register_param_count_) \ 322 ? *((descriptor)->stack_parameter_count_) \ 323 : (descriptor)->register_params_[(index)] 324 325 326 class HydrogenCodeStub : public CodeStub { 327 public: 328 enum InitializationState { 329 UNINITIALIZED, 330 INITIALIZED 331 }; 332 333 explicit HydrogenCodeStub(InitializationState state = INITIALIZED) { 334 is_uninitialized_ = (state == UNINITIALIZED); 335 } 336 337 virtual Code::Kind GetCodeKind() const { return Code::STUB; } 338 339 CodeStubInterfaceDescriptor* GetInterfaceDescriptor(Isolate* isolate) { 340 return isolate->code_stub_interface_descriptor(MajorKey()); 341 } 342 343 bool IsUninitialized() { return is_uninitialized_; } 344 345 template<class SubClass> 346 static Handle<Code> GetUninitialized(Isolate* isolate) { 347 SubClass::GenerateAheadOfTime(isolate); 348 return SubClass().GetCode(isolate); 349 } 350 351 virtual void InitializeInterfaceDescriptor( 352 Isolate* isolate, 353 CodeStubInterfaceDescriptor* descriptor) = 0; 354 355 // Retrieve the code for the stub. Generate the code if needed. 356 virtual Handle<Code> GenerateCode() = 0; 357 358 virtual int NotMissMinorKey() = 0; 359 360 Handle<Code> GenerateLightweightMissCode(Isolate* isolate); 361 362 template<class StateType> 363 void TraceTransition(StateType from, StateType to); 364 365 private: 366 class MinorKeyBits: public BitField<int, 0, kStubMinorKeyBits - 1> {}; 367 class IsMissBits: public BitField<bool, kStubMinorKeyBits - 1, 1> {}; 368 369 void GenerateLightweightMiss(MacroAssembler* masm); 370 virtual int MinorKey() { 371 return IsMissBits::encode(is_uninitialized_) | 372 MinorKeyBits::encode(NotMissMinorKey()); 373 } 374 375 bool is_uninitialized_; 376 }; 377 378 379 // Helper interface to prepare to/restore after making runtime calls. 380 class RuntimeCallHelper { 381 public: 382 virtual ~RuntimeCallHelper() {} 383 384 virtual void BeforeCall(MacroAssembler* masm) const = 0; 385 386 virtual void AfterCall(MacroAssembler* masm) const = 0; 387 388 protected: 389 RuntimeCallHelper() {} 390 391 private: 392 DISALLOW_COPY_AND_ASSIGN(RuntimeCallHelper); 393 }; 394 395 396 // TODO(bmeurer): Move to the StringAddStub declaration once we're 397 // done with the translation to a hydrogen code stub. 398 enum StringAddFlags { 399 // Omit both parameter checks. 400 STRING_ADD_CHECK_NONE = 0, 401 // Check left parameter. 402 STRING_ADD_CHECK_LEFT = 1 << 0, 403 // Check right parameter. 404 STRING_ADD_CHECK_RIGHT = 1 << 1, 405 // Check both parameters. 406 STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT, 407 // Stub needs a frame before calling the runtime 408 STRING_ADD_ERECT_FRAME = 1 << 2 409 }; 410 411 } } // namespace v8::internal 412 413 #if V8_TARGET_ARCH_IA32 414 #include "ia32/code-stubs-ia32.h" 415 #elif V8_TARGET_ARCH_X64 416 #include "x64/code-stubs-x64.h" 417 #elif V8_TARGET_ARCH_ARM 418 #include "arm/code-stubs-arm.h" 419 #elif V8_TARGET_ARCH_MIPS 420 #include "mips/code-stubs-mips.h" 421 #else 422 #error Unsupported target architecture. 423 #endif 424 425 namespace v8 { 426 namespace internal { 427 428 429 // RuntimeCallHelper implementation used in stubs: enters/leaves a 430 // newly created internal frame before/after the runtime call. 431 class StubRuntimeCallHelper : public RuntimeCallHelper { 432 public: 433 StubRuntimeCallHelper() {} 434 435 virtual void BeforeCall(MacroAssembler* masm) const; 436 437 virtual void AfterCall(MacroAssembler* masm) const; 438 }; 439 440 441 // Trivial RuntimeCallHelper implementation. 442 class NopRuntimeCallHelper : public RuntimeCallHelper { 443 public: 444 NopRuntimeCallHelper() {} 445 446 virtual void BeforeCall(MacroAssembler* masm) const {} 447 448 virtual void AfterCall(MacroAssembler* masm) const {} 449 }; 450 451 452 class StackCheckStub : public PlatformCodeStub { 453 public: 454 StackCheckStub() { } 455 456 void Generate(MacroAssembler* masm); 457 458 private: 459 Major MajorKey() { return StackCheck; } 460 int MinorKey() { return 0; } 461 }; 462 463 464 class InterruptStub : public PlatformCodeStub { 465 public: 466 InterruptStub() { } 467 468 void Generate(MacroAssembler* masm); 469 470 private: 471 Major MajorKey() { return Interrupt; } 472 int MinorKey() { return 0; } 473 }; 474 475 476 class ToNumberStub: public HydrogenCodeStub { 477 public: 478 ToNumberStub() { } 479 480 virtual Handle<Code> GenerateCode(); 481 482 virtual void InitializeInterfaceDescriptor( 483 Isolate* isolate, 484 CodeStubInterfaceDescriptor* descriptor); 485 486 private: 487 Major MajorKey() { return ToNumber; } 488 int NotMissMinorKey() { return 0; } 489 }; 490 491 492 class FastNewClosureStub : public PlatformCodeStub { 493 public: 494 explicit FastNewClosureStub(LanguageMode language_mode, bool is_generator) 495 : language_mode_(language_mode), 496 is_generator_(is_generator) { } 497 498 void Generate(MacroAssembler* masm); 499 500 private: 501 class StrictModeBits: public BitField<bool, 0, 1> {}; 502 class IsGeneratorBits: public BitField<bool, 1, 1> {}; 503 504 Major MajorKey() { return FastNewClosure; } 505 int MinorKey() { 506 return StrictModeBits::encode(language_mode_ != CLASSIC_MODE) | 507 IsGeneratorBits::encode(is_generator_); 508 } 509 510 LanguageMode language_mode_; 511 bool is_generator_; 512 }; 513 514 515 class FastNewContextStub : public PlatformCodeStub { 516 public: 517 static const int kMaximumSlots = 64; 518 519 explicit FastNewContextStub(int slots) : slots_(slots) { 520 ASSERT(slots_ > 0 && slots_ <= kMaximumSlots); 521 } 522 523 void Generate(MacroAssembler* masm); 524 525 private: 526 int slots_; 527 528 Major MajorKey() { return FastNewContext; } 529 int MinorKey() { return slots_; } 530 }; 531 532 533 class FastNewBlockContextStub : public PlatformCodeStub { 534 public: 535 static const int kMaximumSlots = 64; 536 537 explicit FastNewBlockContextStub(int slots) : slots_(slots) { 538 ASSERT(slots_ > 0 && slots_ <= kMaximumSlots); 539 } 540 541 void Generate(MacroAssembler* masm); 542 543 private: 544 int slots_; 545 546 Major MajorKey() { return FastNewBlockContext; } 547 int MinorKey() { return slots_; } 548 }; 549 550 class StoreGlobalStub : public HydrogenCodeStub { 551 public: 552 StoreGlobalStub(StrictModeFlag strict_mode, bool is_constant) { 553 bit_field_ = StrictModeBits::encode(strict_mode) | 554 IsConstantBits::encode(is_constant); 555 } 556 557 virtual Handle<Code> GenerateCode(); 558 559 virtual void InitializeInterfaceDescriptor( 560 Isolate* isolate, 561 CodeStubInterfaceDescriptor* descriptor); 562 563 virtual Code::Kind GetCodeKind() const { return Code::STORE_IC; } 564 virtual InlineCacheState GetICState() { return MONOMORPHIC; } 565 virtual Code::ExtraICState GetExtraICState() { return bit_field_; } 566 567 bool is_constant() { 568 return IsConstantBits::decode(bit_field_); 569 } 570 void set_is_constant(bool value) { 571 bit_field_ = IsConstantBits::update(bit_field_, value); 572 } 573 574 Representation representation() { 575 return Representation::FromKind(RepresentationBits::decode(bit_field_)); 576 } 577 void set_representation(Representation r) { 578 bit_field_ = RepresentationBits::update(bit_field_, r.kind()); 579 } 580 581 private: 582 virtual int NotMissMinorKey() { return GetExtraICState(); } 583 Major MajorKey() { return StoreGlobal; } 584 585 class StrictModeBits: public BitField<StrictModeFlag, 0, 1> {}; 586 class IsConstantBits: public BitField<bool, 1, 1> {}; 587 class RepresentationBits: public BitField<Representation::Kind, 2, 8> {}; 588 589 int bit_field_; 590 591 DISALLOW_COPY_AND_ASSIGN(StoreGlobalStub); 592 }; 593 594 595 class FastCloneShallowArrayStub : public HydrogenCodeStub { 596 public: 597 // Maximum length of copied elements array. 598 static const int kMaximumClonedLength = 8; 599 enum Mode { 600 CLONE_ELEMENTS, 601 CLONE_DOUBLE_ELEMENTS, 602 COPY_ON_WRITE_ELEMENTS, 603 CLONE_ANY_ELEMENTS, 604 LAST_CLONE_MODE = CLONE_ANY_ELEMENTS 605 }; 606 607 static const int kFastCloneModeCount = LAST_CLONE_MODE + 1; 608 609 FastCloneShallowArrayStub(Mode mode, 610 AllocationSiteMode allocation_site_mode, 611 int length) 612 : mode_(mode), 613 allocation_site_mode_(allocation_site_mode), 614 length_((mode == COPY_ON_WRITE_ELEMENTS) ? 0 : length) { 615 ASSERT_GE(length_, 0); 616 ASSERT_LE(length_, kMaximumClonedLength); 617 } 618 619 Mode mode() const { return mode_; } 620 int length() const { return length_; } 621 AllocationSiteMode allocation_site_mode() const { 622 return allocation_site_mode_; 623 } 624 625 ElementsKind ComputeElementsKind() const { 626 switch (mode()) { 627 case CLONE_ELEMENTS: 628 case COPY_ON_WRITE_ELEMENTS: 629 return FAST_ELEMENTS; 630 case CLONE_DOUBLE_ELEMENTS: 631 return FAST_DOUBLE_ELEMENTS; 632 case CLONE_ANY_ELEMENTS: 633 /*fall-through*/; 634 } 635 UNREACHABLE(); 636 return LAST_ELEMENTS_KIND; 637 } 638 639 virtual Handle<Code> GenerateCode(); 640 641 virtual void InitializeInterfaceDescriptor( 642 Isolate* isolate, 643 CodeStubInterfaceDescriptor* descriptor); 644 645 private: 646 Mode mode_; 647 AllocationSiteMode allocation_site_mode_; 648 int length_; 649 650 class AllocationSiteModeBits: public BitField<AllocationSiteMode, 0, 1> {}; 651 class ModeBits: public BitField<Mode, 1, 4> {}; 652 class LengthBits: public BitField<int, 5, 4> {}; 653 // Ensure data fits within available bits. 654 STATIC_ASSERT(LAST_ALLOCATION_SITE_MODE == 1); 655 STATIC_ASSERT(kFastCloneModeCount < 16); 656 STATIC_ASSERT(kMaximumClonedLength < 16); 657 Major MajorKey() { return FastCloneShallowArray; } 658 int NotMissMinorKey() { 659 return AllocationSiteModeBits::encode(allocation_site_mode_) 660 | ModeBits::encode(mode_) 661 | LengthBits::encode(length_); 662 } 663 }; 664 665 666 class FastCloneShallowObjectStub : public HydrogenCodeStub { 667 public: 668 // Maximum number of properties in copied object. 669 static const int kMaximumClonedProperties = 6; 670 671 explicit FastCloneShallowObjectStub(int length) 672 : length_(length) { 673 ASSERT_GE(length_, 0); 674 ASSERT_LE(length_, kMaximumClonedProperties); 675 } 676 677 int length() const { return length_; } 678 679 virtual Handle<Code> GenerateCode(); 680 681 virtual void InitializeInterfaceDescriptor( 682 Isolate* isolate, 683 CodeStubInterfaceDescriptor* descriptor); 684 685 private: 686 int length_; 687 688 Major MajorKey() { return FastCloneShallowObject; } 689 int NotMissMinorKey() { return length_; } 690 691 DISALLOW_COPY_AND_ASSIGN(FastCloneShallowObjectStub); 692 }; 693 694 695 class CreateAllocationSiteStub : public HydrogenCodeStub { 696 public: 697 explicit CreateAllocationSiteStub() { } 698 699 virtual Handle<Code> GenerateCode(); 700 701 virtual bool IsPregenerated() { return true; } 702 703 static void GenerateAheadOfTime(Isolate* isolate); 704 705 virtual void InitializeInterfaceDescriptor( 706 Isolate* isolate, 707 CodeStubInterfaceDescriptor* descriptor); 708 709 private: 710 Major MajorKey() { return CreateAllocationSite; } 711 int NotMissMinorKey() { return 0; } 712 713 DISALLOW_COPY_AND_ASSIGN(CreateAllocationSiteStub); 714 }; 715 716 717 class InstanceofStub: public PlatformCodeStub { 718 public: 719 enum Flags { 720 kNoFlags = 0, 721 kArgsInRegisters = 1 << 0, 722 kCallSiteInlineCheck = 1 << 1, 723 kReturnTrueFalseObject = 1 << 2 724 }; 725 726 explicit InstanceofStub(Flags flags) : flags_(flags) { } 727 728 static Register left(); 729 static Register right(); 730 731 void Generate(MacroAssembler* masm); 732 733 private: 734 Major MajorKey() { return Instanceof; } 735 int MinorKey() { return static_cast<int>(flags_); } 736 737 bool HasArgsInRegisters() const { 738 return (flags_ & kArgsInRegisters) != 0; 739 } 740 741 bool HasCallSiteInlineCheck() const { 742 return (flags_ & kCallSiteInlineCheck) != 0; 743 } 744 745 bool ReturnTrueFalseObject() const { 746 return (flags_ & kReturnTrueFalseObject) != 0; 747 } 748 749 virtual void PrintName(StringStream* stream); 750 751 Flags flags_; 752 }; 753 754 755 class ArrayConstructorStub: public PlatformCodeStub { 756 public: 757 enum ArgumentCountKey { ANY, NONE, ONE, MORE_THAN_ONE }; 758 ArrayConstructorStub(Isolate* isolate, int argument_count); 759 explicit ArrayConstructorStub(Isolate* isolate); 760 761 void Generate(MacroAssembler* masm); 762 763 private: 764 virtual CodeStub::Major MajorKey() { return ArrayConstructor; } 765 virtual int MinorKey() { return argument_count_; } 766 767 ArgumentCountKey argument_count_; 768 }; 769 770 771 class InternalArrayConstructorStub: public PlatformCodeStub { 772 public: 773 explicit InternalArrayConstructorStub(Isolate* isolate); 774 775 void Generate(MacroAssembler* masm); 776 777 private: 778 virtual CodeStub::Major MajorKey() { return InternalArrayConstructor; } 779 virtual int MinorKey() { return 0; } 780 781 void GenerateCase(MacroAssembler* masm, ElementsKind kind); 782 }; 783 784 785 class MathPowStub: public PlatformCodeStub { 786 public: 787 enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK }; 788 789 explicit MathPowStub(ExponentType exponent_type) 790 : exponent_type_(exponent_type) { } 791 virtual void Generate(MacroAssembler* masm); 792 793 private: 794 virtual CodeStub::Major MajorKey() { return MathPow; } 795 virtual int MinorKey() { return exponent_type_; } 796 797 ExponentType exponent_type_; 798 }; 799 800 801 class ICStub: public PlatformCodeStub { 802 public: 803 explicit ICStub(Code::Kind kind) : kind_(kind) { } 804 virtual Code::Kind GetCodeKind() const { return kind_; } 805 virtual InlineCacheState GetICState() { return MONOMORPHIC; } 806 807 bool Describes(Code* code) { 808 return GetMajorKey(code) == MajorKey() && code->stub_info() == MinorKey(); 809 } 810 811 protected: 812 class KindBits: public BitField<Code::Kind, 0, 4> {}; 813 virtual void FinishCode(Handle<Code> code) { 814 code->set_stub_info(MinorKey()); 815 } 816 Code::Kind kind() { return kind_; } 817 818 virtual int MinorKey() { 819 return KindBits::encode(kind_); 820 } 821 822 private: 823 Code::Kind kind_; 824 }; 825 826 827 class FunctionPrototypeStub: public ICStub { 828 public: 829 explicit FunctionPrototypeStub(Code::Kind kind) : ICStub(kind) { } 830 virtual void Generate(MacroAssembler* masm); 831 832 private: 833 virtual CodeStub::Major MajorKey() { return FunctionPrototype; } 834 }; 835 836 837 class StringLengthStub: public ICStub { 838 public: 839 StringLengthStub(Code::Kind kind, bool support_wrapper) 840 : ICStub(kind), support_wrapper_(support_wrapper) { } 841 virtual void Generate(MacroAssembler* masm); 842 843 private: 844 STATIC_ASSERT(KindBits::kSize == 4); 845 class WrapperModeBits: public BitField<bool, 4, 1> {}; 846 virtual CodeStub::Major MajorKey() { return StringLength; } 847 virtual int MinorKey() { 848 return KindBits::encode(kind()) | WrapperModeBits::encode(support_wrapper_); 849 } 850 851 bool support_wrapper_; 852 }; 853 854 855 class StoreICStub: public ICStub { 856 public: 857 StoreICStub(Code::Kind kind, StrictModeFlag strict_mode) 858 : ICStub(kind), strict_mode_(strict_mode) { } 859 860 protected: 861 virtual Code::ExtraICState GetExtraICState() { 862 return strict_mode_; 863 } 864 865 private: 866 STATIC_ASSERT(KindBits::kSize == 4); 867 class StrictModeBits: public BitField<bool, 4, 1> {}; 868 virtual int MinorKey() { 869 return KindBits::encode(kind()) | StrictModeBits::encode(strict_mode_); 870 } 871 872 StrictModeFlag strict_mode_; 873 }; 874 875 876 class StoreArrayLengthStub: public StoreICStub { 877 public: 878 explicit StoreArrayLengthStub(Code::Kind kind, StrictModeFlag strict_mode) 879 : StoreICStub(kind, strict_mode) { } 880 virtual void Generate(MacroAssembler* masm); 881 882 private: 883 virtual CodeStub::Major MajorKey() { return StoreArrayLength; } 884 }; 885 886 887 class HICStub: public HydrogenCodeStub { 888 public: 889 virtual Code::Kind GetCodeKind() const { return kind(); } 890 virtual InlineCacheState GetICState() { return MONOMORPHIC; } 891 892 protected: 893 HICStub() { } 894 class KindBits: public BitField<Code::Kind, 0, 4> {}; 895 virtual Code::Kind kind() const = 0; 896 }; 897 898 899 class HandlerStub: public HICStub { 900 public: 901 virtual Code::Kind GetCodeKind() const { return Code::STUB; } 902 virtual int GetStubFlags() { return kind(); } 903 904 protected: 905 HandlerStub() : HICStub() { } 906 }; 907 908 909 class LoadFieldStub: public HandlerStub { 910 public: 911 LoadFieldStub(bool inobject, int index, Representation representation) 912 : HandlerStub() { 913 Initialize(Code::LOAD_IC, inobject, index, representation); 914 } 915 916 virtual Handle<Code> GenerateCode(); 917 918 virtual void InitializeInterfaceDescriptor( 919 Isolate* isolate, 920 CodeStubInterfaceDescriptor* descriptor); 921 922 Representation representation() { 923 if (unboxed_double()) return Representation::Double(); 924 return Representation::Tagged(); 925 } 926 927 virtual Code::Kind kind() const { 928 return KindBits::decode(bit_field_); 929 } 930 931 bool is_inobject() { 932 return InobjectBits::decode(bit_field_); 933 } 934 935 int offset() { 936 int index = IndexBits::decode(bit_field_); 937 int offset = index * kPointerSize; 938 if (is_inobject()) return offset; 939 return FixedArray::kHeaderSize + offset; 940 } 941 942 bool unboxed_double() { 943 return UnboxedDoubleBits::decode(bit_field_); 944 } 945 946 virtual Code::StubType GetStubType() { return Code::FIELD; } 947 948 protected: 949 LoadFieldStub() : HandlerStub() { } 950 951 void Initialize(Code::Kind kind, 952 bool inobject, 953 int index, 954 Representation representation) { 955 bool unboxed_double = FLAG_track_double_fields && representation.IsDouble(); 956 bit_field_ = KindBits::encode(kind) 957 | InobjectBits::encode(inobject) 958 | IndexBits::encode(index) 959 | UnboxedDoubleBits::encode(unboxed_double); 960 } 961 962 private: 963 STATIC_ASSERT(KindBits::kSize == 4); 964 class InobjectBits: public BitField<bool, 4, 1> {}; 965 class IndexBits: public BitField<int, 5, 11> {}; 966 class UnboxedDoubleBits: public BitField<bool, 16, 1> {}; 967 virtual CodeStub::Major MajorKey() { return LoadField; } 968 virtual int NotMissMinorKey() { return bit_field_; } 969 970 int bit_field_; 971 }; 972 973 974 class KeyedLoadFieldStub: public LoadFieldStub { 975 public: 976 KeyedLoadFieldStub(bool inobject, int index, Representation representation) 977 : LoadFieldStub() { 978 Initialize(Code::KEYED_LOAD_IC, inobject, index, representation); 979 } 980 981 virtual void InitializeInterfaceDescriptor( 982 Isolate* isolate, 983 CodeStubInterfaceDescriptor* descriptor); 984 985 virtual Handle<Code> GenerateCode(); 986 987 private: 988 virtual CodeStub::Major MajorKey() { return KeyedLoadField; } 989 }; 990 991 992 class BinaryOpStub: public PlatformCodeStub { 993 public: 994 BinaryOpStub(Token::Value op, OverwriteMode mode) 995 : op_(op), 996 mode_(mode), 997 platform_specific_bit_(false), 998 left_type_(BinaryOpIC::UNINITIALIZED), 999 right_type_(BinaryOpIC::UNINITIALIZED), 1000 result_type_(BinaryOpIC::UNINITIALIZED), 1001 encoded_right_arg_(false, encode_arg_value(1)) { 1002 Initialize(); 1003 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); 1004 } 1005 1006 BinaryOpStub( 1007 int key, 1008 BinaryOpIC::TypeInfo left_type, 1009 BinaryOpIC::TypeInfo right_type, 1010 BinaryOpIC::TypeInfo result_type, 1011 Maybe<int32_t> fixed_right_arg) 1012 : op_(OpBits::decode(key)), 1013 mode_(ModeBits::decode(key)), 1014 platform_specific_bit_(PlatformSpecificBits::decode(key)), 1015 left_type_(left_type), 1016 right_type_(right_type), 1017 result_type_(result_type), 1018 encoded_right_arg_(fixed_right_arg.has_value, 1019 encode_arg_value(fixed_right_arg.value)) { } 1020 1021 static void decode_types_from_minor_key(int minor_key, 1022 BinaryOpIC::TypeInfo* left_type, 1023 BinaryOpIC::TypeInfo* right_type, 1024 BinaryOpIC::TypeInfo* result_type) { 1025 *left_type = 1026 static_cast<BinaryOpIC::TypeInfo>(LeftTypeBits::decode(minor_key)); 1027 *right_type = 1028 static_cast<BinaryOpIC::TypeInfo>(RightTypeBits::decode(minor_key)); 1029 *result_type = 1030 static_cast<BinaryOpIC::TypeInfo>(ResultTypeBits::decode(minor_key)); 1031 } 1032 1033 static Token::Value decode_op_from_minor_key(int minor_key) { 1034 return static_cast<Token::Value>(OpBits::decode(minor_key)); 1035 } 1036 1037 static Maybe<int> decode_fixed_right_arg_from_minor_key(int minor_key) { 1038 return Maybe<int>( 1039 HasFixedRightArgBits::decode(minor_key), 1040 decode_arg_value(FixedRightArgValueBits::decode(minor_key))); 1041 } 1042 1043 int fixed_right_arg_value() const { 1044 return decode_arg_value(encoded_right_arg_.value); 1045 } 1046 1047 static bool can_encode_arg_value(int32_t value) { 1048 return value > 0 && 1049 IsPowerOf2(value) && 1050 FixedRightArgValueBits::is_valid(WhichPowerOf2(value)); 1051 } 1052 1053 enum SmiCodeGenerateHeapNumberResults { 1054 ALLOW_HEAPNUMBER_RESULTS, 1055 NO_HEAPNUMBER_RESULTS 1056 }; 1057 1058 private: 1059 Token::Value op_; 1060 OverwriteMode mode_; 1061 bool platform_specific_bit_; // Indicates SSE3 on IA32. 1062 1063 // Operand type information determined at runtime. 1064 BinaryOpIC::TypeInfo left_type_; 1065 BinaryOpIC::TypeInfo right_type_; 1066 BinaryOpIC::TypeInfo result_type_; 1067 1068 Maybe<int> encoded_right_arg_; 1069 1070 static int encode_arg_value(int32_t value) { 1071 ASSERT(can_encode_arg_value(value)); 1072 return WhichPowerOf2(value); 1073 } 1074 1075 static int32_t decode_arg_value(int value) { 1076 return 1 << value; 1077 } 1078 1079 virtual void PrintName(StringStream* stream); 1080 1081 // Minor key encoding in all 25 bits FFFFFHTTTRRRLLLPOOOOOOOMM. 1082 // Note: We actually do not need 7 bits for the operation, just 4 bits to 1083 // encode ADD, SUB, MUL, DIV, MOD, BIT_OR, BIT_AND, BIT_XOR, SAR, SHL, SHR. 1084 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 1085 class OpBits: public BitField<Token::Value, 2, 7> {}; 1086 class PlatformSpecificBits: public BitField<bool, 9, 1> {}; 1087 class LeftTypeBits: public BitField<BinaryOpIC::TypeInfo, 10, 3> {}; 1088 class RightTypeBits: public BitField<BinaryOpIC::TypeInfo, 13, 3> {}; 1089 class ResultTypeBits: public BitField<BinaryOpIC::TypeInfo, 16, 3> {}; 1090 class HasFixedRightArgBits: public BitField<bool, 19, 1> {}; 1091 class FixedRightArgValueBits: public BitField<int, 20, 5> {}; 1092 1093 Major MajorKey() { return BinaryOp; } 1094 int MinorKey() { 1095 return OpBits::encode(op_) 1096 | ModeBits::encode(mode_) 1097 | PlatformSpecificBits::encode(platform_specific_bit_) 1098 | LeftTypeBits::encode(left_type_) 1099 | RightTypeBits::encode(right_type_) 1100 | ResultTypeBits::encode(result_type_) 1101 | HasFixedRightArgBits::encode(encoded_right_arg_.has_value) 1102 | FixedRightArgValueBits::encode(encoded_right_arg_.value); 1103 } 1104 1105 1106 // Platform-independent implementation. 1107 void Generate(MacroAssembler* masm); 1108 void GenerateCallRuntime(MacroAssembler* masm); 1109 1110 // Platform-independent signature, platform-specific implementation. 1111 void Initialize(); 1112 void GenerateAddStrings(MacroAssembler* masm); 1113 void GenerateBothStringStub(MacroAssembler* masm); 1114 void GenerateGeneric(MacroAssembler* masm); 1115 void GenerateGenericStub(MacroAssembler* masm); 1116 void GenerateNumberStub(MacroAssembler* masm); 1117 void GenerateInt32Stub(MacroAssembler* masm); 1118 void GenerateLoadArguments(MacroAssembler* masm); 1119 void GenerateOddballStub(MacroAssembler* masm); 1120 void GenerateRegisterArgsPush(MacroAssembler* masm); 1121 void GenerateReturn(MacroAssembler* masm); 1122 void GenerateSmiStub(MacroAssembler* masm); 1123 void GenerateStringStub(MacroAssembler* masm); 1124 void GenerateTypeTransition(MacroAssembler* masm); 1125 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); 1126 void GenerateUninitializedStub(MacroAssembler* masm); 1127 1128 // Entirely platform-specific methods are defined as static helper 1129 // functions in the <arch>/code-stubs-<arch>.cc files. 1130 1131 virtual Code::Kind GetCodeKind() const { return Code::BINARY_OP_IC; } 1132 1133 virtual InlineCacheState GetICState() { 1134 return BinaryOpIC::ToState(Max(left_type_, right_type_)); 1135 } 1136 1137 virtual void FinishCode(Handle<Code> code) { 1138 code->set_stub_info(MinorKey()); 1139 } 1140 1141 friend class CodeGenerator; 1142 }; 1143 1144 1145 class ICCompareStub: public PlatformCodeStub { 1146 public: 1147 ICCompareStub(Token::Value op, 1148 CompareIC::State left, 1149 CompareIC::State right, 1150 CompareIC::State handler) 1151 : op_(op), 1152 left_(left), 1153 right_(right), 1154 state_(handler) { 1155 ASSERT(Token::IsCompareOp(op)); 1156 } 1157 1158 virtual void Generate(MacroAssembler* masm); 1159 1160 void set_known_map(Handle<Map> map) { known_map_ = map; } 1161 1162 static void DecodeMinorKey(int minor_key, 1163 CompareIC::State* left_state, 1164 CompareIC::State* right_state, 1165 CompareIC::State* handler_state, 1166 Token::Value* op); 1167 1168 static CompareIC::State CompareState(int minor_key) { 1169 return static_cast<CompareIC::State>(HandlerStateField::decode(minor_key)); 1170 } 1171 1172 virtual InlineCacheState GetICState(); 1173 1174 private: 1175 class OpField: public BitField<int, 0, 3> { }; 1176 class LeftStateField: public BitField<int, 3, 4> { }; 1177 class RightStateField: public BitField<int, 7, 4> { }; 1178 class HandlerStateField: public BitField<int, 11, 4> { }; 1179 1180 virtual void FinishCode(Handle<Code> code) { 1181 code->set_stub_info(MinorKey()); 1182 } 1183 1184 virtual CodeStub::Major MajorKey() { return CompareIC; } 1185 virtual int MinorKey(); 1186 1187 virtual Code::Kind GetCodeKind() const { return Code::COMPARE_IC; } 1188 1189 void GenerateSmis(MacroAssembler* masm); 1190 void GenerateNumbers(MacroAssembler* masm); 1191 void GenerateInternalizedStrings(MacroAssembler* masm); 1192 void GenerateStrings(MacroAssembler* masm); 1193 void GenerateUniqueNames(MacroAssembler* masm); 1194 void GenerateObjects(MacroAssembler* masm); 1195 void GenerateMiss(MacroAssembler* masm); 1196 void GenerateKnownObjects(MacroAssembler* masm); 1197 void GenerateGeneric(MacroAssembler* masm); 1198 1199 bool strict() const { return op_ == Token::EQ_STRICT; } 1200 Condition GetCondition() const { return CompareIC::ComputeCondition(op_); } 1201 1202 virtual void AddToSpecialCache(Handle<Code> new_object); 1203 virtual bool FindCodeInSpecialCache(Code** code_out, Isolate* isolate); 1204 virtual bool UseSpecialCache() { return state_ == CompareIC::KNOWN_OBJECT; } 1205 1206 Token::Value op_; 1207 CompareIC::State left_; 1208 CompareIC::State right_; 1209 CompareIC::State state_; 1210 Handle<Map> known_map_; 1211 }; 1212 1213 1214 class CompareNilICStub : public HydrogenCodeStub { 1215 public: 1216 Handle<Type> GetType(Isolate* isolate, Handle<Map> map = Handle<Map>()); 1217 Handle<Type> GetInputType(Isolate* isolate, Handle<Map> map); 1218 1219 explicit CompareNilICStub(NilValue nil) : nil_value_(nil) { } 1220 1221 CompareNilICStub(Code::ExtraICState ic_state, 1222 InitializationState init_state = INITIALIZED) 1223 : HydrogenCodeStub(init_state), 1224 nil_value_(NilValueField::decode(ic_state)), 1225 state_(State(TypesField::decode(ic_state))) { 1226 } 1227 1228 static Handle<Code> GetUninitialized(Isolate* isolate, 1229 NilValue nil) { 1230 return CompareNilICStub(nil, UNINITIALIZED).GetCode(isolate); 1231 } 1232 1233 virtual void InitializeInterfaceDescriptor( 1234 Isolate* isolate, 1235 CodeStubInterfaceDescriptor* descriptor); 1236 1237 static void InitializeForIsolate(Isolate* isolate) { 1238 CompareNilICStub compare_stub(kNullValue, UNINITIALIZED); 1239 compare_stub.InitializeInterfaceDescriptor( 1240 isolate, 1241 isolate->code_stub_interface_descriptor(CodeStub::CompareNilIC)); 1242 } 1243 1244 virtual InlineCacheState GetICState() { 1245 if (state_.Contains(GENERIC)) { 1246 return MEGAMORPHIC; 1247 } else if (state_.Contains(MONOMORPHIC_MAP)) { 1248 return MONOMORPHIC; 1249 } else { 1250 return PREMONOMORPHIC; 1251 } 1252 } 1253 1254 virtual Code::Kind GetCodeKind() const { return Code::COMPARE_NIL_IC; } 1255 1256 Handle<Code> GenerateCode(); 1257 1258 virtual Code::ExtraICState GetExtraICState() { 1259 return NilValueField::encode(nil_value_) | 1260 TypesField::encode(state_.ToIntegral()); 1261 } 1262 1263 void UpdateStatus(Handle<Object> object); 1264 1265 bool IsMonomorphic() const { return state_.Contains(MONOMORPHIC_MAP); } 1266 NilValue GetNilValue() const { return nil_value_; } 1267 void ClearState() { state_.RemoveAll(); } 1268 1269 virtual void PrintState(StringStream* stream); 1270 virtual void PrintBaseName(StringStream* stream); 1271 1272 private: 1273 friend class CompareNilIC; 1274 1275 enum CompareNilType { 1276 UNDEFINED, 1277 NULL_TYPE, 1278 MONOMORPHIC_MAP, 1279 GENERIC, 1280 NUMBER_OF_TYPES 1281 }; 1282 1283 // At most 6 different types can be distinguished, because the Code object 1284 // only has room for a single byte to hold a set and there are two more 1285 // boolean flags we need to store. :-P 1286 STATIC_ASSERT(NUMBER_OF_TYPES <= 6); 1287 1288 class State : public EnumSet<CompareNilType, byte> { 1289 public: 1290 State() : EnumSet<CompareNilType, byte>(0) { } 1291 explicit State(byte bits) : EnumSet<CompareNilType, byte>(bits) { } 1292 1293 void Print(StringStream* stream) const; 1294 }; 1295 1296 CompareNilICStub(NilValue nil, InitializationState init_state) 1297 : HydrogenCodeStub(init_state), nil_value_(nil) { } 1298 1299 class NilValueField : public BitField<NilValue, 0, 1> {}; 1300 class TypesField : public BitField<byte, 1, NUMBER_OF_TYPES> {}; 1301 1302 virtual CodeStub::Major MajorKey() { return CompareNilIC; } 1303 virtual int NotMissMinorKey() { return GetExtraICState(); } 1304 1305 NilValue nil_value_; 1306 State state_; 1307 1308 DISALLOW_COPY_AND_ASSIGN(CompareNilICStub); 1309 }; 1310 1311 1312 class CEntryStub : public PlatformCodeStub { 1313 public: 1314 explicit CEntryStub(int result_size, 1315 SaveFPRegsMode save_doubles = kDontSaveFPRegs) 1316 : result_size_(result_size), save_doubles_(save_doubles) { } 1317 1318 void Generate(MacroAssembler* masm); 1319 1320 // The version of this stub that doesn't save doubles is generated ahead of 1321 // time, so it's OK to call it from other stubs that can't cope with GC during 1322 // their code generation. On machines that always have gp registers (x64) we 1323 // can generate both variants ahead of time. 1324 virtual bool IsPregenerated(); 1325 static void GenerateAheadOfTime(Isolate* isolate); 1326 1327 private: 1328 void GenerateCore(MacroAssembler* masm, 1329 Label* throw_normal_exception, 1330 Label* throw_termination_exception, 1331 Label* throw_out_of_memory_exception, 1332 bool do_gc, 1333 bool always_allocate_scope); 1334 1335 // Number of pointers/values returned. 1336 const int result_size_; 1337 SaveFPRegsMode save_doubles_; 1338 1339 Major MajorKey() { return CEntry; } 1340 int MinorKey(); 1341 1342 bool NeedsImmovableCode(); 1343 }; 1344 1345 1346 class JSEntryStub : public PlatformCodeStub { 1347 public: 1348 JSEntryStub() { } 1349 1350 void Generate(MacroAssembler* masm) { GenerateBody(masm, false); } 1351 1352 protected: 1353 void GenerateBody(MacroAssembler* masm, bool is_construct); 1354 1355 private: 1356 Major MajorKey() { return JSEntry; } 1357 int MinorKey() { return 0; } 1358 1359 virtual void FinishCode(Handle<Code> code); 1360 1361 int handler_offset_; 1362 }; 1363 1364 1365 class JSConstructEntryStub : public JSEntryStub { 1366 public: 1367 JSConstructEntryStub() { } 1368 1369 void Generate(MacroAssembler* masm) { GenerateBody(masm, true); } 1370 1371 private: 1372 int MinorKey() { return 1; } 1373 1374 virtual void PrintName(StringStream* stream) { 1375 stream->Add("JSConstructEntryStub"); 1376 } 1377 }; 1378 1379 1380 class ArgumentsAccessStub: public PlatformCodeStub { 1381 public: 1382 enum Type { 1383 READ_ELEMENT, 1384 NEW_NON_STRICT_FAST, 1385 NEW_NON_STRICT_SLOW, 1386 NEW_STRICT 1387 }; 1388 1389 explicit ArgumentsAccessStub(Type type) : type_(type) { } 1390 1391 private: 1392 Type type_; 1393 1394 Major MajorKey() { return ArgumentsAccess; } 1395 int MinorKey() { return type_; } 1396 1397 void Generate(MacroAssembler* masm); 1398 void GenerateReadElement(MacroAssembler* masm); 1399 void GenerateNewStrict(MacroAssembler* masm); 1400 void GenerateNewNonStrictFast(MacroAssembler* masm); 1401 void GenerateNewNonStrictSlow(MacroAssembler* masm); 1402 1403 virtual void PrintName(StringStream* stream); 1404 }; 1405 1406 1407 class RegExpExecStub: public PlatformCodeStub { 1408 public: 1409 RegExpExecStub() { } 1410 1411 private: 1412 Major MajorKey() { return RegExpExec; } 1413 int MinorKey() { return 0; } 1414 1415 void Generate(MacroAssembler* masm); 1416 }; 1417 1418 1419 class RegExpConstructResultStub: public PlatformCodeStub { 1420 public: 1421 RegExpConstructResultStub() { } 1422 1423 private: 1424 Major MajorKey() { return RegExpConstructResult; } 1425 int MinorKey() { return 0; } 1426 1427 void Generate(MacroAssembler* masm); 1428 }; 1429 1430 1431 class CallFunctionStub: public PlatformCodeStub { 1432 public: 1433 CallFunctionStub(int argc, CallFunctionFlags flags) 1434 : argc_(argc), flags_(flags) { } 1435 1436 void Generate(MacroAssembler* masm); 1437 1438 virtual void FinishCode(Handle<Code> code) { 1439 code->set_has_function_cache(RecordCallTarget()); 1440 } 1441 1442 static int ExtractArgcFromMinorKey(int minor_key) { 1443 return ArgcBits::decode(minor_key); 1444 } 1445 1446 private: 1447 int argc_; 1448 CallFunctionFlags flags_; 1449 1450 virtual void PrintName(StringStream* stream); 1451 1452 // Minor key encoding in 32 bits with Bitfield <Type, shift, size>. 1453 class FlagBits: public BitField<CallFunctionFlags, 0, 2> {}; 1454 class ArgcBits: public BitField<unsigned, 2, 32 - 2> {}; 1455 1456 Major MajorKey() { return CallFunction; } 1457 int MinorKey() { 1458 // Encode the parameters in a unique 32 bit value. 1459 return FlagBits::encode(flags_) | ArgcBits::encode(argc_); 1460 } 1461 1462 bool ReceiverMightBeImplicit() { 1463 return (flags_ & RECEIVER_MIGHT_BE_IMPLICIT) != 0; 1464 } 1465 1466 bool RecordCallTarget() { 1467 return (flags_ & RECORD_CALL_TARGET) != 0; 1468 } 1469 }; 1470 1471 1472 class CallConstructStub: public PlatformCodeStub { 1473 public: 1474 explicit CallConstructStub(CallFunctionFlags flags) : flags_(flags) {} 1475 1476 void Generate(MacroAssembler* masm); 1477 1478 virtual void FinishCode(Handle<Code> code) { 1479 code->set_has_function_cache(RecordCallTarget()); 1480 } 1481 1482 private: 1483 CallFunctionFlags flags_; 1484 1485 virtual void PrintName(StringStream* stream); 1486 1487 Major MajorKey() { return CallConstruct; } 1488 int MinorKey() { return flags_; } 1489 1490 bool RecordCallTarget() { 1491 return (flags_ & RECORD_CALL_TARGET) != 0; 1492 } 1493 }; 1494 1495 1496 enum StringIndexFlags { 1497 // Accepts smis or heap numbers. 1498 STRING_INDEX_IS_NUMBER, 1499 1500 // Accepts smis or heap numbers that are valid array indices 1501 // (ECMA-262 15.4). Invalid indices are reported as being out of 1502 // range. 1503 STRING_INDEX_IS_ARRAY_INDEX 1504 }; 1505 1506 1507 // Generates code implementing String.prototype.charCodeAt. 1508 // 1509 // Only supports the case when the receiver is a string and the index 1510 // is a number (smi or heap number) that is a valid index into the 1511 // string. Additional index constraints are specified by the 1512 // flags. Otherwise, bails out to the provided labels. 1513 // 1514 // Register usage: |object| may be changed to another string in a way 1515 // that doesn't affect charCodeAt/charAt semantics, |index| is 1516 // preserved, |scratch| and |result| are clobbered. 1517 class StringCharCodeAtGenerator { 1518 public: 1519 StringCharCodeAtGenerator(Register object, 1520 Register index, 1521 Register result, 1522 Label* receiver_not_string, 1523 Label* index_not_number, 1524 Label* index_out_of_range, 1525 StringIndexFlags index_flags) 1526 : object_(object), 1527 index_(index), 1528 result_(result), 1529 receiver_not_string_(receiver_not_string), 1530 index_not_number_(index_not_number), 1531 index_out_of_range_(index_out_of_range), 1532 index_flags_(index_flags) { 1533 ASSERT(!result_.is(object_)); 1534 ASSERT(!result_.is(index_)); 1535 } 1536 1537 // Generates the fast case code. On the fallthrough path |result| 1538 // register contains the result. 1539 void GenerateFast(MacroAssembler* masm); 1540 1541 // Generates the slow case code. Must not be naturally 1542 // reachable. Expected to be put after a ret instruction (e.g., in 1543 // deferred code). Always jumps back to the fast case. 1544 void GenerateSlow(MacroAssembler* masm, 1545 const RuntimeCallHelper& call_helper); 1546 1547 // Skip handling slow case and directly jump to bailout. 1548 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1549 masm->bind(&index_not_smi_); 1550 masm->bind(&call_runtime_); 1551 masm->jmp(bailout); 1552 } 1553 1554 private: 1555 Register object_; 1556 Register index_; 1557 Register result_; 1558 1559 Label* receiver_not_string_; 1560 Label* index_not_number_; 1561 Label* index_out_of_range_; 1562 1563 StringIndexFlags index_flags_; 1564 1565 Label call_runtime_; 1566 Label index_not_smi_; 1567 Label got_smi_index_; 1568 Label exit_; 1569 1570 DISALLOW_COPY_AND_ASSIGN(StringCharCodeAtGenerator); 1571 }; 1572 1573 1574 // Generates code for creating a one-char string from a char code. 1575 class StringCharFromCodeGenerator { 1576 public: 1577 StringCharFromCodeGenerator(Register code, 1578 Register result) 1579 : code_(code), 1580 result_(result) { 1581 ASSERT(!code_.is(result_)); 1582 } 1583 1584 // Generates the fast case code. On the fallthrough path |result| 1585 // register contains the result. 1586 void GenerateFast(MacroAssembler* masm); 1587 1588 // Generates the slow case code. Must not be naturally 1589 // reachable. Expected to be put after a ret instruction (e.g., in 1590 // deferred code). Always jumps back to the fast case. 1591 void GenerateSlow(MacroAssembler* masm, 1592 const RuntimeCallHelper& call_helper); 1593 1594 // Skip handling slow case and directly jump to bailout. 1595 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1596 masm->bind(&slow_case_); 1597 masm->jmp(bailout); 1598 } 1599 1600 private: 1601 Register code_; 1602 Register result_; 1603 1604 Label slow_case_; 1605 Label exit_; 1606 1607 DISALLOW_COPY_AND_ASSIGN(StringCharFromCodeGenerator); 1608 }; 1609 1610 1611 // Generates code implementing String.prototype.charAt. 1612 // 1613 // Only supports the case when the receiver is a string and the index 1614 // is a number (smi or heap number) that is a valid index into the 1615 // string. Additional index constraints are specified by the 1616 // flags. Otherwise, bails out to the provided labels. 1617 // 1618 // Register usage: |object| may be changed to another string in a way 1619 // that doesn't affect charCodeAt/charAt semantics, |index| is 1620 // preserved, |scratch1|, |scratch2|, and |result| are clobbered. 1621 class StringCharAtGenerator { 1622 public: 1623 StringCharAtGenerator(Register object, 1624 Register index, 1625 Register scratch, 1626 Register result, 1627 Label* receiver_not_string, 1628 Label* index_not_number, 1629 Label* index_out_of_range, 1630 StringIndexFlags index_flags) 1631 : char_code_at_generator_(object, 1632 index, 1633 scratch, 1634 receiver_not_string, 1635 index_not_number, 1636 index_out_of_range, 1637 index_flags), 1638 char_from_code_generator_(scratch, result) {} 1639 1640 // Generates the fast case code. On the fallthrough path |result| 1641 // register contains the result. 1642 void GenerateFast(MacroAssembler* masm) { 1643 char_code_at_generator_.GenerateFast(masm); 1644 char_from_code_generator_.GenerateFast(masm); 1645 } 1646 1647 // Generates the slow case code. Must not be naturally 1648 // reachable. Expected to be put after a ret instruction (e.g., in 1649 // deferred code). Always jumps back to the fast case. 1650 void GenerateSlow(MacroAssembler* masm, 1651 const RuntimeCallHelper& call_helper) { 1652 char_code_at_generator_.GenerateSlow(masm, call_helper); 1653 char_from_code_generator_.GenerateSlow(masm, call_helper); 1654 } 1655 1656 // Skip handling slow case and directly jump to bailout. 1657 void SkipSlow(MacroAssembler* masm, Label* bailout) { 1658 char_code_at_generator_.SkipSlow(masm, bailout); 1659 char_from_code_generator_.SkipSlow(masm, bailout); 1660 } 1661 1662 private: 1663 StringCharCodeAtGenerator char_code_at_generator_; 1664 StringCharFromCodeGenerator char_from_code_generator_; 1665 1666 DISALLOW_COPY_AND_ASSIGN(StringCharAtGenerator); 1667 }; 1668 1669 1670 class AllowStubCallsScope { 1671 public: 1672 AllowStubCallsScope(MacroAssembler* masm, bool allow) 1673 : masm_(masm), previous_allow_(masm->allow_stub_calls()) { 1674 masm_->set_allow_stub_calls(allow); 1675 } 1676 ~AllowStubCallsScope() { 1677 masm_->set_allow_stub_calls(previous_allow_); 1678 } 1679 1680 private: 1681 MacroAssembler* masm_; 1682 bool previous_allow_; 1683 1684 DISALLOW_COPY_AND_ASSIGN(AllowStubCallsScope); 1685 }; 1686 1687 1688 class KeyedLoadDictionaryElementStub : public PlatformCodeStub { 1689 public: 1690 KeyedLoadDictionaryElementStub() {} 1691 1692 void Generate(MacroAssembler* masm); 1693 1694 private: 1695 Major MajorKey() { return KeyedLoadElement; } 1696 int MinorKey() { return DICTIONARY_ELEMENTS; } 1697 1698 DISALLOW_COPY_AND_ASSIGN(KeyedLoadDictionaryElementStub); 1699 }; 1700 1701 1702 class DoubleToIStub : public PlatformCodeStub { 1703 public: 1704 DoubleToIStub(Register source, 1705 Register destination, 1706 int offset, 1707 bool is_truncating) : bit_field_(0) { 1708 bit_field_ = SourceRegisterBits::encode(source.code_) | 1709 DestinationRegisterBits::encode(destination.code_) | 1710 OffsetBits::encode(offset) | 1711 IsTruncatingBits::encode(is_truncating); 1712 } 1713 1714 Register source() { 1715 Register result = { SourceRegisterBits::decode(bit_field_) }; 1716 return result; 1717 } 1718 1719 Register destination() { 1720 Register result = { DestinationRegisterBits::decode(bit_field_) }; 1721 return result; 1722 } 1723 1724 bool is_truncating() { 1725 return IsTruncatingBits::decode(bit_field_); 1726 } 1727 1728 int offset() { 1729 return OffsetBits::decode(bit_field_); 1730 } 1731 1732 void Generate(MacroAssembler* masm); 1733 1734 private: 1735 static const int kBitsPerRegisterNumber = 6; 1736 STATIC_ASSERT((1L << kBitsPerRegisterNumber) >= Register::kNumRegisters); 1737 class SourceRegisterBits: 1738 public BitField<int, 0, kBitsPerRegisterNumber> {}; // NOLINT 1739 class DestinationRegisterBits: 1740 public BitField<int, kBitsPerRegisterNumber, 1741 kBitsPerRegisterNumber> {}; // NOLINT 1742 class IsTruncatingBits: 1743 public BitField<bool, 2 * kBitsPerRegisterNumber, 1> {}; // NOLINT 1744 class OffsetBits: 1745 public BitField<int, 2 * kBitsPerRegisterNumber + 1, 3> {}; // NOLINT 1746 1747 Major MajorKey() { return DoubleToI; } 1748 int MinorKey() { return bit_field_; } 1749 1750 int bit_field_; 1751 1752 DISALLOW_COPY_AND_ASSIGN(DoubleToIStub); 1753 }; 1754 1755 1756 class KeyedLoadFastElementStub : public HydrogenCodeStub { 1757 public: 1758 KeyedLoadFastElementStub(bool is_js_array, ElementsKind elements_kind) { 1759 bit_field_ = ElementsKindBits::encode(elements_kind) | 1760 IsJSArrayBits::encode(is_js_array); 1761 } 1762 1763 bool is_js_array() const { 1764 return IsJSArrayBits::decode(bit_field_); 1765 } 1766 1767 ElementsKind elements_kind() const { 1768 return ElementsKindBits::decode(bit_field_); 1769 } 1770 1771 virtual Handle<Code> GenerateCode(); 1772 1773 virtual void InitializeInterfaceDescriptor( 1774 Isolate* isolate, 1775 CodeStubInterfaceDescriptor* descriptor); 1776 1777 private: 1778 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 1779 class IsJSArrayBits: public BitField<bool, 8, 1> {}; 1780 uint32_t bit_field_; 1781 1782 Major MajorKey() { return KeyedLoadElement; } 1783 int NotMissMinorKey() { return bit_field_; } 1784 1785 DISALLOW_COPY_AND_ASSIGN(KeyedLoadFastElementStub); 1786 }; 1787 1788 1789 class KeyedStoreFastElementStub : public HydrogenCodeStub { 1790 public: 1791 KeyedStoreFastElementStub(bool is_js_array, 1792 ElementsKind elements_kind, 1793 KeyedAccessStoreMode mode) { 1794 bit_field_ = ElementsKindBits::encode(elements_kind) | 1795 IsJSArrayBits::encode(is_js_array) | 1796 StoreModeBits::encode(mode); 1797 } 1798 1799 bool is_js_array() const { 1800 return IsJSArrayBits::decode(bit_field_); 1801 } 1802 1803 ElementsKind elements_kind() const { 1804 return ElementsKindBits::decode(bit_field_); 1805 } 1806 1807 KeyedAccessStoreMode store_mode() const { 1808 return StoreModeBits::decode(bit_field_); 1809 } 1810 1811 virtual Handle<Code> GenerateCode(); 1812 1813 virtual void InitializeInterfaceDescriptor( 1814 Isolate* isolate, 1815 CodeStubInterfaceDescriptor* descriptor); 1816 1817 private: 1818 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 1819 class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {}; 1820 class IsJSArrayBits: public BitField<bool, 12, 1> {}; 1821 uint32_t bit_field_; 1822 1823 Major MajorKey() { return KeyedStoreElement; } 1824 int NotMissMinorKey() { return bit_field_; } 1825 1826 DISALLOW_COPY_AND_ASSIGN(KeyedStoreFastElementStub); 1827 }; 1828 1829 1830 class TransitionElementsKindStub : public HydrogenCodeStub { 1831 public: 1832 TransitionElementsKindStub(ElementsKind from_kind, 1833 ElementsKind to_kind) { 1834 bit_field_ = FromKindBits::encode(from_kind) | 1835 ToKindBits::encode(to_kind); 1836 } 1837 1838 ElementsKind from_kind() const { 1839 return FromKindBits::decode(bit_field_); 1840 } 1841 1842 ElementsKind to_kind() const { 1843 return ToKindBits::decode(bit_field_); 1844 } 1845 1846 virtual Handle<Code> GenerateCode(); 1847 1848 virtual void InitializeInterfaceDescriptor( 1849 Isolate* isolate, 1850 CodeStubInterfaceDescriptor* descriptor); 1851 1852 private: 1853 class FromKindBits: public BitField<ElementsKind, 8, 8> {}; 1854 class ToKindBits: public BitField<ElementsKind, 0, 8> {}; 1855 uint32_t bit_field_; 1856 1857 Major MajorKey() { return TransitionElementsKind; } 1858 int NotMissMinorKey() { return bit_field_; } 1859 1860 DISALLOW_COPY_AND_ASSIGN(TransitionElementsKindStub); 1861 }; 1862 1863 1864 enum ContextCheckMode { 1865 CONTEXT_CHECK_REQUIRED, 1866 CONTEXT_CHECK_NOT_REQUIRED, 1867 LAST_CONTEXT_CHECK_MODE = CONTEXT_CHECK_NOT_REQUIRED 1868 }; 1869 1870 1871 enum AllocationSiteOverrideMode { 1872 DONT_OVERRIDE, 1873 DISABLE_ALLOCATION_SITES, 1874 LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES 1875 }; 1876 1877 1878 class ArrayConstructorStubBase : public HydrogenCodeStub { 1879 public: 1880 ArrayConstructorStubBase(ElementsKind kind, ContextCheckMode context_mode, 1881 AllocationSiteOverrideMode override_mode) { 1882 // It only makes sense to override local allocation site behavior 1883 // if there is a difference between the global allocation site policy 1884 // for an ElementsKind and the desired usage of the stub. 1885 ASSERT(override_mode != DISABLE_ALLOCATION_SITES || 1886 AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE); 1887 bit_field_ = ElementsKindBits::encode(kind) | 1888 AllocationSiteOverrideModeBits::encode(override_mode) | 1889 ContextCheckModeBits::encode(context_mode); 1890 } 1891 1892 ElementsKind elements_kind() const { 1893 return ElementsKindBits::decode(bit_field_); 1894 } 1895 1896 AllocationSiteOverrideMode override_mode() const { 1897 return AllocationSiteOverrideModeBits::decode(bit_field_); 1898 } 1899 1900 ContextCheckMode context_mode() const { 1901 return ContextCheckModeBits::decode(bit_field_); 1902 } 1903 1904 virtual bool IsPregenerated() { 1905 // We only pre-generate stubs that verify correct context 1906 return context_mode() == CONTEXT_CHECK_REQUIRED; 1907 } 1908 1909 static void GenerateStubsAheadOfTime(Isolate* isolate); 1910 static void InstallDescriptors(Isolate* isolate); 1911 1912 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 1913 static const int kConstructor = 0; 1914 static const int kPropertyCell = 1; 1915 1916 private: 1917 int NotMissMinorKey() { return bit_field_; } 1918 1919 // Ensure data fits within available bits. 1920 STATIC_ASSERT(LAST_ALLOCATION_SITE_OVERRIDE_MODE == 1); 1921 STATIC_ASSERT(LAST_CONTEXT_CHECK_MODE == 1); 1922 1923 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 1924 class AllocationSiteOverrideModeBits: public 1925 BitField<AllocationSiteOverrideMode, 8, 1> {}; // NOLINT 1926 class ContextCheckModeBits: public BitField<ContextCheckMode, 9, 1> {}; 1927 uint32_t bit_field_; 1928 1929 DISALLOW_COPY_AND_ASSIGN(ArrayConstructorStubBase); 1930 }; 1931 1932 1933 class ArrayNoArgumentConstructorStub : public ArrayConstructorStubBase { 1934 public: 1935 ArrayNoArgumentConstructorStub( 1936 ElementsKind kind, 1937 ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED, 1938 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) 1939 : ArrayConstructorStubBase(kind, context_mode, override_mode) { 1940 } 1941 1942 virtual Handle<Code> GenerateCode(); 1943 1944 virtual void InitializeInterfaceDescriptor( 1945 Isolate* isolate, 1946 CodeStubInterfaceDescriptor* descriptor); 1947 1948 private: 1949 Major MajorKey() { return ArrayNoArgumentConstructor; } 1950 1951 DISALLOW_COPY_AND_ASSIGN(ArrayNoArgumentConstructorStub); 1952 }; 1953 1954 1955 class ArraySingleArgumentConstructorStub : public ArrayConstructorStubBase { 1956 public: 1957 ArraySingleArgumentConstructorStub( 1958 ElementsKind kind, 1959 ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED, 1960 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) 1961 : ArrayConstructorStubBase(kind, context_mode, override_mode) { 1962 } 1963 1964 virtual Handle<Code> GenerateCode(); 1965 1966 virtual void InitializeInterfaceDescriptor( 1967 Isolate* isolate, 1968 CodeStubInterfaceDescriptor* descriptor); 1969 1970 private: 1971 Major MajorKey() { return ArraySingleArgumentConstructor; } 1972 1973 DISALLOW_COPY_AND_ASSIGN(ArraySingleArgumentConstructorStub); 1974 }; 1975 1976 1977 class ArrayNArgumentsConstructorStub : public ArrayConstructorStubBase { 1978 public: 1979 ArrayNArgumentsConstructorStub( 1980 ElementsKind kind, 1981 ContextCheckMode context_mode = CONTEXT_CHECK_REQUIRED, 1982 AllocationSiteOverrideMode override_mode = DONT_OVERRIDE) 1983 : ArrayConstructorStubBase(kind, context_mode, override_mode) { 1984 } 1985 1986 virtual Handle<Code> GenerateCode(); 1987 1988 virtual void InitializeInterfaceDescriptor( 1989 Isolate* isolate, 1990 CodeStubInterfaceDescriptor* descriptor); 1991 1992 private: 1993 Major MajorKey() { return ArrayNArgumentsConstructor; } 1994 1995 DISALLOW_COPY_AND_ASSIGN(ArrayNArgumentsConstructorStub); 1996 }; 1997 1998 1999 class InternalArrayConstructorStubBase : public HydrogenCodeStub { 2000 public: 2001 explicit InternalArrayConstructorStubBase(ElementsKind kind) { 2002 kind_ = kind; 2003 } 2004 2005 virtual bool IsPregenerated() { return true; } 2006 static void GenerateStubsAheadOfTime(Isolate* isolate); 2007 static void InstallDescriptors(Isolate* isolate); 2008 2009 // Parameters accessed via CodeStubGraphBuilder::GetParameter() 2010 static const int kConstructor = 0; 2011 2012 ElementsKind elements_kind() const { return kind_; } 2013 2014 private: 2015 int NotMissMinorKey() { return kind_; } 2016 2017 ElementsKind kind_; 2018 2019 DISALLOW_COPY_AND_ASSIGN(InternalArrayConstructorStubBase); 2020 }; 2021 2022 2023 class InternalArrayNoArgumentConstructorStub : public 2024 InternalArrayConstructorStubBase { 2025 public: 2026 explicit InternalArrayNoArgumentConstructorStub(ElementsKind kind) 2027 : InternalArrayConstructorStubBase(kind) { } 2028 2029 virtual Handle<Code> GenerateCode(); 2030 2031 virtual void InitializeInterfaceDescriptor( 2032 Isolate* isolate, 2033 CodeStubInterfaceDescriptor* descriptor); 2034 2035 private: 2036 Major MajorKey() { return InternalArrayNoArgumentConstructor; } 2037 2038 DISALLOW_COPY_AND_ASSIGN(InternalArrayNoArgumentConstructorStub); 2039 }; 2040 2041 2042 class InternalArraySingleArgumentConstructorStub : public 2043 InternalArrayConstructorStubBase { 2044 public: 2045 explicit InternalArraySingleArgumentConstructorStub(ElementsKind kind) 2046 : InternalArrayConstructorStubBase(kind) { } 2047 2048 virtual Handle<Code> GenerateCode(); 2049 2050 virtual void InitializeInterfaceDescriptor( 2051 Isolate* isolate, 2052 CodeStubInterfaceDescriptor* descriptor); 2053 2054 private: 2055 Major MajorKey() { return InternalArraySingleArgumentConstructor; } 2056 2057 DISALLOW_COPY_AND_ASSIGN(InternalArraySingleArgumentConstructorStub); 2058 }; 2059 2060 2061 class InternalArrayNArgumentsConstructorStub : public 2062 InternalArrayConstructorStubBase { 2063 public: 2064 explicit InternalArrayNArgumentsConstructorStub(ElementsKind kind) 2065 : InternalArrayConstructorStubBase(kind) { } 2066 2067 virtual Handle<Code> GenerateCode(); 2068 2069 virtual void InitializeInterfaceDescriptor( 2070 Isolate* isolate, 2071 CodeStubInterfaceDescriptor* descriptor); 2072 2073 private: 2074 Major MajorKey() { return InternalArrayNArgumentsConstructor; } 2075 2076 DISALLOW_COPY_AND_ASSIGN(InternalArrayNArgumentsConstructorStub); 2077 }; 2078 2079 2080 class KeyedStoreElementStub : public PlatformCodeStub { 2081 public: 2082 KeyedStoreElementStub(bool is_js_array, 2083 ElementsKind elements_kind, 2084 KeyedAccessStoreMode store_mode) 2085 : is_js_array_(is_js_array), 2086 elements_kind_(elements_kind), 2087 store_mode_(store_mode), 2088 fp_registers_(CanUseFPRegisters()) { } 2089 2090 Major MajorKey() { return KeyedStoreElement; } 2091 int MinorKey() { 2092 return ElementsKindBits::encode(elements_kind_) | 2093 IsJSArrayBits::encode(is_js_array_) | 2094 StoreModeBits::encode(store_mode_) | 2095 FPRegisters::encode(fp_registers_); 2096 } 2097 2098 void Generate(MacroAssembler* masm); 2099 2100 private: 2101 class ElementsKindBits: public BitField<ElementsKind, 0, 8> {}; 2102 class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {}; 2103 class IsJSArrayBits: public BitField<bool, 12, 1> {}; 2104 class FPRegisters: public BitField<bool, 13, 1> {}; 2105 2106 bool is_js_array_; 2107 ElementsKind elements_kind_; 2108 KeyedAccessStoreMode store_mode_; 2109 bool fp_registers_; 2110 2111 DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub); 2112 }; 2113 2114 2115 class ToBooleanStub: public HydrogenCodeStub { 2116 public: 2117 enum Type { 2118 UNDEFINED, 2119 BOOLEAN, 2120 NULL_TYPE, 2121 SMI, 2122 SPEC_OBJECT, 2123 STRING, 2124 SYMBOL, 2125 HEAP_NUMBER, 2126 NUMBER_OF_TYPES 2127 }; 2128 2129 // At most 8 different types can be distinguished, because the Code object 2130 // only has room for a single byte to hold a set of these types. :-P 2131 STATIC_ASSERT(NUMBER_OF_TYPES <= 8); 2132 2133 class Types : public EnumSet<Type, byte> { 2134 public: 2135 Types() : EnumSet<Type, byte>(0) {} 2136 explicit Types(byte bits) : EnumSet<Type, byte>(bits) {} 2137 2138 byte ToByte() const { return ToIntegral(); } 2139 void Print(StringStream* stream) const; 2140 bool UpdateStatus(Handle<Object> object); 2141 bool NeedsMap() const; 2142 bool CanBeUndetectable() const; 2143 bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); } 2144 2145 static Types Generic() { return Types((1 << NUMBER_OF_TYPES) - 1); } 2146 }; 2147 2148 explicit ToBooleanStub(Types types = Types()) 2149 : types_(types) { } 2150 explicit ToBooleanStub(Code::ExtraICState state) 2151 : types_(static_cast<byte>(state)) { } 2152 2153 bool UpdateStatus(Handle<Object> object); 2154 Types GetTypes() { return types_; } 2155 2156 virtual Handle<Code> GenerateCode(); 2157 virtual void InitializeInterfaceDescriptor( 2158 Isolate* isolate, 2159 CodeStubInterfaceDescriptor* descriptor); 2160 2161 virtual Code::Kind GetCodeKind() const { return Code::TO_BOOLEAN_IC; } 2162 virtual void PrintState(StringStream* stream); 2163 2164 virtual bool SometimesSetsUpAFrame() { return false; } 2165 2166 static void InitializeForIsolate(Isolate* isolate) { 2167 ToBooleanStub stub; 2168 stub.InitializeInterfaceDescriptor( 2169 isolate, 2170 isolate->code_stub_interface_descriptor(CodeStub::ToBoolean)); 2171 } 2172 2173 static Handle<Code> GetUninitialized(Isolate* isolate) { 2174 return ToBooleanStub(UNINITIALIZED).GetCode(isolate); 2175 } 2176 2177 virtual Code::ExtraICState GetExtraICState() { 2178 return types_.ToIntegral(); 2179 } 2180 2181 virtual InlineCacheState GetICState() { 2182 if (types_.IsEmpty()) { 2183 return ::v8::internal::UNINITIALIZED; 2184 } else { 2185 return MONOMORPHIC; 2186 } 2187 } 2188 2189 private: 2190 Major MajorKey() { return ToBoolean; } 2191 int NotMissMinorKey() { return GetExtraICState(); } 2192 2193 explicit ToBooleanStub(InitializationState init_state) : 2194 HydrogenCodeStub(init_state) {} 2195 2196 Types types_; 2197 }; 2198 2199 2200 class ElementsTransitionAndStoreStub : public HydrogenCodeStub { 2201 public: 2202 ElementsTransitionAndStoreStub(ElementsKind from_kind, 2203 ElementsKind to_kind, 2204 bool is_jsarray, 2205 KeyedAccessStoreMode store_mode) 2206 : from_kind_(from_kind), 2207 to_kind_(to_kind), 2208 is_jsarray_(is_jsarray), 2209 store_mode_(store_mode) {} 2210 2211 ElementsKind from_kind() const { return from_kind_; } 2212 ElementsKind to_kind() const { return to_kind_; } 2213 bool is_jsarray() const { return is_jsarray_; } 2214 KeyedAccessStoreMode store_mode() const { return store_mode_; } 2215 2216 Handle<Code> GenerateCode(); 2217 2218 void InitializeInterfaceDescriptor( 2219 Isolate* isolate, 2220 CodeStubInterfaceDescriptor* descriptor); 2221 2222 private: 2223 class FromBits: public BitField<ElementsKind, 0, 8> {}; 2224 class ToBits: public BitField<ElementsKind, 8, 8> {}; 2225 class IsJSArrayBits: public BitField<bool, 16, 1> {}; 2226 class StoreModeBits: public BitField<KeyedAccessStoreMode, 17, 4> {}; 2227 2228 Major MajorKey() { return ElementsTransitionAndStore; } 2229 int NotMissMinorKey() { 2230 return FromBits::encode(from_kind_) | 2231 ToBits::encode(to_kind_) | 2232 IsJSArrayBits::encode(is_jsarray_) | 2233 StoreModeBits::encode(store_mode_); 2234 } 2235 2236 ElementsKind from_kind_; 2237 ElementsKind to_kind_; 2238 bool is_jsarray_; 2239 KeyedAccessStoreMode store_mode_; 2240 2241 DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub); 2242 }; 2243 2244 2245 class StoreArrayLiteralElementStub : public PlatformCodeStub { 2246 public: 2247 StoreArrayLiteralElementStub() 2248 : fp_registers_(CanUseFPRegisters()) { } 2249 2250 private: 2251 class FPRegisters: public BitField<bool, 0, 1> {}; 2252 2253 Major MajorKey() { return StoreArrayLiteralElement; } 2254 int MinorKey() { return FPRegisters::encode(fp_registers_); } 2255 2256 void Generate(MacroAssembler* masm); 2257 2258 bool fp_registers_; 2259 2260 DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub); 2261 }; 2262 2263 2264 class StubFailureTrampolineStub : public PlatformCodeStub { 2265 public: 2266 explicit StubFailureTrampolineStub(StubFunctionMode function_mode) 2267 : fp_registers_(CanUseFPRegisters()), function_mode_(function_mode) {} 2268 2269 virtual bool IsPregenerated() { return true; } 2270 2271 static void GenerateAheadOfTime(Isolate* isolate); 2272 2273 private: 2274 class FPRegisters: public BitField<bool, 0, 1> {}; 2275 class FunctionModeField: public BitField<StubFunctionMode, 1, 1> {}; 2276 2277 Major MajorKey() { return StubFailureTrampoline; } 2278 int MinorKey() { 2279 return FPRegisters::encode(fp_registers_) | 2280 FunctionModeField::encode(function_mode_); 2281 } 2282 2283 void Generate(MacroAssembler* masm); 2284 2285 bool fp_registers_; 2286 StubFunctionMode function_mode_; 2287 2288 DISALLOW_COPY_AND_ASSIGN(StubFailureTrampolineStub); 2289 }; 2290 2291 2292 class ProfileEntryHookStub : public PlatformCodeStub { 2293 public: 2294 explicit ProfileEntryHookStub() {} 2295 2296 // The profile entry hook function is not allowed to cause a GC. 2297 virtual bool SometimesSetsUpAFrame() { return false; } 2298 2299 // Generates a call to the entry hook if it's enabled. 2300 static void MaybeCallEntryHook(MacroAssembler* masm); 2301 2302 private: 2303 static void EntryHookTrampoline(intptr_t function, 2304 intptr_t stack_pointer); 2305 2306 Major MajorKey() { return ProfileEntryHook; } 2307 int MinorKey() { return 0; } 2308 2309 void Generate(MacroAssembler* masm); 2310 2311 DISALLOW_COPY_AND_ASSIGN(ProfileEntryHookStub); 2312 }; 2313 2314 } } // namespace v8::internal 2315 2316 #endif // V8_CODE_STUBS_H_ 2317